Merge "ahat: annotate char[] objects with their string values."
diff --git a/Android.mk b/Android.mk
index 4f73127..2e05d33 100644
--- a/Android.mk
+++ b/Android.mk
@@ -547,3 +547,5 @@
 art_dont_bother :=
 art_test_bother :=
 TEST_ART_TARGET_SYNC_DEPS :=
+
+include $(art_path)/runtime/openjdkjvm/Android.mk
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index e3f0c24..704d69a 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -239,13 +239,13 @@
   runtime/proxy_test.cc \
   runtime/reflection_test.cc \
   compiler/compiled_method_test.cc \
+  compiler/debug/dwarf/dwarf_test.cc \
   compiler/dex/gvn_dead_code_elimination_test.cc \
   compiler/dex/global_value_numbering_test.cc \
   compiler/dex/local_value_numbering_test.cc \
   compiler/dex/mir_graph_test.cc \
   compiler/dex/mir_optimization_test.cc \
   compiler/dex/type_inference_test.cc \
-  compiler/dwarf/dwarf_test.cc \
   compiler/driver/compiled_method_storage_test.cc \
   compiler/driver/compiler_driver_test.cc \
   compiler/elf_writer_test.cc \
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 87eff82..b164942 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -20,6 +20,7 @@
 
 LIBART_COMPILER_SRC_FILES := \
 	compiled_method.cc \
+	debug/elf_debug_writer.cc \
 	dex/global_value_numbering.cc \
 	dex/gvn_dead_code_elimination.cc \
 	dex/local_value_numbering.cc \
@@ -105,7 +106,6 @@
 	utils/swap_space.cc \
 	compiler.cc \
 	elf_writer.cc \
-	elf_writer_debug.cc \
 	elf_writer_quick.cc \
 	image_writer.cc \
 	oat_writer.cc \
diff --git a/compiler/cfi_test.h b/compiler/cfi_test.h
index 508b04a..230cb9a 100644
--- a/compiler/cfi_test.h
+++ b/compiler/cfi_test.h
@@ -22,9 +22,9 @@
 #include <sstream>
 
 #include "arch/instruction_set.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/dwarf_test.h"
-#include "dwarf/headers.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/dwarf_test.h"
+#include "debug/dwarf/headers.h"
 #include "disassembler/disassembler.h"
 #include "gtest/gtest.h"
 
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 7a93613..5887620 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -283,11 +283,13 @@
     static_assert(sizeof(element_offset_) == sizeof(cmp1_), "needed by relational operators");
   };
   union {
-    uint32_t cmp2_;             // Used for relational operators.
+    // Note: To avoid uninitialized padding on 64-bit systems, we use `size_t` for `cmp2_`.
+    // This allows a hashing function to treat an array of linker patches as raw memory.
+    size_t cmp2_;             // Used for relational operators.
     // Literal offset of the insn loading PC (same as literal_offset if it's the same insn,
     // may be different if the PC-relative addressing needs multiple insns).
     uint32_t pc_insn_offset_;
-    static_assert(sizeof(pc_insn_offset_) == sizeof(cmp2_), "needed by relational operators");
+    static_assert(sizeof(pc_insn_offset_) <= sizeof(cmp2_), "needed by relational operators");
   };
 
   friend bool operator==(const LinkerPatch& lhs, const LinkerPatch& rhs);
diff --git a/compiler/compiler.h b/compiler/compiler.h
index 3a9ce1b..97c60de 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -64,7 +64,8 @@
 
   virtual bool JitCompile(Thread* self ATTRIBUTE_UNUSED,
                           jit::JitCodeCache* code_cache ATTRIBUTE_UNUSED,
-                          ArtMethod* method ATTRIBUTE_UNUSED)
+                          ArtMethod* method ATTRIBUTE_UNUSED,
+                          bool osr ATTRIBUTE_UNUSED)
       SHARED_REQUIRES(Locks::mutator_lock_) {
     return false;
   }
diff --git a/compiler/dwarf/debug_abbrev_writer.h b/compiler/debug/dwarf/debug_abbrev_writer.h
similarity index 92%
rename from compiler/dwarf/debug_abbrev_writer.h
rename to compiler/debug/dwarf/debug_abbrev_writer.h
index 71367e8..0fc843c 100644
--- a/compiler/dwarf/debug_abbrev_writer.h
+++ b/compiler/debug/dwarf/debug_abbrev_writer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_ABBREV_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_ABBREV_WRITER_H_
 
 #include <cstdint>
 #include <type_traits>
@@ -23,8 +23,8 @@
 
 #include "base/casts.h"
 #include "base/stl_util.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/writer.h"
 #include "leb128.h"
 
 namespace art {
@@ -95,4 +95,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_DEBUG_ABBREV_WRITER_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_DEBUG_ABBREV_WRITER_H_
diff --git a/compiler/dwarf/debug_frame_opcode_writer.h b/compiler/debug/dwarf/debug_frame_opcode_writer.h
similarity index 96%
rename from compiler/dwarf/debug_frame_opcode_writer.h
rename to compiler/debug/dwarf/debug_frame_opcode_writer.h
index f74f37c..7c75c9b 100644
--- a/compiler/dwarf/debug_frame_opcode_writer.h
+++ b/compiler/debug/dwarf/debug_frame_opcode_writer.h
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
 
 #include "base/bit_utils.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/register.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/register.h"
+#include "debug/dwarf/writer.h"
 
 namespace art {
 namespace dwarf {
@@ -338,4 +338,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_DEBUG_FRAME_OPCODE_WRITER_H_
diff --git a/compiler/dwarf/debug_info_entry_writer.h b/compiler/debug/dwarf/debug_info_entry_writer.h
similarity index 95%
rename from compiler/dwarf/debug_info_entry_writer.h
rename to compiler/debug/dwarf/debug_info_entry_writer.h
index 1e29859..85f021e 100644
--- a/compiler/dwarf/debug_info_entry_writer.h
+++ b/compiler/debug/dwarf/debug_info_entry_writer.h
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
 
 #include <cstdint>
 #include <unordered_map>
 
 #include "base/casts.h"
-#include "dwarf/debug_abbrev_writer.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/expression.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/debug_abbrev_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/expression.h"
+#include "debug/dwarf/writer.h"
 #include "leb128.h"
 
 namespace art {
@@ -225,4 +225,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_DEBUG_INFO_ENTRY_WRITER_H_
diff --git a/compiler/dwarf/debug_line_opcode_writer.h b/compiler/debug/dwarf/debug_line_opcode_writer.h
similarity index 96%
rename from compiler/dwarf/debug_line_opcode_writer.h
rename to compiler/debug/dwarf/debug_line_opcode_writer.h
index 201f0b4..58502a3 100644
--- a/compiler/dwarf/debug_line_opcode_writer.h
+++ b/compiler/debug/dwarf/debug_line_opcode_writer.h
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
-#define ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
 
 #include <cstdint>
 
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/writer.h"
 
 namespace art {
 namespace dwarf {
@@ -252,4 +252,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_DEBUG_LINE_OPCODE_WRITER_H_
diff --git a/compiler/dwarf/dwarf_constants.h b/compiler/debug/dwarf/dwarf_constants.h
similarity index 98%
rename from compiler/dwarf/dwarf_constants.h
rename to compiler/debug/dwarf/dwarf_constants.h
index 0d7951b..96f805e 100644
--- a/compiler/dwarf/dwarf_constants.h
+++ b/compiler/debug/dwarf/dwarf_constants.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_DWARF_CONSTANTS_H_
-#define ART_COMPILER_DWARF_DWARF_CONSTANTS_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DWARF_CONSTANTS_H_
+#define ART_COMPILER_DEBUG_DWARF_DWARF_CONSTANTS_H_
 
 namespace art {
 namespace dwarf {
@@ -691,4 +691,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_DWARF_CONSTANTS_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_DWARF_CONSTANTS_H_
diff --git a/compiler/dwarf/dwarf_test.cc b/compiler/debug/dwarf/dwarf_test.cc
similarity index 98%
rename from compiler/dwarf/dwarf_test.cc
rename to compiler/debug/dwarf/dwarf_test.cc
index 3237311..e455d0d 100644
--- a/compiler/dwarf/dwarf_test.cc
+++ b/compiler/debug/dwarf/dwarf_test.cc
@@ -16,11 +16,11 @@
 
 #include "dwarf_test.h"
 
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/debug_frame_opcode_writer.h"
-#include "dwarf/debug_info_entry_writer.h"
-#include "dwarf/debug_line_opcode_writer.h"
-#include "dwarf/headers.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/dwarf/debug_line_opcode_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/headers.h"
 #include "gtest/gtest.h"
 
 namespace art {
diff --git a/compiler/dwarf/dwarf_test.h b/compiler/debug/dwarf/dwarf_test.h
similarity index 97%
rename from compiler/dwarf/dwarf_test.h
rename to compiler/debug/dwarf/dwarf_test.h
index c3a3ca9..41bfe79 100644
--- a/compiler/dwarf/dwarf_test.h
+++ b/compiler/debug/dwarf/dwarf_test.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_DWARF_TEST_H_
-#define ART_COMPILER_DWARF_DWARF_TEST_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
+#define ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
 
 #include <cstring>
 #include <dirent.h>
@@ -169,4 +169,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_DWARF_TEST_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_DWARF_TEST_H_
diff --git a/compiler/dwarf/expression.h b/compiler/debug/dwarf/expression.h
similarity index 93%
rename from compiler/dwarf/expression.h
rename to compiler/debug/dwarf/expression.h
index 1503d03..fafc046 100644
--- a/compiler/dwarf/expression.h
+++ b/compiler/debug/dwarf/expression.h
@@ -14,14 +14,14 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_EXPRESSION_H_
-#define ART_COMPILER_DWARF_EXPRESSION_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_EXPRESSION_H_
+#define ART_COMPILER_DEBUG_DWARF_EXPRESSION_H_
 
 #include <cstddef>
 #include <cstdint>
 
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/writer.h"
 
 namespace art {
 namespace dwarf {
@@ -118,4 +118,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_EXPRESSION_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_EXPRESSION_H_
diff --git a/compiler/dwarf/headers.h b/compiler/debug/dwarf/headers.h
similarity index 95%
rename from compiler/dwarf/headers.h
rename to compiler/debug/dwarf/headers.h
index 137c566..146d9fd 100644
--- a/compiler/dwarf/headers.h
+++ b/compiler/debug/dwarf/headers.h
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_HEADERS_H_
-#define ART_COMPILER_DWARF_HEADERS_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_HEADERS_H_
+#define ART_COMPILER_DEBUG_DWARF_HEADERS_H_
 
 #include <cstdint>
 
-#include "dwarf/debug_frame_opcode_writer.h"
-#include "dwarf/debug_info_entry_writer.h"
-#include "dwarf/debug_line_opcode_writer.h"
-#include "dwarf/dwarf_constants.h"
-#include "dwarf/register.h"
-#include "dwarf/writer.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/dwarf/debug_line_opcode_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/register.h"
+#include "debug/dwarf/writer.h"
 #include "utils/array_ref.h"
 
 namespace art {
@@ -204,4 +204,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_HEADERS_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_HEADERS_H_
diff --git a/compiler/dwarf/register.h b/compiler/debug/dwarf/register.h
similarity index 93%
rename from compiler/dwarf/register.h
rename to compiler/debug/dwarf/register.h
index aa3070a..24bacac 100644
--- a/compiler/dwarf/register.h
+++ b/compiler/debug/dwarf/register.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_REGISTER_H_
-#define ART_COMPILER_DWARF_REGISTER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_REGISTER_H_
+#define ART_COMPILER_DEBUG_DWARF_REGISTER_H_
 
 namespace art {
 namespace dwarf {
@@ -59,4 +59,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_REGISTER_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_REGISTER_H_
diff --git a/compiler/dwarf/writer.h b/compiler/debug/dwarf/writer.h
similarity index 97%
rename from compiler/dwarf/writer.h
rename to compiler/debug/dwarf/writer.h
index 74acf07..95912ad 100644
--- a/compiler/dwarf/writer.h
+++ b/compiler/debug/dwarf/writer.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DWARF_WRITER_H_
-#define ART_COMPILER_DWARF_WRITER_H_
+#ifndef ART_COMPILER_DEBUG_DWARF_WRITER_H_
+#define ART_COMPILER_DEBUG_DWARF_WRITER_H_
 
 #include <type_traits>
 #include <vector>
@@ -179,4 +179,4 @@
 }  // namespace dwarf
 }  // namespace art
 
-#endif  // ART_COMPILER_DWARF_WRITER_H_
+#endif  // ART_COMPILER_DEBUG_DWARF_WRITER_H_
diff --git a/compiler/debug/elf_compilation_unit.h b/compiler/debug/elf_compilation_unit.h
new file mode 100644
index 0000000..f725f45
--- /dev/null
+++ b/compiler/debug/elf_compilation_unit.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_
+#define ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_
+
+#include <vector>
+
+#include "debug/method_debug_info.h"
+
+namespace art {
+namespace debug {
+
+struct ElfCompilationUnit {
+  std::vector<const MethodDebugInfo*> methods;
+  size_t debug_line_offset = 0;
+  uintptr_t low_pc = std::numeric_limits<uintptr_t>::max();
+  uintptr_t high_pc = 0;
+};
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_COMPILATION_UNIT_H_
+
diff --git a/compiler/debug/elf_debug_frame_writer.h b/compiler/debug/elf_debug_frame_writer.h
new file mode 100644
index 0000000..f6d9b16
--- /dev/null
+++ b/compiler/debug/elf_debug_frame_writer.h
@@ -0,0 +1,290 @@
+/*
+ * Copyright (C) 2016 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_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_
+
+#include <vector>
+
+#include "arch/instruction_set.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/dwarf/headers.h"
+#include "debug/method_debug_info.h"
+#include "elf_builder.h"
+
+namespace art {
+namespace debug {
+
+static void WriteCIE(InstructionSet isa,
+                     dwarf::CFIFormat format,
+                     std::vector<uint8_t>* buffer) {
+  using Reg = dwarf::Reg;
+  // Scratch registers should be marked as undefined.  This tells the
+  // debugger that its value in the previous frame is not recoverable.
+  bool is64bit = Is64BitInstructionSet(isa);
+  switch (isa) {
+    case kArm:
+    case kThumb2: {
+      dwarf::DebugFrameOpCodeWriter<> opcodes;
+      opcodes.DefCFA(Reg::ArmCore(13), 0);  // R13(SP).
+      // core registers.
+      for (int reg = 0; reg < 13; reg++) {
+        if (reg < 4 || reg == 12) {
+          opcodes.Undefined(Reg::ArmCore(reg));
+        } else {
+          opcodes.SameValue(Reg::ArmCore(reg));
+        }
+      }
+      // fp registers.
+      for (int reg = 0; reg < 32; reg++) {
+        if (reg < 16) {
+          opcodes.Undefined(Reg::ArmFp(reg));
+        } else {
+          opcodes.SameValue(Reg::ArmFp(reg));
+        }
+      }
+      auto return_reg = Reg::ArmCore(14);  // R14(LR).
+      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+      return;
+    }
+    case kArm64: {
+      dwarf::DebugFrameOpCodeWriter<> opcodes;
+      opcodes.DefCFA(Reg::Arm64Core(31), 0);  // R31(SP).
+      // core registers.
+      for (int reg = 0; reg < 30; reg++) {
+        if (reg < 8 || reg == 16 || reg == 17) {
+          opcodes.Undefined(Reg::Arm64Core(reg));
+        } else {
+          opcodes.SameValue(Reg::Arm64Core(reg));
+        }
+      }
+      // fp registers.
+      for (int reg = 0; reg < 32; reg++) {
+        if (reg < 8 || reg >= 16) {
+          opcodes.Undefined(Reg::Arm64Fp(reg));
+        } else {
+          opcodes.SameValue(Reg::Arm64Fp(reg));
+        }
+      }
+      auto return_reg = Reg::Arm64Core(30);  // R30(LR).
+      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+      return;
+    }
+    case kMips:
+    case kMips64: {
+      dwarf::DebugFrameOpCodeWriter<> opcodes;
+      opcodes.DefCFA(Reg::MipsCore(29), 0);  // R29(SP).
+      // core registers.
+      for (int reg = 1; reg < 26; reg++) {
+        if (reg < 16 || reg == 24 || reg == 25) {  // AT, V*, A*, T*.
+          opcodes.Undefined(Reg::MipsCore(reg));
+        } else {
+          opcodes.SameValue(Reg::MipsCore(reg));
+        }
+      }
+      // fp registers.
+      for (int reg = 0; reg < 32; reg++) {
+        if (reg < 24) {
+          opcodes.Undefined(Reg::Mips64Fp(reg));
+        } else {
+          opcodes.SameValue(Reg::Mips64Fp(reg));
+        }
+      }
+      auto return_reg = Reg::MipsCore(31);  // R31(RA).
+      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+      return;
+    }
+    case kX86: {
+      // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296
+      constexpr bool generate_opcodes_for_x86_fp = false;
+      dwarf::DebugFrameOpCodeWriter<> opcodes;
+      opcodes.DefCFA(Reg::X86Core(4), 4);   // R4(ESP).
+      opcodes.Offset(Reg::X86Core(8), -4);  // R8(EIP).
+      // core registers.
+      for (int reg = 0; reg < 8; reg++) {
+        if (reg <= 3) {
+          opcodes.Undefined(Reg::X86Core(reg));
+        } else if (reg == 4) {
+          // Stack pointer.
+        } else {
+          opcodes.SameValue(Reg::X86Core(reg));
+        }
+      }
+      // fp registers.
+      if (generate_opcodes_for_x86_fp) {
+        for (int reg = 0; reg < 8; reg++) {
+          opcodes.Undefined(Reg::X86Fp(reg));
+        }
+      }
+      auto return_reg = Reg::X86Core(8);  // R8(EIP).
+      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+      return;
+    }
+    case kX86_64: {
+      dwarf::DebugFrameOpCodeWriter<> opcodes;
+      opcodes.DefCFA(Reg::X86_64Core(4), 8);  // R4(RSP).
+      opcodes.Offset(Reg::X86_64Core(16), -8);  // R16(RIP).
+      // core registers.
+      for (int reg = 0; reg < 16; reg++) {
+        if (reg == 4) {
+          // Stack pointer.
+        } else if (reg < 12 && reg != 3 && reg != 5) {  // except EBX and EBP.
+          opcodes.Undefined(Reg::X86_64Core(reg));
+        } else {
+          opcodes.SameValue(Reg::X86_64Core(reg));
+        }
+      }
+      // fp registers.
+      for (int reg = 0; reg < 16; reg++) {
+        if (reg < 12) {
+          opcodes.Undefined(Reg::X86_64Fp(reg));
+        } else {
+          opcodes.SameValue(Reg::X86_64Fp(reg));
+        }
+      }
+      auto return_reg = Reg::X86_64Core(16);  // R16(RIP).
+      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
+      return;
+    }
+    case kNone:
+      break;
+  }
+  LOG(FATAL) << "Cannot write CIE frame for ISA " << isa;
+  UNREACHABLE();
+}
+
+template<typename ElfTypes>
+void WriteCFISection(ElfBuilder<ElfTypes>* builder,
+                     const ArrayRef<const MethodDebugInfo>& method_infos,
+                     dwarf::CFIFormat format,
+                     bool write_oat_patches) {
+  CHECK(format == dwarf::DW_DEBUG_FRAME_FORMAT || format == dwarf::DW_EH_FRAME_FORMAT);
+  typedef typename ElfTypes::Addr Elf_Addr;
+
+  if (method_infos.empty()) {
+    return;
+  }
+
+  std::vector<uint32_t> binary_search_table;
+  std::vector<uintptr_t> patch_locations;
+  if (format == dwarf::DW_EH_FRAME_FORMAT) {
+    binary_search_table.reserve(2 * method_infos.size());
+  } else {
+    patch_locations.reserve(method_infos.size());
+  }
+
+  // The methods can be written in any order.
+  // Let's therefore sort them in the lexicographical order of the opcodes.
+  // This has no effect on its own. However, if the final .debug_frame section is
+  // compressed it reduces the size since similar opcodes sequences are grouped.
+  std::vector<const MethodDebugInfo*> sorted_method_infos;
+  sorted_method_infos.reserve(method_infos.size());
+  for (size_t i = 0; i < method_infos.size(); i++) {
+    sorted_method_infos.push_back(&method_infos[i]);
+  }
+  std::sort(
+      sorted_method_infos.begin(),
+      sorted_method_infos.end(),
+      [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) {
+        ArrayRef<const uint8_t> l = lhs->compiled_method->GetCFIInfo();
+        ArrayRef<const uint8_t> r = rhs->compiled_method->GetCFIInfo();
+        return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
+      });
+
+  // Write .eh_frame/.debug_frame section.
+  auto* cfi_section = (format == dwarf::DW_DEBUG_FRAME_FORMAT
+                       ? builder->GetDebugFrame()
+                       : builder->GetEhFrame());
+  {
+    cfi_section->Start();
+    const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
+    const Elf_Addr text_address = builder->GetText()->Exists()
+        ? builder->GetText()->GetAddress()
+        : 0;
+    const Elf_Addr cfi_address = cfi_section->GetAddress();
+    const Elf_Addr cie_address = cfi_address;
+    Elf_Addr buffer_address = cfi_address;
+    std::vector<uint8_t> buffer;  // Small temporary buffer.
+    WriteCIE(builder->GetIsa(), format, &buffer);
+    cfi_section->WriteFully(buffer.data(), buffer.size());
+    buffer_address += buffer.size();
+    buffer.clear();
+    for (const MethodDebugInfo* mi : sorted_method_infos) {
+      if (!mi->deduped) {  // Only one FDE per unique address.
+        ArrayRef<const uint8_t> opcodes = mi->compiled_method->GetCFIInfo();
+        if (!opcodes.empty()) {
+          const Elf_Addr code_address = text_address + mi->low_pc;
+          if (format == dwarf::DW_EH_FRAME_FORMAT) {
+            binary_search_table.push_back(
+                dchecked_integral_cast<uint32_t>(code_address));
+            binary_search_table.push_back(
+                dchecked_integral_cast<uint32_t>(buffer_address));
+          }
+          WriteFDE(is64bit, cfi_address, cie_address,
+                   code_address, mi->high_pc - mi->low_pc,
+                   opcodes, format, buffer_address, &buffer,
+                   &patch_locations);
+          cfi_section->WriteFully(buffer.data(), buffer.size());
+          buffer_address += buffer.size();
+          buffer.clear();
+        }
+      }
+    }
+    cfi_section->End();
+  }
+
+  if (format == dwarf::DW_EH_FRAME_FORMAT) {
+    auto* header_section = builder->GetEhFrameHdr();
+    header_section->Start();
+    uint32_t header_address = dchecked_integral_cast<int32_t>(header_section->GetAddress());
+    // Write .eh_frame_hdr section.
+    std::vector<uint8_t> buffer;
+    dwarf::Writer<> header(&buffer);
+    header.PushUint8(1);  // Version.
+    // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
+    // so we have to use pcrel which means relative to the pointer's location.
+    header.PushUint8(dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4);
+    // Encoding of binary search table size.
+    header.PushUint8(dwarf::DW_EH_PE_udata4);
+    // Encoding of binary search table addresses - libunwind supports only this
+    // specific combination, which means relative to the start of .eh_frame_hdr.
+    header.PushUint8(dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4);
+    // .eh_frame pointer
+    header.PushInt32(cfi_section->GetAddress() - (header_address + 4u));
+    // Binary search table size (number of entries).
+    header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2));
+    header_section->WriteFully(buffer.data(), buffer.size());
+    // Binary search table.
+    for (size_t i = 0; i < binary_search_table.size(); i++) {
+      // Make addresses section-relative since we know the header address now.
+      binary_search_table[i] -= header_address;
+    }
+    header_section->WriteFully(binary_search_table.data(), binary_search_table.size());
+    header_section->End();
+  } else {
+    if (write_oat_patches) {
+      builder->WritePatches(".debug_frame.oat_patches",
+                            ArrayRef<const uintptr_t>(patch_locations));
+    }
+  }
+}
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_FRAME_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_info_writer.h b/compiler/debug/elf_debug_info_writer.h
new file mode 100644
index 0000000..eed032f
--- /dev/null
+++ b/compiler/debug/elf_debug_info_writer.h
@@ -0,0 +1,649 @@
+/*
+ * Copyright (C) 2016 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_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_
+
+#include <map>
+#include <unordered_set>
+#include <vector>
+
+#include "debug/dwarf/debug_abbrev_writer.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/elf_compilation_unit.h"
+#include "debug/elf_debug_loc_writer.h"
+#include "debug/method_debug_info.h"
+#include "dex_file-inl.h"
+#include "dex_file.h"
+#include "elf_builder.h"
+#include "linear_alloc.h"
+#include "mirror/array.h"
+#include "mirror/class-inl.h"
+#include "mirror/class.h"
+
+namespace art {
+namespace debug {
+
+typedef std::vector<DexFile::LocalInfo> LocalInfos;
+
+static void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
+  static_cast<LocalInfos*>(ctx)->push_back(entry);
+}
+
+static std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
+  std::vector<const char*> names;
+  if (mi->code_item != nullptr) {
+    const uint8_t* stream = mi->dex_file->GetDebugInfoStream(mi->code_item);
+    if (stream != nullptr) {
+      DecodeUnsignedLeb128(&stream);  // line.
+      uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
+      for (uint32_t i = 0; i < parameters_size; ++i) {
+        uint32_t id = DecodeUnsignedLeb128P1(&stream);
+        names.push_back(mi->dex_file->StringDataByIdx(id));
+      }
+    }
+  }
+  return names;
+}
+
+// Helper class to write .debug_info and its supporting sections.
+template<typename ElfTypes>
+class ElfDebugInfoWriter {
+  using Elf_Addr = typename ElfTypes::Addr;
+
+ public:
+  explicit ElfDebugInfoWriter(ElfBuilder<ElfTypes>* builder)
+      : builder_(builder),
+        debug_abbrev_(&debug_abbrev_buffer_) {
+  }
+
+  void Start() {
+    builder_->GetDebugInfo()->Start();
+  }
+
+  void End(bool write_oat_patches) {
+    builder_->GetDebugInfo()->End();
+    if (write_oat_patches) {
+      builder_->WritePatches(".debug_info.oat_patches",
+                             ArrayRef<const uintptr_t>(debug_info_patches_));
+    }
+    builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_);
+    if (!debug_loc_.empty()) {
+      builder_->WriteSection(".debug_loc", &debug_loc_);
+    }
+    if (!debug_ranges_.empty()) {
+      builder_->WriteSection(".debug_ranges", &debug_ranges_);
+    }
+  }
+
+ private:
+  ElfBuilder<ElfTypes>* builder_;
+  std::vector<uintptr_t> debug_info_patches_;
+  std::vector<uint8_t> debug_abbrev_buffer_;
+  dwarf::DebugAbbrevWriter<> debug_abbrev_;
+  std::vector<uint8_t> debug_loc_;
+  std::vector<uint8_t> debug_ranges_;
+
+  std::unordered_set<const char*> defined_dex_classes_;  // For CHECKs only.
+
+  template<typename ElfTypes2>
+  friend class ElfCompilationUnitWriter;
+};
+
+// Helper class to write one compilation unit.
+// It holds helper methods and temporary state.
+template<typename ElfTypes>
+class ElfCompilationUnitWriter {
+  using Elf_Addr = typename ElfTypes::Addr;
+
+ public:
+  explicit ElfCompilationUnitWriter(ElfDebugInfoWriter<ElfTypes>* owner)
+    : owner_(owner),
+      info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &owner->debug_abbrev_) {
+  }
+
+  void Write(const ElfCompilationUnit& compilation_unit) {
+    CHECK(!compilation_unit.methods.empty());
+    const Elf_Addr text_address = owner_->builder_->GetText()->Exists()
+        ? owner_->builder_->GetText()->GetAddress()
+        : 0;
+    const uintptr_t cu_size = compilation_unit.high_pc - compilation_unit.low_pc;
+    using namespace dwarf;  // NOLINT. For easy access to DWARF constants.
+
+    info_.StartTag(DW_TAG_compile_unit);
+    info_.WriteString(DW_AT_producer, "Android dex2oat");
+    info_.WriteData1(DW_AT_language, DW_LANG_Java);
+    info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT");
+    info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc);
+    info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
+    info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset);
+
+    const char* last_dex_class_desc = nullptr;
+    for (auto mi : compilation_unit.methods) {
+      const DexFile* dex = mi->dex_file;
+      const DexFile::CodeItem* dex_code = mi->code_item;
+      const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index);
+      const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
+      const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
+      const char* dex_class_desc = dex->GetMethodDeclaringClassDescriptor(dex_method);
+      const bool is_static = (mi->access_flags & kAccStatic) != 0;
+
+      // Enclose the method in correct class definition.
+      if (last_dex_class_desc != dex_class_desc) {
+        if (last_dex_class_desc != nullptr) {
+          EndClassTag();
+        }
+        // Write reference tag for the class we are about to declare.
+        size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type);
+        type_cache_.emplace(std::string(dex_class_desc), reference_tag_offset);
+        size_t type_attrib_offset = info_.size();
+        info_.WriteRef4(DW_AT_type, 0);
+        info_.EndTag();
+        // Declare the class that owns this method.
+        size_t class_offset = StartClassTag(dex_class_desc);
+        info_.UpdateUint32(type_attrib_offset, class_offset);
+        info_.WriteFlagPresent(DW_AT_declaration);
+        // Check that each class is defined only once.
+        bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second;
+        CHECK(unique) << "Redefinition of " << dex_class_desc;
+        last_dex_class_desc = dex_class_desc;
+      }
+
+      int start_depth = info_.Depth();
+      info_.StartTag(DW_TAG_subprogram);
+      WriteName(dex->GetMethodName(dex_method));
+      info_.WriteAddr(DW_AT_low_pc, text_address + mi->low_pc);
+      info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(mi->high_pc-mi->low_pc));
+      std::vector<uint8_t> expr_buffer;
+      Expression expr(&expr_buffer);
+      expr.WriteOpCallFrameCfa();
+      info_.WriteExprLoc(DW_AT_frame_base, expr);
+      WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto));
+
+      // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not
+      // guarantee order or uniqueness so it is safer to iterate over them manually.
+      // DecodeDebugLocalInfo might not also be available if there is no debug info.
+      std::vector<const char*> param_names = GetParamNames(mi);
+      uint32_t arg_reg = 0;
+      if (!is_static) {
+        info_.StartTag(DW_TAG_formal_parameter);
+        WriteName("this");
+        info_.WriteFlagPresent(DW_AT_artificial);
+        WriteLazyType(dex_class_desc);
+        if (dex_code != nullptr) {
+          // Write the stack location of the parameter.
+          const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+          const bool is64bitValue = false;
+          WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc);
+        }
+        arg_reg++;
+        info_.EndTag();
+      }
+      if (dex_params != nullptr) {
+        for (uint32_t i = 0; i < dex_params->Size(); ++i) {
+          info_.StartTag(DW_TAG_formal_parameter);
+          // Parameter names may not be always available.
+          if (i < param_names.size()) {
+            WriteName(param_names[i]);
+          }
+          // Write the type.
+          const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
+          WriteLazyType(type_desc);
+          const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
+          if (dex_code != nullptr) {
+            // Write the stack location of the parameter.
+            const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
+            WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc);
+          }
+          arg_reg += is64bitValue ? 2 : 1;
+          info_.EndTag();
+        }
+        if (dex_code != nullptr) {
+          DCHECK_EQ(arg_reg, dex_code->ins_size_);
+        }
+      }
+
+      // Write local variables.
+      LocalInfos local_infos;
+      if (dex->DecodeDebugLocalInfo(dex_code,
+                                    is_static,
+                                    mi->dex_method_index,
+                                    LocalInfoCallback,
+                                    &local_infos)) {
+        for (const DexFile::LocalInfo& var : local_infos) {
+          if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
+            info_.StartTag(DW_TAG_variable);
+            WriteName(var.name_);
+            WriteLazyType(var.descriptor_);
+            bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J';
+            WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc,
+                             var.start_address_, var.end_address_);
+            info_.EndTag();
+          }
+        }
+      }
+
+      info_.EndTag();
+      CHECK_EQ(info_.Depth(), start_depth);  // Balanced start/end.
+    }
+    if (last_dex_class_desc != nullptr) {
+      EndClassTag();
+    }
+    FinishLazyTypes();
+    CloseNamespacesAboveDepth(0);
+    info_.EndTag();  // DW_TAG_compile_unit
+    CHECK_EQ(info_.Depth(), 0);
+    std::vector<uint8_t> buffer;
+    buffer.reserve(info_.data()->size() + KB);
+    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+    // All compilation units share single table which is at the start of .debug_abbrev.
+    const size_t debug_abbrev_offset = 0;
+    WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
+    owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
+  }
+
+  void Write(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) {
+    using namespace dwarf;  // NOLINT. For easy access to DWARF constants.
+
+    info_.StartTag(DW_TAG_compile_unit);
+    info_.WriteString(DW_AT_producer, "Android dex2oat");
+    info_.WriteData1(DW_AT_language, DW_LANG_Java);
+
+    // Base class references to be patched at the end.
+    std::map<size_t, mirror::Class*> base_class_references;
+
+    // Already written declarations or definitions.
+    std::map<mirror::Class*, size_t> class_declarations;
+
+    std::vector<uint8_t> expr_buffer;
+    for (mirror::Class* type : types) {
+      if (type->IsPrimitive()) {
+        // For primitive types the definition and the declaration is the same.
+        if (type->GetPrimitiveType() != Primitive::kPrimVoid) {
+          WriteTypeDeclaration(type->GetDescriptor(nullptr));
+        }
+      } else if (type->IsArrayClass()) {
+        mirror::Class* element_type = type->GetComponentType();
+        uint32_t component_size = type->GetComponentSize();
+        uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value();
+        uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
+
+        CloseNamespacesAboveDepth(0);  // Declare in root namespace.
+        info_.StartTag(DW_TAG_array_type);
+        std::string descriptor_string;
+        WriteLazyType(element_type->GetDescriptor(&descriptor_string));
+        WriteLinkageName(type);
+        info_.WriteUdata(DW_AT_data_member_location, data_offset);
+        info_.StartTag(DW_TAG_subrange_type);
+        Expression count_expr(&expr_buffer);
+        count_expr.WriteOpPushObjectAddress();
+        count_expr.WriteOpPlusUconst(length_offset);
+        count_expr.WriteOpDerefSize(4);  // Array length is always 32-bit wide.
+        info_.WriteExprLoc(DW_AT_count, count_expr);
+        info_.EndTag();  // DW_TAG_subrange_type.
+        info_.EndTag();  // DW_TAG_array_type.
+      } else if (type->IsInterface()) {
+        // Skip.  Variables cannot have an interface as a dynamic type.
+        // We do not expose the interface information to the debugger in any way.
+      } else {
+        std::string descriptor_string;
+        const char* desc = type->GetDescriptor(&descriptor_string);
+        size_t class_offset = StartClassTag(desc);
+        class_declarations.emplace(type, class_offset);
+
+        if (!type->IsVariableSize()) {
+          info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize());
+        }
+
+        WriteLinkageName(type);
+
+        if (type->IsObjectClass()) {
+          // Generate artificial member which is used to get the dynamic type of variable.
+          // The run-time value of this field will correspond to linkage name of some type.
+          // We need to do it only once in j.l.Object since all other types inherit it.
+          info_.StartTag(DW_TAG_member);
+          WriteName(".dynamic_type");
+          WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I");
+          info_.WriteFlagPresent(DW_AT_artificial);
+          // Create DWARF expression to get the value of the methods_ field.
+          Expression expr(&expr_buffer);
+          // The address of the object has been implicitly pushed on the stack.
+          // Dereference the klass_ field of Object (32-bit; possibly poisoned).
+          DCHECK_EQ(type->ClassOffset().Uint32Value(), 0u);
+          DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Class>), 4u);
+          expr.WriteOpDerefSize(4);
+          if (kPoisonHeapReferences) {
+            expr.WriteOpNeg();
+            // DWARF stack is pointer sized. Ensure that the high bits are clear.
+            expr.WriteOpConstu(0xFFFFFFFF);
+            expr.WriteOpAnd();
+          }
+          // Add offset to the methods_ field.
+          expr.WriteOpPlusUconst(mirror::Class::MethodsOffset().Uint32Value());
+          // Top of stack holds the location of the field now.
+          info_.WriteExprLoc(DW_AT_data_member_location, expr);
+          info_.EndTag();  // DW_TAG_member.
+        }
+
+        // Base class.
+        mirror::Class* base_class = type->GetSuperClass();
+        if (base_class != nullptr) {
+          info_.StartTag(DW_TAG_inheritance);
+          base_class_references.emplace(info_.size(), base_class);
+          info_.WriteRef4(DW_AT_type, 0);
+          info_.WriteUdata(DW_AT_data_member_location, 0);
+          info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
+          info_.EndTag();  // DW_TAG_inheritance.
+        }
+
+        // Member variables.
+        for (uint32_t i = 0, count = type->NumInstanceFields(); i < count; ++i) {
+          ArtField* field = type->GetInstanceField(i);
+          info_.StartTag(DW_TAG_member);
+          WriteName(field->GetName());
+          WriteLazyType(field->GetTypeDescriptor());
+          info_.WriteUdata(DW_AT_data_member_location, field->GetOffset().Uint32Value());
+          uint32_t access_flags = field->GetAccessFlags();
+          if (access_flags & kAccPublic) {
+            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
+          } else if (access_flags & kAccProtected) {
+            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_protected);
+          } else if (access_flags & kAccPrivate) {
+            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
+          }
+          info_.EndTag();  // DW_TAG_member.
+        }
+
+        if (type->IsStringClass()) {
+          // Emit debug info about an artifical class member for java.lang.String which represents
+          // the first element of the data stored in a string instance. Consumers of the debug
+          // info will be able to read the content of java.lang.String based on the count (real
+          // field) and based on the location of this data member.
+          info_.StartTag(DW_TAG_member);
+          WriteName("value");
+          // We don't support fields with C like array types so we just say its type is java char.
+          WriteLazyType("C");  // char.
+          info_.WriteUdata(DW_AT_data_member_location,
+                           mirror::String::ValueOffset().Uint32Value());
+          info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
+          info_.EndTag();  // DW_TAG_member.
+        }
+
+        EndClassTag();
+      }
+    }
+
+    // Write base class declarations.
+    for (const auto& base_class_reference : base_class_references) {
+      size_t reference_offset = base_class_reference.first;
+      mirror::Class* base_class = base_class_reference.second;
+      const auto& it = class_declarations.find(base_class);
+      if (it != class_declarations.end()) {
+        info_.UpdateUint32(reference_offset, it->second);
+      } else {
+        // Declare base class.  We can not use the standard WriteLazyType
+        // since we want to avoid the DW_TAG_reference_tag wrapping.
+        std::string tmp_storage;
+        const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
+        size_t base_class_declaration_offset = StartClassTag(base_class_desc);
+        info_.WriteFlagPresent(DW_AT_declaration);
+        WriteLinkageName(base_class);
+        EndClassTag();
+        class_declarations.emplace(base_class, base_class_declaration_offset);
+        info_.UpdateUint32(reference_offset, base_class_declaration_offset);
+      }
+    }
+
+    FinishLazyTypes();
+    CloseNamespacesAboveDepth(0);
+    info_.EndTag();  // DW_TAG_compile_unit.
+    CHECK_EQ(info_.Depth(), 0);
+    std::vector<uint8_t> buffer;
+    buffer.reserve(info_.data()->size() + KB);
+    const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
+    // All compilation units share single table which is at the start of .debug_abbrev.
+    const size_t debug_abbrev_offset = 0;
+    WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
+    owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
+  }
+
+  // Write table into .debug_loc which describes location of dex register.
+  // The dex register might be valid only at some points and it might
+  // move between machine registers and stack.
+  void WriteRegLocation(const MethodDebugInfo* method_info,
+                        uint16_t vreg,
+                        bool is64bitValue,
+                        uint32_t compilation_unit_low_pc,
+                        uint32_t dex_pc_low = 0,
+                        uint32_t dex_pc_high = 0xFFFFFFFF) {
+    WriteDebugLocEntry(method_info,
+                       vreg,
+                       is64bitValue,
+                       compilation_unit_low_pc,
+                       dex_pc_low,
+                       dex_pc_high,
+                       owner_->builder_->GetIsa(),
+                       &info_,
+                       &owner_->debug_loc_,
+                       &owner_->debug_ranges_);
+  }
+
+  // Linkage name uniquely identifies type.
+  // It is used to determine the dynamic type of objects.
+  // We use the methods_ field of class since it is unique and it is not moved by the GC.
+  void WriteLinkageName(mirror::Class* type) SHARED_REQUIRES(Locks::mutator_lock_) {
+    auto* methods_ptr = type->GetMethodsPtr();
+    if (methods_ptr == nullptr) {
+      // Some types might have no methods.  Allocate empty array instead.
+      LinearAlloc* allocator = Runtime::Current()->GetLinearAlloc();
+      void* storage = allocator->Alloc(Thread::Current(), sizeof(LengthPrefixedArray<ArtMethod>));
+      methods_ptr = new (storage) LengthPrefixedArray<ArtMethod>(0);
+      type->SetMethodsPtr(methods_ptr, 0, 0);
+      DCHECK(type->GetMethodsPtr() != nullptr);
+    }
+    char name[32];
+    snprintf(name, sizeof(name), "0x%" PRIXPTR, reinterpret_cast<uintptr_t>(methods_ptr));
+    info_.WriteString(dwarf::DW_AT_linkage_name, name);
+  }
+
+  // Some types are difficult to define as we go since they need
+  // to be enclosed in the right set of namespaces. Therefore we
+  // just define all types lazily at the end of compilation unit.
+  void WriteLazyType(const char* type_descriptor) {
+    if (type_descriptor != nullptr && type_descriptor[0] != 'V') {
+      lazy_types_.emplace(std::string(type_descriptor), info_.size());
+      info_.WriteRef4(dwarf::DW_AT_type, 0);
+    }
+  }
+
+  void FinishLazyTypes() {
+    for (const auto& lazy_type : lazy_types_) {
+      info_.UpdateUint32(lazy_type.second, WriteTypeDeclaration(lazy_type.first));
+    }
+    lazy_types_.clear();
+  }
+
+ private:
+  void WriteName(const char* name) {
+    if (name != nullptr) {
+      info_.WriteString(dwarf::DW_AT_name, name);
+    }
+  }
+
+  // Convert dex type descriptor to DWARF.
+  // Returns offset in the compilation unit.
+  size_t WriteTypeDeclaration(const std::string& desc) {
+    using namespace dwarf;  // NOLINT. For easy access to DWARF constants.
+
+    DCHECK(!desc.empty());
+    const auto& it = type_cache_.find(desc);
+    if (it != type_cache_.end()) {
+      return it->second;
+    }
+
+    size_t offset;
+    if (desc[0] == 'L') {
+      // Class type. For example: Lpackage/name;
+      size_t class_offset = StartClassTag(desc.c_str());
+      info_.WriteFlagPresent(DW_AT_declaration);
+      EndClassTag();
+      // Reference to the class type.
+      offset = info_.StartTag(DW_TAG_reference_type);
+      info_.WriteRef(DW_AT_type, class_offset);
+      info_.EndTag();
+    } else if (desc[0] == '[') {
+      // Array type.
+      size_t element_type = WriteTypeDeclaration(desc.substr(1));
+      CloseNamespacesAboveDepth(0);  // Declare in root namespace.
+      size_t array_type = info_.StartTag(DW_TAG_array_type);
+      info_.WriteFlagPresent(DW_AT_declaration);
+      info_.WriteRef(DW_AT_type, element_type);
+      info_.EndTag();
+      offset = info_.StartTag(DW_TAG_reference_type);
+      info_.WriteRef4(DW_AT_type, array_type);
+      info_.EndTag();
+    } else {
+      // Primitive types.
+      DCHECK_EQ(desc.size(), 1u);
+
+      const char* name;
+      uint32_t encoding;
+      uint32_t byte_size;
+      switch (desc[0]) {
+      case 'B':
+        name = "byte";
+        encoding = DW_ATE_signed;
+        byte_size = 1;
+        break;
+      case 'C':
+        name = "char";
+        encoding = DW_ATE_UTF;
+        byte_size = 2;
+        break;
+      case 'D':
+        name = "double";
+        encoding = DW_ATE_float;
+        byte_size = 8;
+        break;
+      case 'F':
+        name = "float";
+        encoding = DW_ATE_float;
+        byte_size = 4;
+        break;
+      case 'I':
+        name = "int";
+        encoding = DW_ATE_signed;
+        byte_size = 4;
+        break;
+      case 'J':
+        name = "long";
+        encoding = DW_ATE_signed;
+        byte_size = 8;
+        break;
+      case 'S':
+        name = "short";
+        encoding = DW_ATE_signed;
+        byte_size = 2;
+        break;
+      case 'Z':
+        name = "boolean";
+        encoding = DW_ATE_boolean;
+        byte_size = 1;
+        break;
+      case 'V':
+        LOG(FATAL) << "Void type should not be encoded";
+        UNREACHABLE();
+      default:
+        LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\"";
+        UNREACHABLE();
+      }
+      CloseNamespacesAboveDepth(0);  // Declare in root namespace.
+      offset = info_.StartTag(DW_TAG_base_type);
+      WriteName(name);
+      info_.WriteData1(DW_AT_encoding, encoding);
+      info_.WriteData1(DW_AT_byte_size, byte_size);
+      info_.EndTag();
+    }
+
+    type_cache_.emplace(desc, offset);
+    return offset;
+  }
+
+  // Start DW_TAG_class_type tag nested in DW_TAG_namespace tags.
+  // Returns offset of the class tag in the compilation unit.
+  size_t StartClassTag(const char* desc) {
+    std::string name = SetNamespaceForClass(desc);
+    size_t offset = info_.StartTag(dwarf::DW_TAG_class_type);
+    WriteName(name.c_str());
+    return offset;
+  }
+
+  void EndClassTag() {
+    info_.EndTag();
+  }
+
+  // Set the current namespace nesting to one required by the given class.
+  // Returns the class name with namespaces, 'L', and ';' stripped.
+  std::string SetNamespaceForClass(const char* desc) {
+    DCHECK(desc != nullptr && desc[0] == 'L');
+    desc++;  // Skip the initial 'L'.
+    size_t depth = 0;
+    for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) {
+      // Check whether the name at this depth is already what we need.
+      if (depth < current_namespace_.size()) {
+        const std::string& name = current_namespace_[depth];
+        if (name.compare(0, name.size(), desc, end - desc) == 0) {
+          continue;
+        }
+      }
+      // Otherwise we need to open a new namespace tag at this depth.
+      CloseNamespacesAboveDepth(depth);
+      info_.StartTag(dwarf::DW_TAG_namespace);
+      std::string name(desc, end - desc);
+      WriteName(name.c_str());
+      current_namespace_.push_back(std::move(name));
+    }
+    CloseNamespacesAboveDepth(depth);
+    return std::string(desc, strchr(desc, ';') - desc);
+  }
+
+  // Close namespace tags to reach the given nesting depth.
+  void CloseNamespacesAboveDepth(size_t depth) {
+    DCHECK_LE(depth, current_namespace_.size());
+    while (current_namespace_.size() > depth) {
+      info_.EndTag();
+      current_namespace_.pop_back();
+    }
+  }
+
+  // For access to the ELF sections.
+  ElfDebugInfoWriter<ElfTypes>* owner_;
+  // Temporary buffer to create and store the entries.
+  dwarf::DebugInfoEntryWriter<> info_;
+  // Cache of already translated type descriptors.
+  std::map<std::string, size_t> type_cache_;  // type_desc -> definition_offset.
+  // 32-bit references which need to be resolved to a type later.
+  // Given type may be used multiple times.  Therefore we need a multimap.
+  std::multimap<std::string, size_t> lazy_types_;  // type_desc -> patch_offset.
+  // The current set of open namespace tags which are active and not closed yet.
+  std::vector<std::string> current_namespace_;
+};
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_INFO_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_line_writer.h b/compiler/debug/elf_debug_line_writer.h
new file mode 100644
index 0000000..d3859ca
--- /dev/null
+++ b/compiler/debug/elf_debug_line_writer.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2016 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_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_
+
+#include <vector>
+
+#include "compiled_method.h"
+#include "debug/dwarf/debug_line_opcode_writer.h"
+#include "debug/dwarf/headers.h"
+#include "debug/elf_compilation_unit.h"
+#include "dex_file-inl.h"
+#include "elf_builder.h"
+#include "stack_map.h"
+
+namespace art {
+namespace debug {
+
+typedef std::vector<DexFile::PositionInfo> PositionInfos;
+
+static bool PositionInfoCallback(void* ctx, const DexFile::PositionInfo& entry) {
+  static_cast<PositionInfos*>(ctx)->push_back(entry);
+  return false;
+}
+
+template<typename ElfTypes>
+class ElfDebugLineWriter {
+  using Elf_Addr = typename ElfTypes::Addr;
+
+ public:
+  explicit ElfDebugLineWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) {
+  }
+
+  void Start() {
+    builder_->GetDebugLine()->Start();
+  }
+
+  // Write line table for given set of methods.
+  // Returns the number of bytes written.
+  size_t WriteCompilationUnit(ElfCompilationUnit& compilation_unit) {
+    const bool is64bit = Is64BitInstructionSet(builder_->GetIsa());
+    const Elf_Addr text_address = builder_->GetText()->Exists()
+        ? builder_->GetText()->GetAddress()
+        : 0;
+
+    compilation_unit.debug_line_offset = builder_->GetDebugLine()->GetSize();
+
+    std::vector<dwarf::FileEntry> files;
+    std::unordered_map<std::string, size_t> files_map;
+    std::vector<std::string> directories;
+    std::unordered_map<std::string, size_t> directories_map;
+    int code_factor_bits_ = 0;
+    int dwarf_isa = -1;
+    switch (builder_->GetIsa()) {
+      case kArm:  // arm actually means thumb2.
+      case kThumb2:
+        code_factor_bits_ = 1;  // 16-bit instuctions
+        dwarf_isa = 1;  // DW_ISA_ARM_thumb.
+        break;
+      case kArm64:
+      case kMips:
+      case kMips64:
+        code_factor_bits_ = 2;  // 32-bit instructions
+        break;
+      case kNone:
+      case kX86:
+      case kX86_64:
+        break;
+    }
+    dwarf::DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_);
+    for (const MethodDebugInfo* mi : compilation_unit.methods) {
+      // Ignore function if we have already generated line table for the same address.
+      // It would confuse the debugger and the DWARF specification forbids it.
+      if (mi->deduped) {
+        continue;
+      }
+
+      uint32_t prologue_end = std::numeric_limits<uint32_t>::max();
+      ArrayRef<const SrcMapElem> pc2dex_map;
+      std::vector<SrcMapElem> pc2dex_map_from_stack_maps;
+      if (mi->IsFromOptimizingCompiler()) {
+        // Use stack maps to create mapping table from pc to dex.
+        const CodeInfo code_info(mi->compiled_method->GetVmapTable().data());
+        const StackMapEncoding encoding = code_info.ExtractEncoding();
+        for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
+          StackMap stack_map = code_info.GetStackMapAt(s, encoding);
+          DCHECK(stack_map.IsValid());
+          const uint32_t pc = stack_map.GetNativePcOffset(encoding);
+          const int32_t dex = stack_map.GetDexPc(encoding);
+          pc2dex_map_from_stack_maps.push_back({pc, dex});
+          if (stack_map.HasDexRegisterMap(encoding)) {
+            // Guess that the first map with local variables is the end of prologue.
+            prologue_end = std::min(prologue_end, pc);
+          }
+        }
+        std::sort(pc2dex_map_from_stack_maps.begin(),
+                  pc2dex_map_from_stack_maps.end());
+        pc2dex_map = ArrayRef<const SrcMapElem>(pc2dex_map_from_stack_maps);
+      } else {
+        // Use the mapping table provided by the quick compiler.
+        pc2dex_map = mi->compiled_method->GetSrcMappingTable();
+        prologue_end = 0;
+      }
+
+      if (pc2dex_map.empty()) {
+        continue;
+      }
+
+      Elf_Addr method_address = text_address + mi->low_pc;
+
+      PositionInfos dex2line_map;
+      const DexFile* dex = mi->dex_file;
+      if (!dex->DecodeDebugPositionInfo(mi->code_item, PositionInfoCallback, &dex2line_map)) {
+        continue;
+      }
+
+      if (dex2line_map.empty()) {
+        continue;
+      }
+
+      opcodes.SetAddress(method_address);
+      if (dwarf_isa != -1) {
+        opcodes.SetISA(dwarf_isa);
+      }
+
+      // Get and deduplicate directory and filename.
+      int file_index = 0;  // 0 - primary source file of the compilation.
+      auto& dex_class_def = dex->GetClassDef(mi->class_def_index);
+      const char* source_file = dex->GetSourceFile(dex_class_def);
+      if (source_file != nullptr) {
+        std::string file_name(source_file);
+        size_t file_name_slash = file_name.find_last_of('/');
+        std::string class_name(dex->GetClassDescriptor(dex_class_def));
+        size_t class_name_slash = class_name.find_last_of('/');
+        std::string full_path(file_name);
+
+        // Guess directory from package name.
+        int directory_index = 0;  // 0 - current directory of the compilation.
+        if (file_name_slash == std::string::npos &&  // Just filename.
+            class_name.front() == 'L' &&  // Type descriptor for a class.
+            class_name_slash != std::string::npos) {  // Has package name.
+          std::string package_name = class_name.substr(1, class_name_slash - 1);
+          auto it = directories_map.find(package_name);
+          if (it == directories_map.end()) {
+            directory_index = 1 + directories.size();
+            directories_map.emplace(package_name, directory_index);
+            directories.push_back(package_name);
+          } else {
+            directory_index = it->second;
+          }
+          full_path = package_name + "/" + file_name;
+        }
+
+        // Add file entry.
+        auto it2 = files_map.find(full_path);
+        if (it2 == files_map.end()) {
+          file_index = 1 + files.size();
+          files_map.emplace(full_path, file_index);
+          files.push_back(dwarf::FileEntry {
+            file_name,
+            directory_index,
+            0,  // Modification time - NA.
+            0,  // File size - NA.
+          });
+        } else {
+          file_index = it2->second;
+        }
+      }
+      opcodes.SetFile(file_index);
+
+      // Generate mapping opcodes from PC to Java lines.
+      if (file_index != 0) {
+        bool first = true;
+        for (SrcMapElem pc2dex : pc2dex_map) {
+          uint32_t pc = pc2dex.from_;
+          int dex_pc = pc2dex.to_;
+          // Find mapping with address with is greater than our dex pc; then go back one step.
+          auto dex2line = std::upper_bound(
+              dex2line_map.begin(),
+              dex2line_map.end(),
+              dex_pc,
+              [](uint32_t address, const DexFile::PositionInfo& entry) {
+                  return address < entry.address_;
+              });
+          // Look for first valid mapping after the prologue.
+          if (dex2line != dex2line_map.begin() && pc >= prologue_end) {
+            int line = (--dex2line)->line_;
+            if (first) {
+              first = false;
+              if (pc > 0) {
+                // Assume that any preceding code is prologue.
+                int first_line = dex2line_map.front().line_;
+                // Prologue is not a sensible place for a breakpoint.
+                opcodes.NegateStmt();
+                opcodes.AddRow(method_address, first_line);
+                opcodes.NegateStmt();
+                opcodes.SetPrologueEnd();
+              }
+              opcodes.AddRow(method_address + pc, line);
+            } else if (line != opcodes.CurrentLine()) {
+              opcodes.AddRow(method_address + pc, line);
+            }
+          }
+        }
+      } else {
+        // line 0 - instruction cannot be attributed to any source line.
+        opcodes.AddRow(method_address, 0);
+      }
+
+      opcodes.AdvancePC(text_address + mi->high_pc);
+      opcodes.EndSequence();
+    }
+    std::vector<uint8_t> buffer;
+    buffer.reserve(opcodes.data()->size() + KB);
+    size_t offset = builder_->GetDebugLine()->GetSize();
+    WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches_);
+    builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
+    return buffer.size();
+  }
+
+  void End(bool write_oat_patches) {
+    builder_->GetDebugLine()->End();
+    if (write_oat_patches) {
+      builder_->WritePatches(".debug_line.oat_patches",
+                             ArrayRef<const uintptr_t>(debug_line_patches_));
+    }
+  }
+
+ private:
+  ElfBuilder<ElfTypes>* builder_;
+  std::vector<uintptr_t> debug_line_patches_;
+};
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_LINE_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
new file mode 100644
index 0000000..a19b36f
--- /dev/null
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2016 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_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+
+#include <map>
+
+#include "arch/instruction_set.h"
+#include "compiled_method.h"
+#include "debug/dwarf/debug_info_entry_writer.h"
+#include "debug/dwarf/register.h"
+#include "debug/method_debug_info.h"
+#include "stack_map.h"
+
+namespace art {
+namespace debug {
+using Reg = dwarf::Reg;
+
+static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return Reg::ArmCore(machine_reg);
+    case kArm64:
+      return Reg::Arm64Core(machine_reg);
+    case kX86:
+      return Reg::X86Core(machine_reg);
+    case kX86_64:
+      return Reg::X86_64Core(machine_reg);
+    case kMips:
+      return Reg::MipsCore(machine_reg);
+    case kMips64:
+      return Reg::Mips64Core(machine_reg);
+    case kNone:
+      LOG(FATAL) << "No instruction set";
+  }
+  UNREACHABLE();
+}
+
+static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+      return Reg::ArmFp(machine_reg);
+    case kArm64:
+      return Reg::Arm64Fp(machine_reg);
+    case kX86:
+      return Reg::X86Fp(machine_reg);
+    case kX86_64:
+      return Reg::X86_64Fp(machine_reg);
+    case kMips:
+      return Reg::MipsFp(machine_reg);
+    case kMips64:
+      return Reg::Mips64Fp(machine_reg);
+    case kNone:
+      LOG(FATAL) << "No instruction set";
+  }
+  UNREACHABLE();
+}
+
+struct VariableLocation {
+  uint32_t low_pc;
+  uint32_t high_pc;
+  DexRegisterLocation reg_lo;  // May be None if the location is unknown.
+  DexRegisterLocation reg_hi;  // Most significant bits of 64-bit value.
+};
+
+// Get the location of given dex register (e.g. stack or machine register).
+// Note that the location might be different based on the current pc.
+// The result will cover all ranges where the variable is in scope.
+// PCs corresponding to stackmap with dex register map are accurate,
+// all other PCs are best-effort only.
+std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info,
+                                                   uint16_t vreg,
+                                                   bool is64bitValue,
+                                                   uint32_t dex_pc_low,
+                                                   uint32_t dex_pc_high) {
+  std::vector<VariableLocation> variable_locations;
+
+  // Get stack maps sorted by pc (they might not be sorted internally).
+  const CodeInfo code_info(method_info->compiled_method->GetVmapTable().data());
+  const StackMapEncoding encoding = code_info.ExtractEncoding();
+  std::map<uint32_t, StackMap> stack_maps;
+  for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
+    StackMap stack_map = code_info.GetStackMapAt(s, encoding);
+    DCHECK(stack_map.IsValid());
+    const uint32_t low_pc = method_info->low_pc + stack_map.GetNativePcOffset(encoding);
+    DCHECK_LE(low_pc, method_info->high_pc);
+    stack_maps.emplace(low_pc, stack_map);
+  }
+
+  // Create entries for the requested register based on stack map data.
+  for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) {
+    const StackMap& stack_map = it->second;
+    const uint32_t low_pc = it->first;
+    auto next_it = it;
+    next_it++;
+    const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first
+                                                         : method_info->high_pc;
+    DCHECK_LE(low_pc, high_pc);
+    if (low_pc == high_pc) {
+      continue;  // Ignore if the address range is empty.
+    }
+
+    // Check that the stack map is in the requested range.
+    uint32_t dex_pc = stack_map.GetDexPc(encoding);
+    if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) {
+      continue;
+    }
+
+    // Find the location of the dex register.
+    DexRegisterLocation reg_lo = DexRegisterLocation::None();
+    DexRegisterLocation reg_hi = DexRegisterLocation::None();
+    if (stack_map.HasDexRegisterMap(encoding)) {
+      DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
+          stack_map, encoding, method_info->code_item->registers_size_);
+      reg_lo = dex_register_map.GetDexRegisterLocation(
+          vreg, method_info->code_item->registers_size_, code_info, encoding);
+      if (is64bitValue) {
+        reg_hi = dex_register_map.GetDexRegisterLocation(
+            vreg + 1, method_info->code_item->registers_size_, code_info, encoding);
+      }
+    }
+
+    // Add location entry for this address range.
+    if (!variable_locations.empty() &&
+        variable_locations.back().reg_lo == reg_lo &&
+        variable_locations.back().reg_hi == reg_hi &&
+        variable_locations.back().high_pc == low_pc) {
+      // Merge with the previous entry (extend its range).
+      variable_locations.back().high_pc = high_pc;
+    } else if (!variable_locations.empty() && reg_lo == DexRegisterLocation::None()) {
+      // Unknown location - use the last known location as best-effort guess.
+      variable_locations.back().high_pc = high_pc;
+    } else {
+      variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi});
+    }
+  }
+
+  return variable_locations;
+}
+
+// Write table into .debug_loc which describes location of dex register.
+// The dex register might be valid only at some points and it might
+// move between machine registers and stack.
+static void WriteDebugLocEntry(const MethodDebugInfo* method_info,
+                               uint16_t vreg,
+                               bool is64bitValue,
+                               uint32_t compilation_unit_low_pc,
+                               uint32_t dex_pc_low,
+                               uint32_t dex_pc_high,
+                               InstructionSet isa,
+                               dwarf::DebugInfoEntryWriter<>* debug_info,
+                               std::vector<uint8_t>* debug_loc_buffer,
+                               std::vector<uint8_t>* debug_ranges_buffer) {
+  using Kind = DexRegisterLocation::Kind;
+  if (!method_info->IsFromOptimizingCompiler()) {
+    return;
+  }
+
+  dwarf::Writer<> debug_loc(debug_loc_buffer);
+  dwarf::Writer<> debug_ranges(debug_ranges_buffer);
+  debug_info->WriteSecOffset(dwarf::DW_AT_location, debug_loc.size());
+  debug_info->WriteSecOffset(dwarf::DW_AT_start_scope, debug_ranges.size());
+
+  std::vector<VariableLocation> variable_locations = GetVariableLocations(
+      method_info,
+      vreg,
+      is64bitValue,
+      dex_pc_low,
+      dex_pc_high);
+
+  // Write .debug_loc entries.
+  const bool is64bit = Is64BitInstructionSet(isa);
+  std::vector<uint8_t> expr_buffer;
+  for (const VariableLocation& variable_location : variable_locations) {
+    // Translate dex register location to DWARF expression.
+    // Note that 64-bit value might be split to two distinct locations.
+    // (for example, two 32-bit machine registers, or even stack and register)
+    dwarf::Expression expr(&expr_buffer);
+    DexRegisterLocation reg_lo = variable_location.reg_lo;
+    DexRegisterLocation reg_hi = variable_location.reg_hi;
+    for (int piece = 0; piece < (is64bitValue ? 2 : 1); piece++) {
+      DexRegisterLocation reg_loc = (piece == 0 ? reg_lo : reg_hi);
+      const Kind kind = reg_loc.GetKind();
+      const int32_t value = reg_loc.GetValue();
+      if (kind == Kind::kInStack) {
+        const size_t frame_size = method_info->compiled_method->GetFrameSizeInBytes();
+        // The stack offset is relative to SP. Make it relative to CFA.
+        expr.WriteOpFbreg(value - frame_size);
+        if (piece == 0 && reg_hi.GetKind() == Kind::kInStack &&
+            reg_hi.GetValue() == value + 4) {
+          break;  // the high word is correctly implied by the low word.
+        }
+      } else if (kind == Kind::kInRegister) {
+        expr.WriteOpReg(GetDwarfCoreReg(isa, value).num());
+        if (piece == 0 && reg_hi.GetKind() == Kind::kInRegisterHigh &&
+            reg_hi.GetValue() == value) {
+          break;  // the high word is correctly implied by the low word.
+        }
+      } else if (kind == Kind::kInFpuRegister) {
+        if ((isa == kArm || isa == kThumb2) &&
+            piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister &&
+            reg_hi.GetValue() == value + 1 && value % 2 == 0) {
+          // Translate S register pair to D register (e.g. S4+S5 to D2).
+          expr.WriteOpReg(Reg::ArmDp(value / 2).num());
+          break;
+        }
+        expr.WriteOpReg(GetDwarfFpReg(isa, value).num());
+        if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh &&
+            reg_hi.GetValue() == reg_lo.GetValue()) {
+          break;  // the high word is correctly implied by the low word.
+        }
+      } else if (kind == Kind::kConstant) {
+        expr.WriteOpConsts(value);
+        expr.WriteOpStackValue();
+      } else if (kind == Kind::kNone) {
+        break;
+      } else {
+        // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
+        // kInRegisterHigh and kInFpuRegisterHigh should be handled by
+        // the special cases above and they should not occur alone.
+        LOG(ERROR) << "Unexpected register location kind: "
+                   << DexRegisterLocation::PrettyDescriptor(kind);
+        break;
+      }
+      if (is64bitValue) {
+        // Write the marker which is needed by split 64-bit values.
+        // This code is skipped by the special cases.
+        expr.WriteOpPiece(4);
+      }
+    }
+
+    if (expr.size() > 0) {
+      if (is64bit) {
+        debug_loc.PushUint64(variable_location.low_pc - compilation_unit_low_pc);
+        debug_loc.PushUint64(variable_location.high_pc - compilation_unit_low_pc);
+      } else {
+        debug_loc.PushUint32(variable_location.low_pc - compilation_unit_low_pc);
+        debug_loc.PushUint32(variable_location.high_pc - compilation_unit_low_pc);
+      }
+      // Write the expression.
+      debug_loc.PushUint16(expr.size());
+      debug_loc.PushData(expr.data());
+    } else {
+      // Do not generate .debug_loc if the location is not known.
+    }
+  }
+  // Write end-of-list entry.
+  if (is64bit) {
+    debug_loc.PushUint64(0);
+    debug_loc.PushUint64(0);
+  } else {
+    debug_loc.PushUint32(0);
+    debug_loc.PushUint32(0);
+  }
+
+  // Write .debug_ranges entries.
+  // This includes ranges where the variable is in scope but the location is not known.
+  for (size_t i = 0; i < variable_locations.size(); i++) {
+    uint32_t low_pc = variable_locations[i].low_pc;
+    uint32_t high_pc = variable_locations[i].high_pc;
+    while (i + 1 < variable_locations.size() && variable_locations[i+1].low_pc == high_pc) {
+      // Merge address range with the next entry.
+      high_pc = variable_locations[++i].high_pc;
+    }
+    if (is64bit) {
+      debug_ranges.PushUint64(low_pc - compilation_unit_low_pc);
+      debug_ranges.PushUint64(high_pc - compilation_unit_low_pc);
+    } else {
+      debug_ranges.PushUint32(low_pc - compilation_unit_low_pc);
+      debug_ranges.PushUint32(high_pc - compilation_unit_low_pc);
+    }
+  }
+  // Write end-of-list entry.
+  if (is64bit) {
+    debug_ranges.PushUint64(0);
+    debug_ranges.PushUint64(0);
+  } else {
+    debug_ranges.PushUint32(0);
+    debug_ranges.PushUint32(0);
+  }
+}
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_LOC_WRITER_H_
+
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
new file mode 100644
index 0000000..01bd679
--- /dev/null
+++ b/compiler/debug/elf_debug_writer.cc
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2016 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 "elf_debug_writer.h"
+
+#include <vector>
+
+#include "debug/dwarf/dwarf_constants.h"
+#include "debug/elf_compilation_unit.h"
+#include "debug/elf_debug_frame_writer.h"
+#include "debug/elf_debug_info_writer.h"
+#include "debug/elf_debug_line_writer.h"
+#include "debug/elf_debug_loc_writer.h"
+#include "debug/elf_gnu_debugdata_writer.h"
+#include "debug/elf_symtab_writer.h"
+#include "debug/method_debug_info.h"
+#include "elf_builder.h"
+#include "linker/vector_output_stream.h"
+#include "utils/array_ref.h"
+
+namespace art {
+namespace debug {
+
+template <typename ElfTypes>
+void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
+                    const ArrayRef<const MethodDebugInfo>& method_infos,
+                    dwarf::CFIFormat cfi_format,
+                    bool write_oat_patches) {
+  // Add methods to .symtab.
+  WriteDebugSymbols(builder, method_infos, true /* with_signature */);
+  // Generate CFI (stack unwinding information).
+  WriteCFISection(builder, method_infos, cfi_format, write_oat_patches);
+  // Write DWARF .debug_* sections.
+  WriteDebugSections(builder, method_infos, write_oat_patches);
+}
+
+template<typename ElfTypes>
+static void WriteDebugSections(ElfBuilder<ElfTypes>* builder,
+                               const ArrayRef<const MethodDebugInfo>& method_infos,
+                               bool write_oat_patches) {
+  // Group the methods into compilation units based on source file.
+  std::vector<ElfCompilationUnit> compilation_units;
+  const char* last_source_file = nullptr;
+  for (const MethodDebugInfo& mi : method_infos) {
+    auto& dex_class_def = mi.dex_file->GetClassDef(mi.class_def_index);
+    const char* source_file = mi.dex_file->GetSourceFile(dex_class_def);
+    if (compilation_units.empty() || source_file != last_source_file) {
+      compilation_units.push_back(ElfCompilationUnit());
+    }
+    ElfCompilationUnit& cu = compilation_units.back();
+    cu.methods.push_back(&mi);
+    cu.low_pc = std::min(cu.low_pc, mi.low_pc);
+    cu.high_pc = std::max(cu.high_pc, mi.high_pc);
+    last_source_file = source_file;
+  }
+
+  // Write .debug_line section.
+  if (!compilation_units.empty()) {
+    ElfDebugLineWriter<ElfTypes> line_writer(builder);
+    line_writer.Start();
+    for (auto& compilation_unit : compilation_units) {
+      line_writer.WriteCompilationUnit(compilation_unit);
+    }
+    line_writer.End(write_oat_patches);
+  }
+
+  // Write .debug_info section.
+  if (!compilation_units.empty()) {
+    ElfDebugInfoWriter<ElfTypes> info_writer(builder);
+    info_writer.Start();
+    for (const auto& compilation_unit : compilation_units) {
+      ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
+      cu_writer.Write(compilation_unit);
+    }
+    info_writer.End(write_oat_patches);
+  }
+}
+
+std::vector<uint8_t> MakeMiniDebugInfo(
+    InstructionSet isa,
+    size_t rodata_size,
+    size_t text_size,
+    const ArrayRef<const MethodDebugInfo>& method_infos) {
+  if (Is64BitInstructionSet(isa)) {
+    return MakeMiniDebugInfoInternal<ElfTypes64>(isa, rodata_size, text_size, method_infos);
+  } else {
+    return MakeMiniDebugInfoInternal<ElfTypes32>(isa, rodata_size, text_size, method_infos);
+  }
+}
+
+template <typename ElfTypes>
+static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal(
+    const MethodDebugInfo& method_info) {
+  const InstructionSet isa = method_info.compiled_method->GetInstructionSet();
+  std::vector<uint8_t> buffer;
+  buffer.reserve(KB);
+  VectorOutputStream out("Debug ELF file", &buffer);
+  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
+  // No program headers since the ELF file is not linked and has no allocated sections.
+  builder->Start(false /* write_program_headers */);
+  WriteDebugInfo(builder.get(),
+                 ArrayRef<const MethodDebugInfo>(&method_info, 1),
+                 dwarf::DW_DEBUG_FRAME_FORMAT,
+                 false /* write_oat_patches */);
+  builder->End();
+  CHECK(builder->Good());
+  // Make a copy of the buffer.  We want to shrink it anyway.
+  uint8_t* result = new uint8_t[buffer.size()];
+  CHECK(result != nullptr);
+  memcpy(result, buffer.data(), buffer.size());
+  return ArrayRef<const uint8_t>(result, buffer.size());
+}
+
+ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const MethodDebugInfo& method_info) {
+  const InstructionSet isa = method_info.compiled_method->GetInstructionSet();
+  if (Is64BitInstructionSet(isa)) {
+    return WriteDebugElfFileForMethodInternal<ElfTypes64>(method_info);
+  } else {
+    return WriteDebugElfFileForMethodInternal<ElfTypes32>(method_info);
+  }
+}
+
+template <typename ElfTypes>
+static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal(
+    const InstructionSet isa, const ArrayRef<mirror::Class*>& types)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  std::vector<uint8_t> buffer;
+  buffer.reserve(KB);
+  VectorOutputStream out("Debug ELF file", &buffer);
+  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
+  // No program headers since the ELF file is not linked and has no allocated sections.
+  builder->Start(false /* write_program_headers */);
+  ElfDebugInfoWriter<ElfTypes> info_writer(builder.get());
+  info_writer.Start();
+  ElfCompilationUnitWriter<ElfTypes> cu_writer(&info_writer);
+  cu_writer.Write(types);
+  info_writer.End(false /* write_oat_patches */);
+
+  builder->End();
+  CHECK(builder->Good());
+  // Make a copy of the buffer.  We want to shrink it anyway.
+  uint8_t* result = new uint8_t[buffer.size()];
+  CHECK(result != nullptr);
+  memcpy(result, buffer.data(), buffer.size());
+  return ArrayRef<const uint8_t>(result, buffer.size());
+}
+
+ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
+                                                    const ArrayRef<mirror::Class*>& types) {
+  if (Is64BitInstructionSet(isa)) {
+    return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, types);
+  } else {
+    return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, types);
+  }
+}
+
+// Explicit instantiations
+template void WriteDebugInfo<ElfTypes32>(
+    ElfBuilder<ElfTypes32>* builder,
+    const ArrayRef<const MethodDebugInfo>& method_infos,
+    dwarf::CFIFormat cfi_format,
+    bool write_oat_patches);
+template void WriteDebugInfo<ElfTypes64>(
+    ElfBuilder<ElfTypes64>* builder,
+    const ArrayRef<const MethodDebugInfo>& method_infos,
+    dwarf::CFIFormat cfi_format,
+    bool write_oat_patches);
+
+}  // namespace debug
+}  // namespace art
diff --git a/compiler/elf_writer_debug.h b/compiler/debug/elf_debug_writer.h
similarity index 60%
rename from compiler/elf_writer_debug.h
rename to compiler/debug/elf_debug_writer.h
index e19da08..103b501 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 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.
@@ -14,12 +14,12 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_ELF_WRITER_DEBUG_H_
-#define ART_COMPILER_ELF_WRITER_DEBUG_H_
+#ifndef ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
 
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "dwarf/dwarf_constants.h"
+#include "debug/dwarf/dwarf_constants.h"
 #include "elf_builder.h"
 #include "utils/array_ref.h"
 
@@ -27,25 +27,27 @@
 namespace mirror {
 class Class;
 }
-namespace dwarf {
+namespace debug {
 struct MethodDebugInfo;
 
 template <typename ElfTypes>
 void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
                     const ArrayRef<const MethodDebugInfo>& method_infos,
-                    CFIFormat cfi_format);
+                    dwarf::CFIFormat cfi_format,
+                    bool write_oat_patches);
 
-template <typename ElfTypes>
-void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* builder,
-                        const ArrayRef<const MethodDebugInfo>& method_infos);
+std::vector<uint8_t> MakeMiniDebugInfo(InstructionSet isa,
+                                       size_t rodata_section_size,
+                                       size_t text_section_size,
+                                       const ArrayRef<const MethodDebugInfo>& method_infos);
 
-ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info);
+ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const MethodDebugInfo& method_info);
 
 ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
                                                     const ArrayRef<mirror::Class*>& types)
     SHARED_REQUIRES(Locks::mutator_lock_);
 
-}  // namespace dwarf
+}  // namespace debug
 }  // namespace art
 
-#endif  // ART_COMPILER_ELF_WRITER_DEBUG_H_
+#endif  // ART_COMPILER_DEBUG_ELF_DEBUG_WRITER_H_
diff --git a/compiler/debug/elf_gnu_debugdata_writer.h b/compiler/debug/elf_gnu_debugdata_writer.h
new file mode 100644
index 0000000..5c7d1c7
--- /dev/null
+++ b/compiler/debug/elf_gnu_debugdata_writer.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 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_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_
+
+#include <vector>
+
+#include "arch/instruction_set.h"
+#include "elf_builder.h"
+#include "linker/vector_output_stream.h"
+
+// liblzma.
+#include "7zCrc.h"
+#include "XzCrc64.h"
+#include "XzEnc.h"
+
+namespace art {
+namespace debug {
+
+static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) {
+  // Configure the compression library.
+  CrcGenerateTable();
+  Crc64GenerateTable();
+  CLzma2EncProps lzma2Props;
+  Lzma2EncProps_Init(&lzma2Props);
+  lzma2Props.lzmaProps.level = 1;  // Fast compression.
+  Lzma2EncProps_Normalize(&lzma2Props);
+  CXzProps props;
+  XzProps_Init(&props);
+  props.lzma2Props = &lzma2Props;
+  // Implement the required interface for communication (written in C so no virtual methods).
+  struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress {
+    static SRes ReadImpl(void* p, void* buf, size_t* size) {
+      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p));
+      *size = std::min(*size, ctx->src_->size() - ctx->src_pos_);
+      memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size);
+      ctx->src_pos_ += *size;
+      return SZ_OK;
+    }
+    static size_t WriteImpl(void* p, const void* buf, size_t size) {
+      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p));
+      const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf);
+      ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size);
+      return size;
+    }
+    static SRes ProgressImpl(void* , UInt64, UInt64) {
+      return SZ_OK;
+    }
+    size_t src_pos_;
+    const std::vector<uint8_t>* src_;
+    std::vector<uint8_t>* dst_;
+  };
+  XzCallbacks callbacks;
+  callbacks.Read = XzCallbacks::ReadImpl;
+  callbacks.Write = XzCallbacks::WriteImpl;
+  callbacks.Progress = XzCallbacks::ProgressImpl;
+  callbacks.src_pos_ = 0;
+  callbacks.src_ = src;
+  callbacks.dst_ = dst;
+  // Compress.
+  SRes res = Xz_Encode(&callbacks, &callbacks, &props, &callbacks);
+  CHECK_EQ(res, SZ_OK);
+}
+
+template <typename ElfTypes>
+static std::vector<uint8_t> MakeMiniDebugInfoInternal(
+    InstructionSet isa,
+    size_t rodata_section_size,
+    size_t text_section_size,
+    const ArrayRef<const MethodDebugInfo>& method_infos) {
+  std::vector<uint8_t> buffer;
+  buffer.reserve(KB);
+  VectorOutputStream out("Mini-debug-info ELF file", &buffer);
+  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
+  builder->Start();
+  // Mirror .rodata and .text as NOBITS sections.
+  // It is needed to detected relocations after compression.
+  builder->GetRoData()->WriteNoBitsSection(rodata_section_size);
+  builder->GetText()->WriteNoBitsSection(text_section_size);
+  WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
+  WriteCFISection(builder.get(),
+                  method_infos,
+                  dwarf::DW_DEBUG_FRAME_FORMAT,
+                  false /* write_oat_paches */);
+  builder->End();
+  CHECK(builder->Good());
+  std::vector<uint8_t> compressed_buffer;
+  compressed_buffer.reserve(buffer.size() / 4);
+  XzCompress(&buffer, &compressed_buffer);
+  return compressed_buffer;
+}
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_GNU_DEBUGDATA_WRITER_H_
+
diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h
new file mode 100644
index 0000000..41508f4
--- /dev/null
+++ b/compiler/debug/elf_symtab_writer.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2016 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_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
+#define ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
+
+#include <unordered_set>
+
+#include "debug/method_debug_info.h"
+#include "elf_builder.h"
+#include "utils.h"
+
+namespace art {
+namespace debug {
+
+// The ARM specification defines three special mapping symbols
+// $a, $t and $d which mark ARM, Thumb and data ranges respectively.
+// These symbols can be used by tools, for example, to pretty
+// print instructions correctly.  Objdump will use them if they
+// exist, but it will still work well without them.
+// However, these extra symbols take space, so let's just generate
+// one symbol which marks the whole .text section as code.
+constexpr bool kGenerateSingleArmMappingSymbol = true;
+
+template <typename ElfTypes>
+static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
+                              const ArrayRef<const MethodDebugInfo>& method_infos,
+                              bool with_signature) {
+  bool generated_mapping_symbol = false;
+  auto* strtab = builder->GetStrTab();
+  auto* symtab = builder->GetSymTab();
+
+  if (method_infos.empty()) {
+    return;
+  }
+
+  // Find all addresses (low_pc) which contain deduped methods.
+  // The first instance of method is not marked deduped_, but the rest is.
+  std::unordered_set<uint32_t> deduped_addresses;
+  for (const MethodDebugInfo& info : method_infos) {
+    if (info.deduped) {
+      deduped_addresses.insert(info.low_pc);
+    }
+  }
+
+  strtab->Start();
+  strtab->Write("");  // strtab should start with empty string.
+  std::string last_name;
+  size_t last_name_offset = 0;
+  for (const MethodDebugInfo& info : method_infos) {
+    if (info.deduped) {
+      continue;  // Add symbol only for the first instance.
+    }
+    std::string name = PrettyMethod(info.dex_method_index, *info.dex_file, with_signature);
+    if (deduped_addresses.find(info.low_pc) != deduped_addresses.end()) {
+      name += " [DEDUPED]";
+    }
+    // If we write method names without signature, we might see the same name multiple times.
+    size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
+
+    const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr;
+    const bool is_relative = (text != nullptr);
+    uint32_t low_pc = info.low_pc;
+    // Add in code delta, e.g., thumb bit 0 for Thumb2 code.
+    low_pc += info.compiled_method->CodeDelta();
+    symtab->Add(name_offset,
+                text,
+                low_pc,
+                is_relative,
+                info.high_pc - info.low_pc,
+                STB_GLOBAL,
+                STT_FUNC);
+
+    // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
+    // instructions, so that disassembler tools can correctly disassemble.
+    // Note that even if we generate just a single mapping symbol, ARM's Streamline
+    // requires it to match function symbol.  Just address 0 does not work.
+    if (info.compiled_method->GetInstructionSet() == kThumb2) {
+      if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) {
+        symtab->Add(strtab->Write("$t"), text, info.low_pc & ~1,
+                    is_relative, 0, STB_LOCAL, STT_NOTYPE);
+        generated_mapping_symbol = true;
+      }
+    }
+
+    last_name = std::move(name);
+    last_name_offset = name_offset;
+  }
+  strtab->End();
+
+  // Symbols are buffered and written after names (because they are smaller).
+  // We could also do two passes in this function to avoid the buffering.
+  symtab->Start();
+  symtab->Write();
+  symtab->End();
+}
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_ELF_SYMTAB_WRITER_H_
+
diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h
new file mode 100644
index 0000000..6b3dd8c
--- /dev/null
+++ b/compiler/debug/method_debug_info.h
@@ -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.
+ */
+
+#ifndef ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_
+#define ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_
+
+#include "compiled_method.h"
+#include "dex_file.h"
+
+namespace art {
+namespace debug {
+
+struct MethodDebugInfo {
+  const DexFile* dex_file;
+  size_t class_def_index;
+  uint32_t dex_method_index;
+  uint32_t access_flags;
+  const DexFile::CodeItem* code_item;
+  bool deduped;
+  uintptr_t low_pc;
+  uintptr_t high_pc;
+  CompiledMethod* compiled_method;
+
+  bool IsFromOptimizingCompiler() const {
+    return compiled_method->GetQuickCode().size() > 0 &&
+           compiled_method->GetVmapTable().size() > 0 &&
+           compiled_method->GetGcMap().size() == 0 &&
+           code_item != nullptr;
+  }
+};
+
+}  // namespace debug
+}  // namespace art
+
+#endif  // ART_COMPILER_DEBUG_METHOD_DEBUG_INFO_H_
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 22b178c..209f101 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -875,6 +875,7 @@
       move_result = mir_graph->FindMoveResult(bb, invoke);
       result = GenInlineIPut(mir_graph, bb, invoke, move_result, method);
       break;
+    case kInlineOpConstructor:
     case kInlineStringInit:
       return false;
     default:
diff --git a/compiler/dex/quick/lazy_debug_frame_opcode_writer.h b/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
index c425fc8..85050f4 100644
--- a/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
+++ b/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
@@ -19,7 +19,7 @@
 
 #include "base/arena_allocator.h"
 #include "base/arena_containers.h"
-#include "dwarf/debug_frame_opcode_writer.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
 
 namespace art {
 struct LIR;
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 6bc2a13..f078bf6 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2306,9 +2306,9 @@
           mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, soa.Self());
           // Mark methods as pre-verified. If we don't do this, the interpreter will run with
           // access checks.
-          klass->SetPreverifiedFlagOnAllMethods(
+          klass->SetSkipAccessChecksFlagOnAllMethods(
               GetInstructionSetPointerSize(manager_->GetCompiler()->GetInstructionSet()));
-          klass->SetPreverified();
+          klass->SetVerificationAttempted();
         }
         // Record the final class status if necessary.
         ClassReference ref(manager_->GetDexFile(), class_def_index);
diff --git a/compiler/driver/compiler_driver_test.cc b/compiler/driver/compiler_driver_test.cc
index 4c03e5d..4785885 100644
--- a/compiler/driver/compiler_driver_test.cc
+++ b/compiler/driver/compiler_driver_test.cc
@@ -249,9 +249,9 @@
 
     ProfileCompilationInfo info;
     for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
-      std::cout << std::string(dex_file->GetLocation());
-      profile_info_.AddData(dex_file->GetLocation(), dex_file->GetLocationChecksum(), 1);
-      profile_info_.AddData(dex_file->GetLocation(), dex_file->GetLocationChecksum(), 2);
+      std::string key = ProfileCompilationInfo::GetProfileDexFileKey(dex_file->GetLocation());
+      profile_info_.AddData(key, dex_file->GetLocationChecksum(), 1);
+      profile_info_.AddData(key, dex_file->GetLocationChecksum(), 2);
     }
     return &profile_info_;
   }
diff --git a/compiler/dwarf/method_debug_info.h b/compiler/dwarf/method_debug_info.h
deleted file mode 100644
index e8ba914..0000000
--- a/compiler/dwarf/method_debug_info.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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_COMPILER_DWARF_METHOD_DEBUG_INFO_H_
-#define ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_
-
-#include "dex_file.h"
-
-namespace art {
-class CompiledMethod;
-namespace dwarf {
-
-struct MethodDebugInfo {
-  const DexFile* dex_file_;
-  size_t class_def_index_;
-  uint32_t dex_method_index_;
-  uint32_t access_flags_;
-  const DexFile::CodeItem* code_item_;
-  bool deduped_;
-  uintptr_t low_pc_;
-  uintptr_t high_pc_;
-  CompiledMethod* compiled_method_;
-};
-
-}  // namespace dwarf
-}  // namespace art
-
-#endif  // ART_COMPILER_DWARF_METHOD_DEBUG_INFO_H_
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 3d24d19..b673eeb 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -110,18 +110,27 @@
       CHECK(sections.empty() || sections.back()->finished_);
       // The first ELF section index is 1. Index 0 is reserved for NULL.
       section_index_ = sections.size() + 1;
-      // Push this section on the list of written sections.
-      sections.push_back(this);
+      // Page-align if we switch between allocated and non-allocated sections,
+      // or if we change the type of allocation (e.g. executable vs non-executable).
+      if (!sections.empty()) {
+        if (header_.sh_flags != sections.back()->header_.sh_flags) {
+          header_.sh_addralign = kPageSize;
+        }
+      }
       // Align file position.
       if (header_.sh_type != SHT_NOBITS) {
-        header_.sh_offset = RoundUp(owner_->stream_.Seek(0, kSeekCurrent), header_.sh_addralign);
-        owner_->stream_.Seek(header_.sh_offset, kSeekSet);
+        header_.sh_offset = owner_->AlignFileOffset(header_.sh_addralign);
+      } else {
+        header_.sh_offset = 0;
       }
       // Align virtual memory address.
       if ((header_.sh_flags & SHF_ALLOC) != 0) {
-        header_.sh_addr = RoundUp(owner_->virtual_address_, header_.sh_addralign);
-        owner_->virtual_address_ = header_.sh_addr;
+        header_.sh_addr = owner_->AlignVirtualAddress(header_.sh_addralign);
+      } else {
+        header_.sh_addr = 0;
       }
+      // Push this section on the list of written sections.
+      sections.push_back(this);
     }
 
     // Finish writing of this section.
@@ -170,8 +179,8 @@
     // and it will be zero-initialized when the ELF file is loaded in the running program.
     void WriteNoBitsSection(Elf_Word size) {
       DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
-      Start();
       header_.sh_type = SHT_NOBITS;
+      Start();
       header_.sh_size = size;
       End();
     }
@@ -293,12 +302,13 @@
         dynamic_(this, ".dynamic", SHT_DYNAMIC, SHF_ALLOC, &dynstr_, 0, kPageSize, sizeof(Elf_Dyn)),
         eh_frame_(this, ".eh_frame", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
         eh_frame_hdr_(this, ".eh_frame_hdr", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, 4, 0),
-        strtab_(this, ".strtab", 0, kPageSize),
+        strtab_(this, ".strtab", 0, 1),
         symtab_(this, ".symtab", SHT_SYMTAB, 0, &strtab_),
         debug_frame_(this, ".debug_frame", SHT_PROGBITS, 0, nullptr, 0, sizeof(Elf_Addr), 0),
         debug_info_(this, ".debug_info", SHT_PROGBITS, 0, nullptr, 0, 1, 0),
         debug_line_(this, ".debug_line", SHT_PROGBITS, 0, nullptr, 0, 1, 0),
         shstrtab_(this, ".shstrtab", 0, 1),
+        started_(false),
         virtual_address_(0) {
     text_.phdr_flags_ = PF_R | PF_X;
     bss_.phdr_flags_ = PF_R | PF_W;
@@ -351,22 +361,25 @@
     other_sections_.push_back(std::move(s));
   }
 
-  // Set where the next section will be allocated in the virtual address space.
-  void SetVirtualAddress(Elf_Addr address) {
-    DCHECK_GE(address, virtual_address_);
-    virtual_address_ = address;
-  }
-
-  void Start() {
-    // Reserve space for ELF header and program headers.
-    // We do not know the number of headers until later, so
-    // it is easiest to just reserve a fixed amount of space.
-    int size = sizeof(Elf_Ehdr) + sizeof(Elf_Phdr) * kMaxProgramHeaders;
+  // Reserve space for ELF header and program headers.
+  // We do not know the number of headers until later, so
+  // it is easiest to just reserve a fixed amount of space.
+  // Program headers are required for loading by the linker.
+  // It is possible to omit them for ELF files used for debugging.
+  void Start(bool write_program_headers = true) {
+    int size = sizeof(Elf_Ehdr);
+    if (write_program_headers) {
+      size += sizeof(Elf_Phdr) * kMaxProgramHeaders;
+    }
     stream_.Seek(size, kSeekSet);
+    started_ = true;
     virtual_address_ += size;
+    write_program_headers_ = write_program_headers;
   }
 
   void End() {
+    DCHECK(started_);
+
     // Write section names and finish the section headers.
     shstrtab_.Start();
     shstrtab_.Write("");
@@ -386,8 +399,7 @@
       shdrs.push_back(section->header_);
     }
     Elf_Off section_headers_offset;
-    section_headers_offset = RoundUp(stream_.Seek(0, kSeekCurrent), sizeof(Elf_Off));
-    stream_.Seek(section_headers_offset, kSeekSet);
+    section_headers_offset = AlignFileOffset(sizeof(Elf_Off));
     stream_.WriteFully(shdrs.data(), shdrs.size() * sizeof(shdrs[0]));
 
     // Flush everything else before writing the program headers. This should prevent
@@ -395,14 +407,21 @@
     // and partially written data if we suddenly lose power, for example.
     stream_.Flush();
 
-    // Write the initial file headers.
-    std::vector<Elf_Phdr> phdrs = MakeProgramHeaders();
+    // The main ELF header.
     Elf_Ehdr elf_header = MakeElfHeader(isa_);
-    elf_header.e_phoff = sizeof(Elf_Ehdr);
     elf_header.e_shoff = section_headers_offset;
-    elf_header.e_phnum = phdrs.size();
     elf_header.e_shnum = shdrs.size();
     elf_header.e_shstrndx = shstrtab_.GetSectionIndex();
+
+    // Program headers (i.e. mmap instructions).
+    std::vector<Elf_Phdr> phdrs;
+    if (write_program_headers_) {
+      phdrs = MakeProgramHeaders();
+      CHECK_LE(phdrs.size(), kMaxProgramHeaders);
+      elf_header.e_phoff = sizeof(Elf_Ehdr);
+      elf_header.e_phnum = phdrs.size();
+    }
+
     stream_.Seek(0, kSeekSet);
     stream_.WriteFully(&elf_header, sizeof(elf_header));
     stream_.WriteFully(phdrs.data(), phdrs.size() * sizeof(phdrs[0]));
@@ -492,6 +511,14 @@
     return &stream_;
   }
 
+  off_t AlignFileOffset(size_t alignment) {
+     return stream_.Seek(RoundUp(stream_.Seek(0, kSeekCurrent), alignment), kSeekSet);
+  }
+
+  Elf_Addr AlignVirtualAddress(size_t alignment) {
+     return virtual_address_ = RoundUp(virtual_address_, alignment);
+  }
+
  private:
   static Elf_Ehdr MakeElfHeader(InstructionSet isa) {
     Elf_Ehdr elf_header = Elf_Ehdr();
@@ -666,9 +693,13 @@
   // List of used section in the order in which they were written.
   std::vector<Section*> sections_;
 
+  bool started_;
+
   // Used for allocation of virtual address space.
   Elf_Addr virtual_address_;
 
+  size_t write_program_headers_;
+
   DISALLOW_COPY_AND_ASSIGN(ElfBuilder);
 };
 
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index c5a0fd5..d50a08c 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -32,9 +32,9 @@
 class ElfFile;
 class OutputStream;
 
-namespace dwarf {
+namespace debug {
 struct MethodDebugInfo;
-}  // namespace dwarf
+}  // namespace debug
 
 class ElfWriter {
  public:
@@ -52,13 +52,16 @@
   virtual ~ElfWriter() {}
 
   virtual void Start() = 0;
+  virtual void PrepareDebugInfo(size_t rodata_section_size,
+                                size_t text_section_size,
+                                const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
   virtual OutputStream* StartRoData() = 0;
   virtual void EndRoData(OutputStream* rodata) = 0;
   virtual OutputStream* StartText() = 0;
   virtual void EndText(OutputStream* text) = 0;
   virtual void SetBssSize(size_t bss_size) = 0;
   virtual void WriteDynamicSection() = 0;
-  virtual void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) = 0;
+  virtual void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
   virtual void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) = 0;
   virtual bool End() = 0;
 
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
deleted file mode 100644
index d1f5007..0000000
--- a/compiler/elf_writer_debug.cc
+++ /dev/null
@@ -1,1646 +0,0 @@
-/*
- * 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 "elf_writer_debug.h"
-
-#include <algorithm>
-#include <unordered_set>
-#include <vector>
-#include <cstdio>
-
-#include "base/casts.h"
-#include "base/stl_util.h"
-#include "linear_alloc.h"
-#include "compiled_method.h"
-#include "dex_file-inl.h"
-#include "driver/compiler_driver.h"
-#include "dwarf/expression.h"
-#include "dwarf/headers.h"
-#include "dwarf/method_debug_info.h"
-#include "dwarf/register.h"
-#include "elf_builder.h"
-#include "linker/vector_output_stream.h"
-#include "mirror/array.h"
-#include "mirror/class-inl.h"
-#include "mirror/class.h"
-#include "oat_writer.h"
-#include "stack_map.h"
-#include "utils.h"
-
-// liblzma.
-#include "XzEnc.h"
-#include "7zCrc.h"
-#include "XzCrc64.h"
-
-namespace art {
-namespace dwarf {
-
-// The ARM specification defines three special mapping symbols
-// $a, $t and $d which mark ARM, Thumb and data ranges respectively.
-// These symbols can be used by tools, for example, to pretty
-// print instructions correctly.  Objdump will use them if they
-// exist, but it will still work well without them.
-// However, these extra symbols take space, so let's just generate
-// one symbol which marks the whole .text section as code.
-constexpr bool kGenerateSingleArmMappingSymbol = true;
-
-static Reg GetDwarfCoreReg(InstructionSet isa, int machine_reg) {
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-      return Reg::ArmCore(machine_reg);
-    case kArm64:
-      return Reg::Arm64Core(machine_reg);
-    case kX86:
-      return Reg::X86Core(machine_reg);
-    case kX86_64:
-      return Reg::X86_64Core(machine_reg);
-    case kMips:
-      return Reg::MipsCore(machine_reg);
-    case kMips64:
-      return Reg::Mips64Core(machine_reg);
-    default:
-      LOG(FATAL) << "Unknown instruction set: " << isa;
-      UNREACHABLE();
-  }
-}
-
-static Reg GetDwarfFpReg(InstructionSet isa, int machine_reg) {
-  switch (isa) {
-    case kArm:
-    case kThumb2:
-      return Reg::ArmFp(machine_reg);
-    case kArm64:
-      return Reg::Arm64Fp(machine_reg);
-    case kX86:
-      return Reg::X86Fp(machine_reg);
-    case kX86_64:
-      return Reg::X86_64Fp(machine_reg);
-    case kMips:
-      return Reg::MipsFp(machine_reg);
-    case kMips64:
-      return Reg::Mips64Fp(machine_reg);
-    default:
-      LOG(FATAL) << "Unknown instruction set: " << isa;
-      UNREACHABLE();
-  }
-}
-
-static void WriteCIE(InstructionSet isa,
-                     CFIFormat format,
-                     std::vector<uint8_t>* buffer) {
-  // Scratch registers should be marked as undefined.  This tells the
-  // debugger that its value in the previous frame is not recoverable.
-  bool is64bit = Is64BitInstructionSet(isa);
-  switch (isa) {
-    case kArm:
-    case kThumb2: {
-      DebugFrameOpCodeWriter<> opcodes;
-      opcodes.DefCFA(Reg::ArmCore(13), 0);  // R13(SP).
-      // core registers.
-      for (int reg = 0; reg < 13; reg++) {
-        if (reg < 4 || reg == 12) {
-          opcodes.Undefined(Reg::ArmCore(reg));
-        } else {
-          opcodes.SameValue(Reg::ArmCore(reg));
-        }
-      }
-      // fp registers.
-      for (int reg = 0; reg < 32; reg++) {
-        if (reg < 16) {
-          opcodes.Undefined(Reg::ArmFp(reg));
-        } else {
-          opcodes.SameValue(Reg::ArmFp(reg));
-        }
-      }
-      auto return_reg = Reg::ArmCore(14);  // R14(LR).
-      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
-      return;
-    }
-    case kArm64: {
-      DebugFrameOpCodeWriter<> opcodes;
-      opcodes.DefCFA(Reg::Arm64Core(31), 0);  // R31(SP).
-      // core registers.
-      for (int reg = 0; reg < 30; reg++) {
-        if (reg < 8 || reg == 16 || reg == 17) {
-          opcodes.Undefined(Reg::Arm64Core(reg));
-        } else {
-          opcodes.SameValue(Reg::Arm64Core(reg));
-        }
-      }
-      // fp registers.
-      for (int reg = 0; reg < 32; reg++) {
-        if (reg < 8 || reg >= 16) {
-          opcodes.Undefined(Reg::Arm64Fp(reg));
-        } else {
-          opcodes.SameValue(Reg::Arm64Fp(reg));
-        }
-      }
-      auto return_reg = Reg::Arm64Core(30);  // R30(LR).
-      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
-      return;
-    }
-    case kMips:
-    case kMips64: {
-      DebugFrameOpCodeWriter<> opcodes;
-      opcodes.DefCFA(Reg::MipsCore(29), 0);  // R29(SP).
-      // core registers.
-      for (int reg = 1; reg < 26; reg++) {
-        if (reg < 16 || reg == 24 || reg == 25) {  // AT, V*, A*, T*.
-          opcodes.Undefined(Reg::MipsCore(reg));
-        } else {
-          opcodes.SameValue(Reg::MipsCore(reg));
-        }
-      }
-      // fp registers.
-      for (int reg = 0; reg < 32; reg++) {
-        if (reg < 24) {
-          opcodes.Undefined(Reg::Mips64Fp(reg));
-        } else {
-          opcodes.SameValue(Reg::Mips64Fp(reg));
-        }
-      }
-      auto return_reg = Reg::MipsCore(31);  // R31(RA).
-      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
-      return;
-    }
-    case kX86: {
-      // FIXME: Add fp registers once libunwind adds support for them. Bug: 20491296
-      constexpr bool generate_opcodes_for_x86_fp = false;
-      DebugFrameOpCodeWriter<> opcodes;
-      opcodes.DefCFA(Reg::X86Core(4), 4);   // R4(ESP).
-      opcodes.Offset(Reg::X86Core(8), -4);  // R8(EIP).
-      // core registers.
-      for (int reg = 0; reg < 8; reg++) {
-        if (reg <= 3) {
-          opcodes.Undefined(Reg::X86Core(reg));
-        } else if (reg == 4) {
-          // Stack pointer.
-        } else {
-          opcodes.SameValue(Reg::X86Core(reg));
-        }
-      }
-      // fp registers.
-      if (generate_opcodes_for_x86_fp) {
-        for (int reg = 0; reg < 8; reg++) {
-          opcodes.Undefined(Reg::X86Fp(reg));
-        }
-      }
-      auto return_reg = Reg::X86Core(8);  // R8(EIP).
-      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
-      return;
-    }
-    case kX86_64: {
-      DebugFrameOpCodeWriter<> opcodes;
-      opcodes.DefCFA(Reg::X86_64Core(4), 8);  // R4(RSP).
-      opcodes.Offset(Reg::X86_64Core(16), -8);  // R16(RIP).
-      // core registers.
-      for (int reg = 0; reg < 16; reg++) {
-        if (reg == 4) {
-          // Stack pointer.
-        } else if (reg < 12 && reg != 3 && reg != 5) {  // except EBX and EBP.
-          opcodes.Undefined(Reg::X86_64Core(reg));
-        } else {
-          opcodes.SameValue(Reg::X86_64Core(reg));
-        }
-      }
-      // fp registers.
-      for (int reg = 0; reg < 16; reg++) {
-        if (reg < 12) {
-          opcodes.Undefined(Reg::X86_64Fp(reg));
-        } else {
-          opcodes.SameValue(Reg::X86_64Fp(reg));
-        }
-      }
-      auto return_reg = Reg::X86_64Core(16);  // R16(RIP).
-      WriteCIE(is64bit, return_reg, opcodes, format, buffer);
-      return;
-    }
-    case kNone:
-      break;
-  }
-  LOG(FATAL) << "Cannot write CIE frame for ISA " << isa;
-  UNREACHABLE();
-}
-
-template<typename ElfTypes>
-void WriteCFISection(ElfBuilder<ElfTypes>* builder,
-                     const ArrayRef<const MethodDebugInfo>& method_infos,
-                     CFIFormat format,
-                     bool write_oat_patches) {
-  CHECK(format == DW_DEBUG_FRAME_FORMAT || format == DW_EH_FRAME_FORMAT);
-  typedef typename ElfTypes::Addr Elf_Addr;
-
-  if (method_infos.empty()) {
-    return;
-  }
-
-  std::vector<uint32_t> binary_search_table;
-  std::vector<uintptr_t> patch_locations;
-  if (format == DW_EH_FRAME_FORMAT) {
-    binary_search_table.reserve(2 * method_infos.size());
-  } else {
-    patch_locations.reserve(method_infos.size());
-  }
-
-  // The methods can be written any order.
-  // Let's therefore sort them in the lexicographical order of the opcodes.
-  // This has no effect on its own. However, if the final .debug_frame section is
-  // compressed it reduces the size since similar opcodes sequences are grouped.
-  std::vector<const MethodDebugInfo*> sorted_method_infos;
-  sorted_method_infos.reserve(method_infos.size());
-  for (size_t i = 0; i < method_infos.size(); i++) {
-    sorted_method_infos.push_back(&method_infos[i]);
-  }
-  std::sort(
-      sorted_method_infos.begin(),
-      sorted_method_infos.end(),
-      [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) {
-        ArrayRef<const uint8_t> l = lhs->compiled_method_->GetCFIInfo();
-        ArrayRef<const uint8_t> r = rhs->compiled_method_->GetCFIInfo();
-        return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
-      });
-
-  // Write .eh_frame/.debug_frame section.
-  auto* cfi_section = (format == DW_DEBUG_FRAME_FORMAT
-                       ? builder->GetDebugFrame()
-                       : builder->GetEhFrame());
-  {
-    cfi_section->Start();
-    const bool is64bit = Is64BitInstructionSet(builder->GetIsa());
-    const Elf_Addr text_address = builder->GetText()->Exists()
-        ? builder->GetText()->GetAddress()
-        : 0;
-    const Elf_Addr cfi_address = cfi_section->GetAddress();
-    const Elf_Addr cie_address = cfi_address;
-    Elf_Addr buffer_address = cfi_address;
-    std::vector<uint8_t> buffer;  // Small temporary buffer.
-    WriteCIE(builder->GetIsa(), format, &buffer);
-    cfi_section->WriteFully(buffer.data(), buffer.size());
-    buffer_address += buffer.size();
-    buffer.clear();
-    for (const MethodDebugInfo* mi : sorted_method_infos) {
-      if (!mi->deduped_) {  // Only one FDE per unique address.
-        ArrayRef<const uint8_t> opcodes = mi->compiled_method_->GetCFIInfo();
-        if (!opcodes.empty()) {
-          const Elf_Addr code_address = text_address + mi->low_pc_;
-          if (format == DW_EH_FRAME_FORMAT) {
-            binary_search_table.push_back(
-                dchecked_integral_cast<uint32_t>(code_address));
-            binary_search_table.push_back(
-                dchecked_integral_cast<uint32_t>(buffer_address));
-          }
-          WriteFDE(is64bit, cfi_address, cie_address,
-                   code_address, mi->high_pc_ - mi->low_pc_,
-                   opcodes, format, buffer_address, &buffer,
-                   &patch_locations);
-          cfi_section->WriteFully(buffer.data(), buffer.size());
-          buffer_address += buffer.size();
-          buffer.clear();
-        }
-      }
-    }
-    cfi_section->End();
-  }
-
-  if (format == DW_EH_FRAME_FORMAT) {
-    auto* header_section = builder->GetEhFrameHdr();
-    header_section->Start();
-    uint32_t header_address = dchecked_integral_cast<int32_t>(header_section->GetAddress());
-    // Write .eh_frame_hdr section.
-    std::vector<uint8_t> buffer;
-    Writer<> header(&buffer);
-    header.PushUint8(1);  // Version.
-    // Encoding of .eh_frame pointer - libunwind does not honor datarel here,
-    // so we have to use pcrel which means relative to the pointer's location.
-    header.PushUint8(DW_EH_PE_pcrel | DW_EH_PE_sdata4);
-    // Encoding of binary search table size.
-    header.PushUint8(DW_EH_PE_udata4);
-    // Encoding of binary search table addresses - libunwind supports only this
-    // specific combination, which means relative to the start of .eh_frame_hdr.
-    header.PushUint8(DW_EH_PE_datarel | DW_EH_PE_sdata4);
-    // .eh_frame pointer
-    header.PushInt32(cfi_section->GetAddress() - (header_address + 4u));
-    // Binary search table size (number of entries).
-    header.PushUint32(dchecked_integral_cast<uint32_t>(binary_search_table.size()/2));
-    header_section->WriteFully(buffer.data(), buffer.size());
-    // Binary search table.
-    for (size_t i = 0; i < binary_search_table.size(); i++) {
-      // Make addresses section-relative since we know the header address now.
-      binary_search_table[i] -= header_address;
-    }
-    header_section->WriteFully(binary_search_table.data(), binary_search_table.size());
-    header_section->End();
-  } else {
-    if (write_oat_patches) {
-      builder->WritePatches(".debug_frame.oat_patches",
-                            ArrayRef<const uintptr_t>(patch_locations));
-    }
-  }
-}
-
-namespace {
-  struct CompilationUnit {
-    std::vector<const MethodDebugInfo*> methods_;
-    size_t debug_line_offset_ = 0;
-    uintptr_t low_pc_ = std::numeric_limits<uintptr_t>::max();
-    uintptr_t high_pc_ = 0;
-  };
-
-  typedef std::vector<DexFile::LocalInfo> LocalInfos;
-
-  void LocalInfoCallback(void* ctx, const DexFile::LocalInfo& entry) {
-    static_cast<LocalInfos*>(ctx)->push_back(entry);
-  }
-
-  typedef std::vector<DexFile::PositionInfo> PositionInfos;
-
-  bool PositionInfoCallback(void* ctx, const DexFile::PositionInfo& entry) {
-    static_cast<PositionInfos*>(ctx)->push_back(entry);
-    return false;
-  }
-
-  std::vector<const char*> GetParamNames(const MethodDebugInfo* mi) {
-    std::vector<const char*> names;
-    if (mi->code_item_ != nullptr) {
-      const uint8_t* stream = mi->dex_file_->GetDebugInfoStream(mi->code_item_);
-      if (stream != nullptr) {
-        DecodeUnsignedLeb128(&stream);  // line.
-        uint32_t parameters_size = DecodeUnsignedLeb128(&stream);
-        for (uint32_t i = 0; i < parameters_size; ++i) {
-          uint32_t id = DecodeUnsignedLeb128P1(&stream);
-          names.push_back(mi->dex_file_->StringDataByIdx(id));
-        }
-      }
-    }
-    return names;
-  }
-
-  struct VariableLocation {
-    uint32_t low_pc;
-    uint32_t high_pc;
-    DexRegisterLocation reg_lo;  // May be None if the location is unknown.
-    DexRegisterLocation reg_hi;  // Most significant bits of 64-bit value.
-  };
-
-  // Get the location of given dex register (e.g. stack or machine register).
-  // Note that the location might be different based on the current pc.
-  // The result will cover all ranges where the variable is in scope.
-  std::vector<VariableLocation> GetVariableLocations(const MethodDebugInfo* method_info,
-                                                     uint16_t vreg,
-                                                     bool is64bitValue,
-                                                     uint32_t dex_pc_low,
-                                                     uint32_t dex_pc_high) {
-    std::vector<VariableLocation> variable_locations;
-
-    // Get stack maps sorted by pc (they might not be sorted internally).
-    const CodeInfo code_info(method_info->compiled_method_->GetVmapTable().data());
-    const StackMapEncoding encoding = code_info.ExtractEncoding();
-    std::map<uint32_t, StackMap> stack_maps;
-    for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
-      StackMap stack_map = code_info.GetStackMapAt(s, encoding);
-      DCHECK(stack_map.IsValid());
-      const uint32_t low_pc = method_info->low_pc_ + stack_map.GetNativePcOffset(encoding);
-      DCHECK_LE(low_pc, method_info->high_pc_);
-      stack_maps.emplace(low_pc, stack_map);
-    }
-
-    // Create entries for the requested register based on stack map data.
-    for (auto it = stack_maps.begin(); it != stack_maps.end(); it++) {
-      const StackMap& stack_map = it->second;
-      const uint32_t low_pc = it->first;
-      auto next_it = it;
-      next_it++;
-      const uint32_t high_pc = next_it != stack_maps.end() ? next_it->first
-                                                           : method_info->high_pc_;
-      DCHECK_LE(low_pc, high_pc);
-      if (low_pc == high_pc) {
-        continue;  // Ignore if the address range is empty.
-      }
-
-      // Check that the stack map is in the requested range.
-      uint32_t dex_pc = stack_map.GetDexPc(encoding);
-      if (!(dex_pc_low <= dex_pc && dex_pc < dex_pc_high)) {
-        continue;
-      }
-
-      // Find the location of the dex register.
-      DexRegisterLocation reg_lo = DexRegisterLocation::None();
-      DexRegisterLocation reg_hi = DexRegisterLocation::None();
-      if (stack_map.HasDexRegisterMap(encoding)) {
-        DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(
-            stack_map, encoding, method_info->code_item_->registers_size_);
-        reg_lo = dex_register_map.GetDexRegisterLocation(
-            vreg, method_info->code_item_->registers_size_, code_info, encoding);
-        if (is64bitValue) {
-          reg_hi = dex_register_map.GetDexRegisterLocation(
-              vreg + 1, method_info->code_item_->registers_size_, code_info, encoding);
-        }
-      }
-
-      // Add location entry for this address range.
-      if (!variable_locations.empty() &&
-          variable_locations.back().reg_lo == reg_lo &&
-          variable_locations.back().reg_hi == reg_hi &&
-          variable_locations.back().high_pc == low_pc) {
-        // Merge with the previous entry (extend its range).
-        variable_locations.back().high_pc = high_pc;
-      } else {
-        variable_locations.push_back({low_pc, high_pc, reg_lo, reg_hi});
-      }
-    }
-
-    return variable_locations;
-  }
-
-  bool IsFromOptimizingCompiler(const MethodDebugInfo* method_info) {
-    return method_info->compiled_method_->GetQuickCode().size() > 0 &&
-           method_info->compiled_method_->GetVmapTable().size() > 0 &&
-           method_info->compiled_method_->GetGcMap().size() == 0 &&
-           method_info->code_item_ != nullptr;
-  }
-}  // namespace
-
-// Helper class to write .debug_info and its supporting sections.
-template<typename ElfTypes>
-class DebugInfoWriter {
-  typedef typename ElfTypes::Addr Elf_Addr;
-
-  // Helper class to write one compilation unit.
-  // It holds helper methods and temporary state.
-  class CompilationUnitWriter {
-   public:
-    explicit CompilationUnitWriter(DebugInfoWriter* owner)
-      : owner_(owner),
-        info_(Is64BitInstructionSet(owner_->builder_->GetIsa()), &owner->debug_abbrev_) {
-    }
-
-    void Write(const CompilationUnit& compilation_unit) {
-      CHECK(!compilation_unit.methods_.empty());
-      const Elf_Addr text_address = owner_->builder_->GetText()->Exists()
-          ? owner_->builder_->GetText()->GetAddress()
-          : 0;
-      const uintptr_t cu_size = compilation_unit.high_pc_ - compilation_unit.low_pc_;
-
-      info_.StartTag(DW_TAG_compile_unit);
-      info_.WriteString(DW_AT_producer, "Android dex2oat");
-      info_.WriteData1(DW_AT_language, DW_LANG_Java);
-      info_.WriteString(DW_AT_comp_dir, "$JAVA_SRC_ROOT");
-      info_.WriteAddr(DW_AT_low_pc, text_address + compilation_unit.low_pc_);
-      info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(cu_size));
-      info_.WriteSecOffset(DW_AT_stmt_list, compilation_unit.debug_line_offset_);
-
-      const char* last_dex_class_desc = nullptr;
-      for (auto mi : compilation_unit.methods_) {
-        const DexFile* dex = mi->dex_file_;
-        const DexFile::CodeItem* dex_code = mi->code_item_;
-        const DexFile::MethodId& dex_method = dex->GetMethodId(mi->dex_method_index_);
-        const DexFile::ProtoId& dex_proto = dex->GetMethodPrototype(dex_method);
-        const DexFile::TypeList* dex_params = dex->GetProtoParameters(dex_proto);
-        const char* dex_class_desc = dex->GetMethodDeclaringClassDescriptor(dex_method);
-        const bool is_static = (mi->access_flags_ & kAccStatic) != 0;
-
-        // Enclose the method in correct class definition.
-        if (last_dex_class_desc != dex_class_desc) {
-          if (last_dex_class_desc != nullptr) {
-            EndClassTag();
-          }
-          // Write reference tag for the class we are about to declare.
-          size_t reference_tag_offset = info_.StartTag(DW_TAG_reference_type);
-          type_cache_.emplace(std::string(dex_class_desc), reference_tag_offset);
-          size_t type_attrib_offset = info_.size();
-          info_.WriteRef4(DW_AT_type, 0);
-          info_.EndTag();
-          // Declare the class that owns this method.
-          size_t class_offset = StartClassTag(dex_class_desc);
-          info_.UpdateUint32(type_attrib_offset, class_offset);
-          info_.WriteFlagPresent(DW_AT_declaration);
-          // Check that each class is defined only once.
-          bool unique = owner_->defined_dex_classes_.insert(dex_class_desc).second;
-          CHECK(unique) << "Redefinition of " << dex_class_desc;
-          last_dex_class_desc = dex_class_desc;
-        }
-
-        int start_depth = info_.Depth();
-        info_.StartTag(DW_TAG_subprogram);
-        WriteName(dex->GetMethodName(dex_method));
-        info_.WriteAddr(DW_AT_low_pc, text_address + mi->low_pc_);
-        info_.WriteUdata(DW_AT_high_pc, dchecked_integral_cast<uint32_t>(mi->high_pc_-mi->low_pc_));
-        std::vector<uint8_t> expr_buffer;
-        Expression expr(&expr_buffer);
-        expr.WriteOpCallFrameCfa();
-        info_.WriteExprLoc(DW_AT_frame_base, expr);
-        WriteLazyType(dex->GetReturnTypeDescriptor(dex_proto));
-
-        // Write parameters. DecodeDebugLocalInfo returns them as well, but it does not
-        // guarantee order or uniqueness so it is safer to iterate over them manually.
-        // DecodeDebugLocalInfo might not also be available if there is no debug info.
-        std::vector<const char*> param_names = GetParamNames(mi);
-        uint32_t arg_reg = 0;
-        if (!is_static) {
-          info_.StartTag(DW_TAG_formal_parameter);
-          WriteName("this");
-          info_.WriteFlagPresent(DW_AT_artificial);
-          WriteLazyType(dex_class_desc);
-          if (dex_code != nullptr) {
-            // Write the stack location of the parameter.
-            const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
-            const bool is64bitValue = false;
-            WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_);
-          }
-          arg_reg++;
-          info_.EndTag();
-        }
-        if (dex_params != nullptr) {
-          for (uint32_t i = 0; i < dex_params->Size(); ++i) {
-            info_.StartTag(DW_TAG_formal_parameter);
-            // Parameter names may not be always available.
-            if (i < param_names.size()) {
-              WriteName(param_names[i]);
-            }
-            // Write the type.
-            const char* type_desc = dex->StringByTypeIdx(dex_params->GetTypeItem(i).type_idx_);
-            WriteLazyType(type_desc);
-            const bool is64bitValue = type_desc[0] == 'D' || type_desc[0] == 'J';
-            if (dex_code != nullptr) {
-              // Write the stack location of the parameter.
-              const uint32_t vreg = dex_code->registers_size_ - dex_code->ins_size_ + arg_reg;
-              WriteRegLocation(mi, vreg, is64bitValue, compilation_unit.low_pc_);
-            }
-            arg_reg += is64bitValue ? 2 : 1;
-            info_.EndTag();
-          }
-          if (dex_code != nullptr) {
-            DCHECK_EQ(arg_reg, dex_code->ins_size_);
-          }
-        }
-
-        // Write local variables.
-        LocalInfos local_infos;
-        if (dex->DecodeDebugLocalInfo(dex_code,
-                                      is_static,
-                                      mi->dex_method_index_,
-                                      LocalInfoCallback,
-                                      &local_infos)) {
-          for (const DexFile::LocalInfo& var : local_infos) {
-            if (var.reg_ < dex_code->registers_size_ - dex_code->ins_size_) {
-              info_.StartTag(DW_TAG_variable);
-              WriteName(var.name_);
-              WriteLazyType(var.descriptor_);
-              bool is64bitValue = var.descriptor_[0] == 'D' || var.descriptor_[0] == 'J';
-              WriteRegLocation(mi, var.reg_, is64bitValue, compilation_unit.low_pc_,
-                               var.start_address_, var.end_address_);
-              info_.EndTag();
-            }
-          }
-        }
-
-        info_.EndTag();
-        CHECK_EQ(info_.Depth(), start_depth);  // Balanced start/end.
-      }
-      if (last_dex_class_desc != nullptr) {
-        EndClassTag();
-      }
-      FinishLazyTypes();
-      CloseNamespacesAboveDepth(0);
-      info_.EndTag();  // DW_TAG_compile_unit
-      CHECK_EQ(info_.Depth(), 0);
-      std::vector<uint8_t> buffer;
-      buffer.reserve(info_.data()->size() + KB);
-      const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
-      // All compilation units share single table which is at the start of .debug_abbrev.
-      const size_t debug_abbrev_offset = 0;
-      WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
-      owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
-    }
-
-    void Write(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) {
-      info_.StartTag(DW_TAG_compile_unit);
-      info_.WriteString(DW_AT_producer, "Android dex2oat");
-      info_.WriteData1(DW_AT_language, DW_LANG_Java);
-
-      // Base class references to be patched at the end.
-      std::map<size_t, mirror::Class*> base_class_references;
-
-      // Already written declarations or definitions.
-      std::map<mirror::Class*, size_t> class_declarations;
-
-      std::vector<uint8_t> expr_buffer;
-      for (mirror::Class* type : types) {
-        if (type->IsPrimitive()) {
-          // For primitive types the definition and the declaration is the same.
-          if (type->GetPrimitiveType() != Primitive::kPrimVoid) {
-            WriteTypeDeclaration(type->GetDescriptor(nullptr));
-          }
-        } else if (type->IsArrayClass()) {
-          mirror::Class* element_type = type->GetComponentType();
-          uint32_t component_size = type->GetComponentSize();
-          uint32_t data_offset = mirror::Array::DataOffset(component_size).Uint32Value();
-          uint32_t length_offset = mirror::Array::LengthOffset().Uint32Value();
-
-          CloseNamespacesAboveDepth(0);  // Declare in root namespace.
-          info_.StartTag(DW_TAG_array_type);
-          std::string descriptor_string;
-          WriteLazyType(element_type->GetDescriptor(&descriptor_string));
-          WriteLinkageName(type);
-          info_.WriteUdata(DW_AT_data_member_location, data_offset);
-          info_.StartTag(DW_TAG_subrange_type);
-          Expression count_expr(&expr_buffer);
-          count_expr.WriteOpPushObjectAddress();
-          count_expr.WriteOpPlusUconst(length_offset);
-          count_expr.WriteOpDerefSize(4);  // Array length is always 32-bit wide.
-          info_.WriteExprLoc(DW_AT_count, count_expr);
-          info_.EndTag();  // DW_TAG_subrange_type.
-          info_.EndTag();  // DW_TAG_array_type.
-        } else if (type->IsInterface()) {
-          // Skip.  Variables cannot have an interface as a dynamic type.
-          // We do not expose the interface information to the debugger in any way.
-        } else {
-          std::string descriptor_string;
-          const char* desc = type->GetDescriptor(&descriptor_string);
-          size_t class_offset = StartClassTag(desc);
-          class_declarations.emplace(type, class_offset);
-
-          if (!type->IsVariableSize()) {
-            info_.WriteUdata(DW_AT_byte_size, type->GetObjectSize());
-          }
-
-          WriteLinkageName(type);
-
-          if (type->IsObjectClass()) {
-            // Generate artificial member which is used to get the dynamic type of variable.
-            // The run-time value of this field will correspond to linkage name of some type.
-            // We need to do it only once in j.l.Object since all other types inherit it.
-            info_.StartTag(DW_TAG_member);
-            WriteName(".dynamic_type");
-            WriteLazyType(sizeof(uintptr_t) == 8 ? "J" : "I");
-            info_.WriteFlagPresent(DW_AT_artificial);
-            // Create DWARF expression to get the value of the methods_ field.
-            Expression expr(&expr_buffer);
-            // The address of the object has been implicitly pushed on the stack.
-            // Dereference the klass_ field of Object (32-bit; possibly poisoned).
-            DCHECK_EQ(type->ClassOffset().Uint32Value(), 0u);
-            DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Class>), 4u);
-            expr.WriteOpDerefSize(4);
-            if (kPoisonHeapReferences) {
-              expr.WriteOpNeg();
-              // DWARF stack is pointer sized. Ensure that the high bits are clear.
-              expr.WriteOpConstu(0xFFFFFFFF);
-              expr.WriteOpAnd();
-            }
-            // Add offset to the methods_ field.
-            expr.WriteOpPlusUconst(mirror::Class::MethodsOffset().Uint32Value());
-            // Top of stack holds the location of the field now.
-            info_.WriteExprLoc(DW_AT_data_member_location, expr);
-            info_.EndTag();  // DW_TAG_member.
-          }
-
-          // Base class.
-          mirror::Class* base_class = type->GetSuperClass();
-          if (base_class != nullptr) {
-            info_.StartTag(DW_TAG_inheritance);
-            base_class_references.emplace(info_.size(), base_class);
-            info_.WriteRef4(DW_AT_type, 0);
-            info_.WriteUdata(DW_AT_data_member_location, 0);
-            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
-            info_.EndTag();  // DW_TAG_inheritance.
-          }
-
-          // Member variables.
-          for (uint32_t i = 0, count = type->NumInstanceFields(); i < count; ++i) {
-            ArtField* field = type->GetInstanceField(i);
-            info_.StartTag(DW_TAG_member);
-            WriteName(field->GetName());
-            WriteLazyType(field->GetTypeDescriptor());
-            info_.WriteUdata(DW_AT_data_member_location, field->GetOffset().Uint32Value());
-            uint32_t access_flags = field->GetAccessFlags();
-            if (access_flags & kAccPublic) {
-              info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_public);
-            } else if (access_flags & kAccProtected) {
-              info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_protected);
-            } else if (access_flags & kAccPrivate) {
-              info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
-            }
-            info_.EndTag();  // DW_TAG_member.
-          }
-
-          if (type->IsStringClass()) {
-            // Emit debug info about an artifical class member for java.lang.String which represents
-            // the first element of the data stored in a string instance. Consumers of the debug
-            // info will be able to read the content of java.lang.String based on the count (real
-            // field) and based on the location of this data member.
-            info_.StartTag(DW_TAG_member);
-            WriteName("value");
-            // We don't support fields with C like array types so we just say its type is java char.
-            WriteLazyType("C");  // char.
-            info_.WriteUdata(DW_AT_data_member_location,
-                             mirror::String::ValueOffset().Uint32Value());
-            info_.WriteSdata(DW_AT_accessibility, DW_ACCESS_private);
-            info_.EndTag();  // DW_TAG_member.
-          }
-
-          EndClassTag();
-        }
-      }
-
-      // Write base class declarations.
-      for (const auto& base_class_reference : base_class_references) {
-        size_t reference_offset = base_class_reference.first;
-        mirror::Class* base_class = base_class_reference.second;
-        const auto& it = class_declarations.find(base_class);
-        if (it != class_declarations.end()) {
-          info_.UpdateUint32(reference_offset, it->second);
-        } else {
-          // Declare base class.  We can not use the standard WriteLazyType
-          // since we want to avoid the DW_TAG_reference_tag wrapping.
-          std::string tmp_storage;
-          const char* base_class_desc = base_class->GetDescriptor(&tmp_storage);
-          size_t base_class_declaration_offset = StartClassTag(base_class_desc);
-          info_.WriteFlagPresent(DW_AT_declaration);
-          WriteLinkageName(base_class);
-          EndClassTag();
-          class_declarations.emplace(base_class, base_class_declaration_offset);
-          info_.UpdateUint32(reference_offset, base_class_declaration_offset);
-        }
-      }
-
-      FinishLazyTypes();
-      CloseNamespacesAboveDepth(0);
-      info_.EndTag();  // DW_TAG_compile_unit.
-      CHECK_EQ(info_.Depth(), 0);
-      std::vector<uint8_t> buffer;
-      buffer.reserve(info_.data()->size() + KB);
-      const size_t offset = owner_->builder_->GetDebugInfo()->GetSize();
-      // All compilation units share single table which is at the start of .debug_abbrev.
-      const size_t debug_abbrev_offset = 0;
-      WriteDebugInfoCU(debug_abbrev_offset, info_, offset, &buffer, &owner_->debug_info_patches_);
-      owner_->builder_->GetDebugInfo()->WriteFully(buffer.data(), buffer.size());
-    }
-
-    // Linkage name uniquely identifies type.
-    // It is used to determine the dynamic type of objects.
-    // We use the methods_ field of class since it is unique and it is not moved by the GC.
-    void WriteLinkageName(mirror::Class* type) SHARED_REQUIRES(Locks::mutator_lock_) {
-      auto* methods_ptr = type->GetMethodsPtr();
-      if (methods_ptr == nullptr) {
-        // Some types might have no methods.  Allocate empty array instead.
-        LinearAlloc* allocator = Runtime::Current()->GetLinearAlloc();
-        void* storage = allocator->Alloc(Thread::Current(), sizeof(LengthPrefixedArray<ArtMethod>));
-        methods_ptr = new (storage) LengthPrefixedArray<ArtMethod>(0);
-        type->SetMethodsPtr(methods_ptr, 0, 0);
-        DCHECK(type->GetMethodsPtr() != nullptr);
-      }
-      char name[32];
-      snprintf(name, sizeof(name), "0x%" PRIXPTR, reinterpret_cast<uintptr_t>(methods_ptr));
-      info_.WriteString(DW_AT_linkage_name, name);
-    }
-
-    // Write table into .debug_loc which describes location of dex register.
-    // The dex register might be valid only at some points and it might
-    // move between machine registers and stack.
-    void WriteRegLocation(const MethodDebugInfo* method_info,
-                          uint16_t vreg,
-                          bool is64bitValue,
-                          uint32_t compilation_unit_low_pc,
-                          uint32_t dex_pc_low = 0,
-                          uint32_t dex_pc_high = 0xFFFFFFFF) {
-      using Kind = DexRegisterLocation::Kind;
-      if (!IsFromOptimizingCompiler(method_info)) {
-        return;
-      }
-
-      Writer<> debug_loc(&owner_->debug_loc_);
-      Writer<> debug_ranges(&owner_->debug_ranges_);
-      info_.WriteSecOffset(DW_AT_location, debug_loc.size());
-      info_.WriteSecOffset(DW_AT_start_scope, debug_ranges.size());
-
-      std::vector<VariableLocation> variable_locations = GetVariableLocations(
-          method_info,
-          vreg,
-          is64bitValue,
-          dex_pc_low,
-          dex_pc_high);
-
-      // Write .debug_loc entries.
-      const InstructionSet isa = owner_->builder_->GetIsa();
-      const bool is64bit = Is64BitInstructionSet(isa);
-      std::vector<uint8_t> expr_buffer;
-      for (const VariableLocation& variable_location : variable_locations) {
-        // Translate dex register location to DWARF expression.
-        // Note that 64-bit value might be split to two distinct locations.
-        // (for example, two 32-bit machine registers, or even stack and register)
-        Expression expr(&expr_buffer);
-        DexRegisterLocation reg_lo = variable_location.reg_lo;
-        DexRegisterLocation reg_hi = variable_location.reg_hi;
-        for (int piece = 0; piece < (is64bitValue ? 2 : 1); piece++) {
-          DexRegisterLocation reg_loc = (piece == 0 ? reg_lo : reg_hi);
-          const Kind kind = reg_loc.GetKind();
-          const int32_t value = reg_loc.GetValue();
-          if (kind == Kind::kInStack) {
-            const size_t frame_size = method_info->compiled_method_->GetFrameSizeInBytes();
-            // The stack offset is relative to SP. Make it relative to CFA.
-            expr.WriteOpFbreg(value - frame_size);
-            if (piece == 0 && reg_hi.GetKind() == Kind::kInStack &&
-                reg_hi.GetValue() == value + 4) {
-              break;  // the high word is correctly implied by the low word.
-            }
-          } else if (kind == Kind::kInRegister) {
-            expr.WriteOpReg(GetDwarfCoreReg(isa, value).num());
-            if (piece == 0 && reg_hi.GetKind() == Kind::kInRegisterHigh &&
-                reg_hi.GetValue() == value) {
-              break;  // the high word is correctly implied by the low word.
-            }
-          } else if (kind == Kind::kInFpuRegister) {
-            if ((isa == kArm || isa == kThumb2) &&
-                piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegister &&
-                reg_hi.GetValue() == value + 1 && value % 2 == 0) {
-              // Translate S register pair to D register (e.g. S4+S5 to D2).
-              expr.WriteOpReg(Reg::ArmDp(value / 2).num());
-              break;
-            }
-            expr.WriteOpReg(GetDwarfFpReg(isa, value).num());
-            if (piece == 0 && reg_hi.GetKind() == Kind::kInFpuRegisterHigh &&
-                reg_hi.GetValue() == reg_lo.GetValue()) {
-              break;  // the high word is correctly implied by the low word.
-            }
-          } else if (kind == Kind::kConstant) {
-            expr.WriteOpConsts(value);
-            expr.WriteOpStackValue();
-          } else if (kind == Kind::kNone) {
-            break;
-          } else {
-            // kInStackLargeOffset and kConstantLargeValue are hidden by GetKind().
-            // kInRegisterHigh and kInFpuRegisterHigh should be handled by
-            // the special cases above and they should not occur alone.
-            LOG(ERROR) << "Unexpected register location kind: "
-                       << DexRegisterLocation::PrettyDescriptor(kind);
-            break;
-          }
-          if (is64bitValue) {
-            // Write the marker which is needed by split 64-bit values.
-            // This code is skipped by the special cases.
-            expr.WriteOpPiece(4);
-          }
-        }
-
-        if (expr.size() > 0) {
-          if (is64bit) {
-            debug_loc.PushUint64(variable_location.low_pc - compilation_unit_low_pc);
-            debug_loc.PushUint64(variable_location.high_pc - compilation_unit_low_pc);
-          } else {
-            debug_loc.PushUint32(variable_location.low_pc - compilation_unit_low_pc);
-            debug_loc.PushUint32(variable_location.high_pc - compilation_unit_low_pc);
-          }
-          // Write the expression.
-          debug_loc.PushUint16(expr.size());
-          debug_loc.PushData(expr.data());
-        } else {
-          // Do not generate .debug_loc if the location is not known.
-        }
-      }
-      // Write end-of-list entry.
-      if (is64bit) {
-        debug_loc.PushUint64(0);
-        debug_loc.PushUint64(0);
-      } else {
-        debug_loc.PushUint32(0);
-        debug_loc.PushUint32(0);
-      }
-
-      // Write .debug_ranges entries.
-      // This includes ranges where the variable is in scope but the location is not known.
-      for (size_t i = 0; i < variable_locations.size(); i++) {
-        uint32_t low_pc = variable_locations[i].low_pc;
-        uint32_t high_pc = variable_locations[i].high_pc;
-        while (i + 1 < variable_locations.size() && variable_locations[i+1].low_pc == high_pc) {
-          // Merge address range with the next entry.
-          high_pc = variable_locations[++i].high_pc;
-        }
-        if (is64bit) {
-          debug_ranges.PushUint64(low_pc - compilation_unit_low_pc);
-          debug_ranges.PushUint64(high_pc - compilation_unit_low_pc);
-        } else {
-          debug_ranges.PushUint32(low_pc - compilation_unit_low_pc);
-          debug_ranges.PushUint32(high_pc - compilation_unit_low_pc);
-        }
-      }
-      // Write end-of-list entry.
-      if (is64bit) {
-        debug_ranges.PushUint64(0);
-        debug_ranges.PushUint64(0);
-      } else {
-        debug_ranges.PushUint32(0);
-        debug_ranges.PushUint32(0);
-      }
-    }
-
-    // Some types are difficult to define as we go since they need
-    // to be enclosed in the right set of namespaces. Therefore we
-    // just define all types lazily at the end of compilation unit.
-    void WriteLazyType(const char* type_descriptor) {
-      if (type_descriptor != nullptr && type_descriptor[0] != 'V') {
-        lazy_types_.emplace(std::string(type_descriptor), info_.size());
-        info_.WriteRef4(DW_AT_type, 0);
-      }
-    }
-
-    void FinishLazyTypes() {
-      for (const auto& lazy_type : lazy_types_) {
-        info_.UpdateUint32(lazy_type.second, WriteTypeDeclaration(lazy_type.first));
-      }
-      lazy_types_.clear();
-    }
-
-   private:
-    void WriteName(const char* name) {
-      if (name != nullptr) {
-        info_.WriteString(DW_AT_name, name);
-      }
-    }
-
-    // Convert dex type descriptor to DWARF.
-    // Returns offset in the compilation unit.
-    size_t WriteTypeDeclaration(const std::string& desc) {
-      DCHECK(!desc.empty());
-      const auto& it = type_cache_.find(desc);
-      if (it != type_cache_.end()) {
-        return it->second;
-      }
-
-      size_t offset;
-      if (desc[0] == 'L') {
-        // Class type. For example: Lpackage/name;
-        size_t class_offset = StartClassTag(desc.c_str());
-        info_.WriteFlagPresent(DW_AT_declaration);
-        EndClassTag();
-        // Reference to the class type.
-        offset = info_.StartTag(DW_TAG_reference_type);
-        info_.WriteRef(DW_AT_type, class_offset);
-        info_.EndTag();
-      } else if (desc[0] == '[') {
-        // Array type.
-        size_t element_type = WriteTypeDeclaration(desc.substr(1));
-        CloseNamespacesAboveDepth(0);  // Declare in root namespace.
-        size_t array_type = info_.StartTag(DW_TAG_array_type);
-        info_.WriteFlagPresent(DW_AT_declaration);
-        info_.WriteRef(DW_AT_type, element_type);
-        info_.EndTag();
-        offset = info_.StartTag(DW_TAG_reference_type);
-        info_.WriteRef4(DW_AT_type, array_type);
-        info_.EndTag();
-      } else {
-        // Primitive types.
-        DCHECK_EQ(desc.size(), 1u);
-
-        const char* name;
-        uint32_t encoding;
-        uint32_t byte_size;
-        switch (desc[0]) {
-        case 'B':
-          name = "byte";
-          encoding = DW_ATE_signed;
-          byte_size = 1;
-          break;
-        case 'C':
-          name = "char";
-          encoding = DW_ATE_UTF;
-          byte_size = 2;
-          break;
-        case 'D':
-          name = "double";
-          encoding = DW_ATE_float;
-          byte_size = 8;
-          break;
-        case 'F':
-          name = "float";
-          encoding = DW_ATE_float;
-          byte_size = 4;
-          break;
-        case 'I':
-          name = "int";
-          encoding = DW_ATE_signed;
-          byte_size = 4;
-          break;
-        case 'J':
-          name = "long";
-          encoding = DW_ATE_signed;
-          byte_size = 8;
-          break;
-        case 'S':
-          name = "short";
-          encoding = DW_ATE_signed;
-          byte_size = 2;
-          break;
-        case 'Z':
-          name = "boolean";
-          encoding = DW_ATE_boolean;
-          byte_size = 1;
-          break;
-        case 'V':
-          LOG(FATAL) << "Void type should not be encoded";
-          UNREACHABLE();
-        default:
-          LOG(FATAL) << "Unknown dex type descriptor: \"" << desc << "\"";
-          UNREACHABLE();
-        }
-        CloseNamespacesAboveDepth(0);  // Declare in root namespace.
-        offset = info_.StartTag(DW_TAG_base_type);
-        WriteName(name);
-        info_.WriteData1(DW_AT_encoding, encoding);
-        info_.WriteData1(DW_AT_byte_size, byte_size);
-        info_.EndTag();
-      }
-
-      type_cache_.emplace(desc, offset);
-      return offset;
-    }
-
-    // Start DW_TAG_class_type tag nested in DW_TAG_namespace tags.
-    // Returns offset of the class tag in the compilation unit.
-    size_t StartClassTag(const char* desc) {
-      std::string name = SetNamespaceForClass(desc);
-      size_t offset = info_.StartTag(DW_TAG_class_type);
-      WriteName(name.c_str());
-      return offset;
-    }
-
-    void EndClassTag() {
-      info_.EndTag();
-    }
-
-    // Set the current namespace nesting to one required by the given class.
-    // Returns the class name with namespaces, 'L', and ';' stripped.
-    std::string SetNamespaceForClass(const char* desc) {
-      DCHECK(desc != nullptr && desc[0] == 'L');
-      desc++;  // Skip the initial 'L'.
-      size_t depth = 0;
-      for (const char* end; (end = strchr(desc, '/')) != nullptr; desc = end + 1, ++depth) {
-        // Check whether the name at this depth is already what we need.
-        if (depth < current_namespace_.size()) {
-          const std::string& name = current_namespace_[depth];
-          if (name.compare(0, name.size(), desc, end - desc) == 0) {
-            continue;
-          }
-        }
-        // Otherwise we need to open a new namespace tag at this depth.
-        CloseNamespacesAboveDepth(depth);
-        info_.StartTag(DW_TAG_namespace);
-        std::string name(desc, end - desc);
-        WriteName(name.c_str());
-        current_namespace_.push_back(std::move(name));
-      }
-      CloseNamespacesAboveDepth(depth);
-      return std::string(desc, strchr(desc, ';') - desc);
-    }
-
-    // Close namespace tags to reach the given nesting depth.
-    void CloseNamespacesAboveDepth(size_t depth) {
-      DCHECK_LE(depth, current_namespace_.size());
-      while (current_namespace_.size() > depth) {
-        info_.EndTag();
-        current_namespace_.pop_back();
-      }
-    }
-
-    // For access to the ELF sections.
-    DebugInfoWriter<ElfTypes>* owner_;
-    // Temporary buffer to create and store the entries.
-    DebugInfoEntryWriter<> info_;
-    // Cache of already translated type descriptors.
-    std::map<std::string, size_t> type_cache_;  // type_desc -> definition_offset.
-    // 32-bit references which need to be resolved to a type later.
-    // Given type may be used multiple times.  Therefore we need a multimap.
-    std::multimap<std::string, size_t> lazy_types_;  // type_desc -> patch_offset.
-    // The current set of open namespace tags which are active and not closed yet.
-    std::vector<std::string> current_namespace_;
-  };
-
- public:
-  explicit DebugInfoWriter(ElfBuilder<ElfTypes>* builder)
-      : builder_(builder),
-        debug_abbrev_(&debug_abbrev_buffer_) {
-  }
-
-  void Start() {
-    builder_->GetDebugInfo()->Start();
-  }
-
-  void WriteCompilationUnit(const CompilationUnit& compilation_unit) {
-    CompilationUnitWriter writer(this);
-    writer.Write(compilation_unit);
-  }
-
-  void WriteTypes(const ArrayRef<mirror::Class*>& types) SHARED_REQUIRES(Locks::mutator_lock_) {
-    CompilationUnitWriter writer(this);
-    writer.Write(types);
-  }
-
-  void End() {
-    builder_->GetDebugInfo()->End();
-    builder_->WritePatches(".debug_info.oat_patches",
-                           ArrayRef<const uintptr_t>(debug_info_patches_));
-    builder_->WriteSection(".debug_abbrev", &debug_abbrev_buffer_);
-    builder_->WriteSection(".debug_loc", &debug_loc_);
-    builder_->WriteSection(".debug_ranges", &debug_ranges_);
-  }
-
- private:
-  ElfBuilder<ElfTypes>* builder_;
-  std::vector<uintptr_t> debug_info_patches_;
-  std::vector<uint8_t> debug_abbrev_buffer_;
-  DebugAbbrevWriter<> debug_abbrev_;
-  std::vector<uint8_t> debug_loc_;
-  std::vector<uint8_t> debug_ranges_;
-
-  std::unordered_set<const char*> defined_dex_classes_;  // For CHECKs only.
-};
-
-template<typename ElfTypes>
-class DebugLineWriter {
-  typedef typename ElfTypes::Addr Elf_Addr;
-
- public:
-  explicit DebugLineWriter(ElfBuilder<ElfTypes>* builder) : builder_(builder) {
-  }
-
-  void Start() {
-    builder_->GetDebugLine()->Start();
-  }
-
-  // Write line table for given set of methods.
-  // Returns the number of bytes written.
-  size_t WriteCompilationUnit(CompilationUnit& compilation_unit) {
-    const bool is64bit = Is64BitInstructionSet(builder_->GetIsa());
-    const Elf_Addr text_address = builder_->GetText()->Exists()
-        ? builder_->GetText()->GetAddress()
-        : 0;
-
-    compilation_unit.debug_line_offset_ = builder_->GetDebugLine()->GetSize();
-
-    std::vector<FileEntry> files;
-    std::unordered_map<std::string, size_t> files_map;
-    std::vector<std::string> directories;
-    std::unordered_map<std::string, size_t> directories_map;
-    int code_factor_bits_ = 0;
-    int dwarf_isa = -1;
-    switch (builder_->GetIsa()) {
-      case kArm:  // arm actually means thumb2.
-      case kThumb2:
-        code_factor_bits_ = 1;  // 16-bit instuctions
-        dwarf_isa = 1;  // DW_ISA_ARM_thumb.
-        break;
-      case kArm64:
-      case kMips:
-      case kMips64:
-        code_factor_bits_ = 2;  // 32-bit instructions
-        break;
-      case kNone:
-      case kX86:
-      case kX86_64:
-        break;
-    }
-    DebugLineOpCodeWriter<> opcodes(is64bit, code_factor_bits_);
-    for (const MethodDebugInfo* mi : compilation_unit.methods_) {
-      // Ignore function if we have already generated line table for the same address.
-      // It would confuse the debugger and the DWARF specification forbids it.
-      if (mi->deduped_) {
-        continue;
-      }
-
-      ArrayRef<const SrcMapElem> src_mapping_table;
-      std::vector<SrcMapElem> src_mapping_table_from_stack_maps;
-      if (IsFromOptimizingCompiler(mi)) {
-        // Use stack maps to create mapping table from pc to dex.
-        const CodeInfo code_info(mi->compiled_method_->GetVmapTable().data());
-        const StackMapEncoding encoding = code_info.ExtractEncoding();
-        for (uint32_t s = 0; s < code_info.GetNumberOfStackMaps(); s++) {
-          StackMap stack_map = code_info.GetStackMapAt(s, encoding);
-          DCHECK(stack_map.IsValid());
-          // Emit only locations where we have local-variable information.
-          // In particular, skip mappings inside the prologue.
-          if (stack_map.HasDexRegisterMap(encoding)) {
-            const uint32_t pc = stack_map.GetNativePcOffset(encoding);
-            const int32_t dex = stack_map.GetDexPc(encoding);
-            src_mapping_table_from_stack_maps.push_back({pc, dex});
-          }
-        }
-        std::sort(src_mapping_table_from_stack_maps.begin(),
-                  src_mapping_table_from_stack_maps.end());
-        src_mapping_table = ArrayRef<const SrcMapElem>(src_mapping_table_from_stack_maps);
-      } else {
-        // Use the mapping table provided by the quick compiler.
-        src_mapping_table = mi->compiled_method_->GetSrcMappingTable();
-      }
-
-      if (src_mapping_table.empty()) {
-        continue;
-      }
-
-      Elf_Addr method_address = text_address + mi->low_pc_;
-
-      PositionInfos position_infos;
-      const DexFile* dex = mi->dex_file_;
-      if (!dex->DecodeDebugPositionInfo(mi->code_item_, PositionInfoCallback, &position_infos)) {
-        continue;
-      }
-
-      if (position_infos.empty()) {
-        continue;
-      }
-
-      opcodes.SetAddress(method_address);
-      if (dwarf_isa != -1) {
-        opcodes.SetISA(dwarf_isa);
-      }
-
-      // Get and deduplicate directory and filename.
-      int file_index = 0;  // 0 - primary source file of the compilation.
-      auto& dex_class_def = dex->GetClassDef(mi->class_def_index_);
-      const char* source_file = dex->GetSourceFile(dex_class_def);
-      if (source_file != nullptr) {
-        std::string file_name(source_file);
-        size_t file_name_slash = file_name.find_last_of('/');
-        std::string class_name(dex->GetClassDescriptor(dex_class_def));
-        size_t class_name_slash = class_name.find_last_of('/');
-        std::string full_path(file_name);
-
-        // Guess directory from package name.
-        int directory_index = 0;  // 0 - current directory of the compilation.
-        if (file_name_slash == std::string::npos &&  // Just filename.
-            class_name.front() == 'L' &&  // Type descriptor for a class.
-            class_name_slash != std::string::npos) {  // Has package name.
-          std::string package_name = class_name.substr(1, class_name_slash - 1);
-          auto it = directories_map.find(package_name);
-          if (it == directories_map.end()) {
-            directory_index = 1 + directories.size();
-            directories_map.emplace(package_name, directory_index);
-            directories.push_back(package_name);
-          } else {
-            directory_index = it->second;
-          }
-          full_path = package_name + "/" + file_name;
-        }
-
-        // Add file entry.
-        auto it2 = files_map.find(full_path);
-        if (it2 == files_map.end()) {
-          file_index = 1 + files.size();
-          files_map.emplace(full_path, file_index);
-          files.push_back(FileEntry {
-            file_name,
-            directory_index,
-            0,  // Modification time - NA.
-            0,  // File size - NA.
-          });
-        } else {
-          file_index = it2->second;
-        }
-      }
-      opcodes.SetFile(file_index);
-
-      // Generate mapping opcodes from PC to Java lines.
-      if (file_index != 0) {
-        bool first = true;
-        for (SrcMapElem pc2dex : src_mapping_table) {
-          uint32_t pc = pc2dex.from_;
-          int dex_pc = pc2dex.to_;
-          // Find mapping with address with is greater than our dex pc; then go back one step.
-          auto ub = std::upper_bound(position_infos.begin(), position_infos.end(), dex_pc,
-              [](uint32_t address, const DexFile::PositionInfo& entry) {
-                  return address < entry.address_;
-              });
-          if (ub != position_infos.begin()) {
-            int line = (--ub)->line_;
-            if (first) {
-              first = false;
-              if (pc > 0) {
-                // Assume that any preceding code is prologue.
-                int first_line = position_infos.front().line_;
-                // Prologue is not a sensible place for a breakpoint.
-                opcodes.NegateStmt();
-                opcodes.AddRow(method_address, first_line);
-                opcodes.NegateStmt();
-                opcodes.SetPrologueEnd();
-              }
-              opcodes.AddRow(method_address + pc, line);
-            } else if (line != opcodes.CurrentLine()) {
-              opcodes.AddRow(method_address + pc, line);
-            }
-          }
-        }
-      } else {
-        // line 0 - instruction cannot be attributed to any source line.
-        opcodes.AddRow(method_address, 0);
-      }
-
-      opcodes.AdvancePC(text_address + mi->high_pc_);
-      opcodes.EndSequence();
-    }
-    std::vector<uint8_t> buffer;
-    buffer.reserve(opcodes.data()->size() + KB);
-    size_t offset = builder_->GetDebugLine()->GetSize();
-    WriteDebugLineTable(directories, files, opcodes, offset, &buffer, &debug_line_patches);
-    builder_->GetDebugLine()->WriteFully(buffer.data(), buffer.size());
-    return buffer.size();
-  }
-
-  void End() {
-    builder_->GetDebugLine()->End();
-    builder_->WritePatches(".debug_line.oat_patches",
-                           ArrayRef<const uintptr_t>(debug_line_patches));
-  }
-
- private:
-  ElfBuilder<ElfTypes>* builder_;
-  std::vector<uintptr_t> debug_line_patches;
-};
-
-template<typename ElfTypes>
-static void WriteDebugSections(ElfBuilder<ElfTypes>* builder,
-                               const ArrayRef<const MethodDebugInfo>& method_infos) {
-  // Group the methods into compilation units based on source file.
-  std::vector<CompilationUnit> compilation_units;
-  const char* last_source_file = nullptr;
-  for (const MethodDebugInfo& mi : method_infos) {
-    auto& dex_class_def = mi.dex_file_->GetClassDef(mi.class_def_index_);
-    const char* source_file = mi.dex_file_->GetSourceFile(dex_class_def);
-    if (compilation_units.empty() || source_file != last_source_file) {
-      compilation_units.push_back(CompilationUnit());
-    }
-    CompilationUnit& cu = compilation_units.back();
-    cu.methods_.push_back(&mi);
-    cu.low_pc_ = std::min(cu.low_pc_, mi.low_pc_);
-    cu.high_pc_ = std::max(cu.high_pc_, mi.high_pc_);
-    last_source_file = source_file;
-  }
-
-  // Write .debug_line section.
-  if (!compilation_units.empty()) {
-    DebugLineWriter<ElfTypes> line_writer(builder);
-    line_writer.Start();
-    for (auto& compilation_unit : compilation_units) {
-      line_writer.WriteCompilationUnit(compilation_unit);
-    }
-    line_writer.End();
-  }
-
-  // Write .debug_info section.
-  if (!compilation_units.empty()) {
-    DebugInfoWriter<ElfTypes> info_writer(builder);
-    info_writer.Start();
-    for (const auto& compilation_unit : compilation_units) {
-      info_writer.WriteCompilationUnit(compilation_unit);
-    }
-    info_writer.End();
-  }
-}
-
-template <typename ElfTypes>
-static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
-                              const ArrayRef<const MethodDebugInfo>& method_infos,
-                              bool with_signature) {
-  bool generated_mapping_symbol = false;
-  auto* strtab = builder->GetStrTab();
-  auto* symtab = builder->GetSymTab();
-
-  if (method_infos.empty()) {
-    return;
-  }
-
-  // Find all addresses (low_pc) which contain deduped methods.
-  // The first instance of method is not marked deduped_, but the rest is.
-  std::unordered_set<uint32_t> deduped_addresses;
-  for (const MethodDebugInfo& info : method_infos) {
-    if (info.deduped_) {
-      deduped_addresses.insert(info.low_pc_);
-    }
-  }
-
-  strtab->Start();
-  strtab->Write("");  // strtab should start with empty string.
-  std::string last_name;
-  size_t last_name_offset = 0;
-  for (const MethodDebugInfo& info : method_infos) {
-    if (info.deduped_) {
-      continue;  // Add symbol only for the first instance.
-    }
-    std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, with_signature);
-    if (deduped_addresses.find(info.low_pc_) != deduped_addresses.end()) {
-      name += " [DEDUPED]";
-    }
-    // If we write method names without signature, we might see the same name multiple times.
-    size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
-
-    const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr;
-    const bool is_relative = (text != nullptr);
-    uint32_t low_pc = info.low_pc_;
-    // Add in code delta, e.g., thumb bit 0 for Thumb2 code.
-    low_pc += info.compiled_method_->CodeDelta();
-    symtab->Add(name_offset,
-                text,
-                low_pc,
-                is_relative,
-                info.high_pc_ - info.low_pc_,
-                STB_GLOBAL,
-                STT_FUNC);
-
-    // Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
-    // instructions, so that disassembler tools can correctly disassemble.
-    // Note that even if we generate just a single mapping symbol, ARM's Streamline
-    // requires it to match function symbol.  Just address 0 does not work.
-    if (info.compiled_method_->GetInstructionSet() == kThumb2) {
-      if (!generated_mapping_symbol || !kGenerateSingleArmMappingSymbol) {
-        symtab->Add(strtab->Write("$t"), text, info.low_pc_ & ~1,
-                    is_relative, 0, STB_LOCAL, STT_NOTYPE);
-        generated_mapping_symbol = true;
-      }
-    }
-
-    last_name = std::move(name);
-    last_name_offset = name_offset;
-  }
-  strtab->End();
-
-  // Symbols are buffered and written after names (because they are smaller).
-  // We could also do two passes in this function to avoid the buffering.
-  symtab->Start();
-  symtab->Write();
-  symtab->End();
-}
-
-template <typename ElfTypes>
-void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
-                    const ArrayRef<const MethodDebugInfo>& method_infos,
-                    CFIFormat cfi_format) {
-  // Add methods to .symtab.
-  WriteDebugSymbols(builder, method_infos, true /* with_signature */);
-  // Generate CFI (stack unwinding information).
-  WriteCFISection(builder, method_infos, cfi_format, true /* write_oat_patches */);
-  // Write DWARF .debug_* sections.
-  WriteDebugSections(builder, method_infos);
-}
-
-static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) {
-  // Configure the compression library.
-  CrcGenerateTable();
-  Crc64GenerateTable();
-  CLzma2EncProps lzma2Props;
-  Lzma2EncProps_Init(&lzma2Props);
-  lzma2Props.lzmaProps.level = 1;  // Fast compression.
-  Lzma2EncProps_Normalize(&lzma2Props);
-  CXzProps props;
-  XzProps_Init(&props);
-  props.lzma2Props = &lzma2Props;
-  // Implement the required interface for communication (written in C so no virtual methods).
-  struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress {
-    static SRes ReadImpl(void* p, void* buf, size_t* size) {
-      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p));
-      *size = std::min(*size, ctx->src_->size() - ctx->src_pos_);
-      memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size);
-      ctx->src_pos_ += *size;
-      return SZ_OK;
-    }
-    static size_t WriteImpl(void* p, const void* buf, size_t size) {
-      auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p));
-      const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf);
-      ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size);
-      return size;
-    }
-    static SRes ProgressImpl(void* , UInt64, UInt64) {
-      return SZ_OK;
-    }
-    size_t src_pos_;
-    const std::vector<uint8_t>* src_;
-    std::vector<uint8_t>* dst_;
-  };
-  XzCallbacks callbacks;
-  callbacks.Read = XzCallbacks::ReadImpl;
-  callbacks.Write = XzCallbacks::WriteImpl;
-  callbacks.Progress = XzCallbacks::ProgressImpl;
-  callbacks.src_pos_ = 0;
-  callbacks.src_ = src;
-  callbacks.dst_ = dst;
-  // Compress.
-  SRes res = Xz_Encode(&callbacks, &callbacks, &props, &callbacks);
-  CHECK_EQ(res, SZ_OK);
-}
-
-template <typename ElfTypes>
-void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* parent_builder,
-                        const ArrayRef<const MethodDebugInfo>& method_infos) {
-  const InstructionSet isa = parent_builder->GetIsa();
-  std::vector<uint8_t> buffer;
-  buffer.reserve(KB);
-  VectorOutputStream out("Mini-debug-info ELF file", &buffer);
-  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
-  builder->Start();
-  // Write .rodata and .text as NOBITS sections.
-  // This allows tools to detect virtual address relocation of the parent ELF file.
-  builder->SetVirtualAddress(parent_builder->GetRoData()->GetAddress());
-  builder->GetRoData()->WriteNoBitsSection(parent_builder->GetRoData()->GetSize());
-  builder->SetVirtualAddress(parent_builder->GetText()->GetAddress());
-  builder->GetText()->WriteNoBitsSection(parent_builder->GetText()->GetSize());
-  WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
-  WriteCFISection(builder.get(), method_infos, DW_DEBUG_FRAME_FORMAT, false /* write_oat_paches */);
-  builder->End();
-  CHECK(builder->Good());
-  std::vector<uint8_t> compressed_buffer;
-  compressed_buffer.reserve(buffer.size() / 4);
-  XzCompress(&buffer, &compressed_buffer);
-  parent_builder->WriteSection(".gnu_debugdata", &compressed_buffer);
-}
-
-template <typename ElfTypes>
-static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal(
-    const dwarf::MethodDebugInfo& method_info) {
-  const InstructionSet isa = method_info.compiled_method_->GetInstructionSet();
-  std::vector<uint8_t> buffer;
-  buffer.reserve(KB);
-  VectorOutputStream out("Debug ELF file", &buffer);
-  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
-  builder->Start();
-  WriteDebugInfo(builder.get(),
-                 ArrayRef<const MethodDebugInfo>(&method_info, 1),
-                 DW_DEBUG_FRAME_FORMAT);
-  builder->End();
-  CHECK(builder->Good());
-  // Make a copy of the buffer.  We want to shrink it anyway.
-  uint8_t* result = new uint8_t[buffer.size()];
-  CHECK(result != nullptr);
-  memcpy(result, buffer.data(), buffer.size());
-  return ArrayRef<const uint8_t>(result, buffer.size());
-}
-
-ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info) {
-  const InstructionSet isa = method_info.compiled_method_->GetInstructionSet();
-  if (Is64BitInstructionSet(isa)) {
-    return WriteDebugElfFileForMethodInternal<ElfTypes64>(method_info);
-  } else {
-    return WriteDebugElfFileForMethodInternal<ElfTypes32>(method_info);
-  }
-}
-
-template <typename ElfTypes>
-static ArrayRef<const uint8_t> WriteDebugElfFileForClassesInternal(
-    const InstructionSet isa, const ArrayRef<mirror::Class*>& types)
-    SHARED_REQUIRES(Locks::mutator_lock_) {
-  std::vector<uint8_t> buffer;
-  buffer.reserve(KB);
-  VectorOutputStream out("Debug ELF file", &buffer);
-  std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
-  builder->Start();
-
-  DebugInfoWriter<ElfTypes> info_writer(builder.get());
-  info_writer.Start();
-  info_writer.WriteTypes(types);
-  info_writer.End();
-
-  builder->End();
-  CHECK(builder->Good());
-  // Make a copy of the buffer.  We want to shrink it anyway.
-  uint8_t* result = new uint8_t[buffer.size()];
-  CHECK(result != nullptr);
-  memcpy(result, buffer.data(), buffer.size());
-  return ArrayRef<const uint8_t>(result, buffer.size());
-}
-
-ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
-                                                    const ArrayRef<mirror::Class*>& types) {
-  if (Is64BitInstructionSet(isa)) {
-    return WriteDebugElfFileForClassesInternal<ElfTypes64>(isa, types);
-  } else {
-    return WriteDebugElfFileForClassesInternal<ElfTypes32>(isa, types);
-  }
-}
-
-// Explicit instantiations
-template void WriteDebugInfo<ElfTypes32>(
-    ElfBuilder<ElfTypes32>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
-    CFIFormat cfi_format);
-template void WriteDebugInfo<ElfTypes64>(
-    ElfBuilder<ElfTypes64>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos,
-    CFIFormat cfi_format);
-template void WriteMiniDebugInfo<ElfTypes32>(
-    ElfBuilder<ElfTypes32>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos);
-template void WriteMiniDebugInfo<ElfTypes64>(
-    ElfBuilder<ElfTypes64>* builder,
-    const ArrayRef<const MethodDebugInfo>& method_infos);
-
-}  // namespace dwarf
-}  // namespace art
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 6bf080a..1d71e57 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -23,16 +23,18 @@
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "compiled_method.h"
+#include "debug/elf_debug_writer.h"
+#include "debug/method_debug_info.h"
 #include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
 #include "elf.h"
 #include "elf_builder.h"
 #include "elf_utils.h"
-#include "elf_writer_debug.h"
 #include "globals.h"
 #include "leb128.h"
 #include "linker/buffered_output_stream.h"
 #include "linker/file_output_stream.h"
+#include "thread-inl.h"
+#include "thread_pool.h"
 #include "utils.h"
 
 namespace art {
@@ -46,6 +48,37 @@
 // Let's use .debug_frame because it is easier to strip or compress.
 constexpr dwarf::CFIFormat kCFIFormat = dwarf::DW_DEBUG_FRAME_FORMAT;
 
+class DebugInfoTask : public Task {
+ public:
+  DebugInfoTask(InstructionSet isa,
+                size_t rodata_section_size,
+                size_t text_section_size,
+                const ArrayRef<const debug::MethodDebugInfo>& method_infos)
+      : isa_(isa),
+        rodata_section_size_(rodata_section_size),
+        text_section_size_(text_section_size),
+        method_infos_(method_infos) {
+  }
+
+  void Run(Thread*) {
+    result_ = debug::MakeMiniDebugInfo(isa_,
+                                       rodata_section_size_,
+                                       text_section_size_,
+                                       method_infos_);
+  }
+
+  std::vector<uint8_t>* GetResult() {
+    return &result_;
+  }
+
+ private:
+  InstructionSet isa_;
+  size_t rodata_section_size_;
+  size_t text_section_size_;
+  const ArrayRef<const debug::MethodDebugInfo>& method_infos_;
+  std::vector<uint8_t> result_;
+};
+
 template <typename ElfTypes>
 class ElfWriterQuick FINAL : public ElfWriter {
  public:
@@ -55,13 +88,16 @@
   ~ElfWriterQuick();
 
   void Start() OVERRIDE;
+  void PrepareDebugInfo(size_t rodata_section_size,
+                        size_t text_section_size,
+                        const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
   OutputStream* StartRoData() OVERRIDE;
   void EndRoData(OutputStream* rodata) OVERRIDE;
   OutputStream* StartText() OVERRIDE;
   void EndText(OutputStream* text) OVERRIDE;
   void SetBssSize(size_t bss_size) OVERRIDE;
   void WriteDynamicSection() OVERRIDE;
-  void WriteDebugInfo(const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) OVERRIDE;
+  void WriteDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
   void WritePatchLocations(const ArrayRef<const uintptr_t>& patch_locations) OVERRIDE;
   bool End() OVERRIDE;
 
@@ -75,6 +111,8 @@
   File* const elf_file_;
   std::unique_ptr<BufferedOutputStream> output_stream_;
   std::unique_ptr<ElfBuilder<ElfTypes>> builder_;
+  std::unique_ptr<DebugInfoTask> debug_info_task_;
+  std::unique_ptr<ThreadPool> debug_info_thread_pool_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(ElfWriterQuick);
 };
@@ -147,15 +185,40 @@
 }
 
 template <typename ElfTypes>
-void ElfWriterQuick<ElfTypes>::WriteDebugInfo(
-    const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) {
-  if (compiler_options_->GetGenerateDebugInfo()) {
-    // Generate all the debug information we can.
-    dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat);
+void ElfWriterQuick<ElfTypes>::PrepareDebugInfo(
+    size_t rodata_section_size,
+    size_t text_section_size,
+    const ArrayRef<const debug::MethodDebugInfo>& method_infos) {
+  if (!method_infos.empty() && compiler_options_->GetGenerateMiniDebugInfo()) {
+    // Prepare the mini-debug-info in background while we do other I/O.
+    Thread* self = Thread::Current();
+    debug_info_task_ = std::unique_ptr<DebugInfoTask>(
+        new DebugInfoTask(builder_->GetIsa(),
+                          rodata_section_size,
+                          text_section_size,
+                          method_infos));
+    debug_info_thread_pool_ = std::unique_ptr<ThreadPool>(
+        new ThreadPool("Mini-debug-info writer", 1));
+    debug_info_thread_pool_->AddTask(self, debug_info_task_.get());
+    debug_info_thread_pool_->StartWorkers(self);
   }
-  if (compiler_options_->GetGenerateMiniDebugInfo()) {
-    // Generate only some information and compress it.
-    dwarf::WriteMiniDebugInfo(builder_.get(), method_infos);
+}
+
+template <typename ElfTypes>
+void ElfWriterQuick<ElfTypes>::WriteDebugInfo(
+    const ArrayRef<const debug::MethodDebugInfo>& method_infos) {
+  if (!method_infos.empty()) {
+    if (compiler_options_->GetGenerateDebugInfo()) {
+      // Generate all the debug information we can.
+      debug::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat, true /* write_oat_patches */);
+    }
+    if (compiler_options_->GetGenerateMiniDebugInfo()) {
+      // Wait for the mini-debug-info generation to finish and write it to disk.
+      Thread* self = Thread::Current();
+      DCHECK(debug_info_thread_pool_ != nullptr);
+      debug_info_thread_pool_->Wait(self, true, false);
+      builder_->WriteSection(".gnu_debugdata", debug_info_task_->GetResult());
+    }
   }
 }
 
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index a5a7796..4920f9b 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -23,7 +23,7 @@
 #include "base/unix_file/fd_file.h"
 #include "class_linker-inl.h"
 #include "common_compiler_test.h"
-#include "dwarf/method_debug_info.h"
+#include "debug/method_debug_info.h"
 #include "elf_writer.h"
 #include "elf_writer_quick.h"
 #include "gc/space/image_space.h"
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 6774758..3fe7861 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -16,19 +16,19 @@
 
 #include "jit_compiler.h"
 
-#include "art_method-inl.h"
 #include "arch/instruction_set.h"
 #include "arch/instruction_set_features.h"
+#include "art_method-inl.h"
 #include "base/stringpiece.h"
 #include "base/time_utils.h"
 #include "base/timing_logger.h"
 #include "base/unix_file/fd_file.h"
 #include "compiler_callbacks.h"
+#include "debug/elf_debug_writer.h"
 #include "dex/pass_manager.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
-#include "elf_writer_debug.h"
 #include "jit/debugger_interface.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
@@ -60,11 +60,12 @@
   delete reinterpret_cast<JitCompiler*>(handle);
 }
 
-extern "C" bool jit_compile_method(void* handle, ArtMethod* method, Thread* self)
+extern "C" bool jit_compile_method(
+    void* handle, ArtMethod* method, Thread* self, bool osr)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   auto* jit_compiler = reinterpret_cast<JitCompiler*>(handle);
   DCHECK(jit_compiler != nullptr);
-  return jit_compiler->CompileMethod(self, method);
+  return jit_compiler->CompileMethod(self, method, osr);
 }
 
 extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t count)
@@ -73,7 +74,7 @@
   DCHECK(jit_compiler != nullptr);
   if (jit_compiler->GetCompilerOptions()->GetGenerateDebugInfo()) {
     const ArrayRef<mirror::Class*> types_array(types, count);
-    ArrayRef<const uint8_t> elf_file = dwarf::WriteDebugElfFileForClasses(kRuntimeISA, types_array);
+    ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForClasses(kRuntimeISA, types_array);
     CreateJITCodeEntry(std::unique_ptr<const uint8_t[]>(elf_file.data()), elf_file.size());
   }
 }
@@ -201,7 +202,8 @@
   }
 }
 
-bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method) {
+bool JitCompiler::CompileMethod(Thread* self, ArtMethod* method, bool osr) {
+  DCHECK(!method->IsProxyMethod());
   TimingLogger logger("JIT compiler timing logger", true, VLOG_IS_ON(jit));
   const uint64_t start_time = NanoTime();
   StackHandleScope<2> hs(self);
@@ -219,20 +221,17 @@
   bool success = false;
   {
     TimingLogger::ScopedTiming t2("Compiling", &logger);
-    // If we get a request to compile a proxy method, we pass the actual Java method
-    // of that proxy method, as the compiler does not expect a proxy method.
-    ArtMethod* method_to_compile = method->GetInterfaceMethodIfProxy(sizeof(void*));
     JitCodeCache* const code_cache = runtime->GetJit()->GetCodeCache();
-    success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method_to_compile);
-    if (success && perf_file_ != nullptr) {
-      const void* ptr = method_to_compile->GetEntryPointFromQuickCompiledCode();
+    success = compiler_driver_->GetCompiler()->JitCompile(self, code_cache, method, osr);
+    if (success && (perf_file_ != nullptr)) {
+      const void* ptr = method->GetEntryPointFromQuickCompiledCode();
       std::ostringstream stream;
       stream << std::hex
              << reinterpret_cast<uintptr_t>(ptr)
              << " "
              << code_cache->GetMemorySizeOfCodePointer(ptr)
              << " "
-             << PrettyMethod(method_to_compile)
+             << PrettyMethod(method)
              << std::endl;
       std::string str = stream.str();
       bool res = perf_file_->WriteFully(str.c_str(), str.size());
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index 037a18a..5294d0e 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -37,7 +37,7 @@
  public:
   static JitCompiler* Create();
   virtual ~JitCompiler();
-  bool CompileMethod(Thread* self, ArtMethod* method)
+  bool CompileMethod(Thread* self, ArtMethod* method, bool osr)
       SHARED_REQUIRES(Locks::mutator_lock_);
   CompilerCallbacks* GetCompilerCallbacks() const;
   size_t GetTotalCompileTime() const {
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index cff2f47..894d29e 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -21,20 +21,20 @@
 #include "common_compiler_test.h"
 #include "compiled_method.h"
 #include "compiler.h"
+#include "debug/method_debug_info.h"
 #include "dex/pass_manager.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 #include "dex/quick_compiler_callbacks.h"
 #include "dex/verification_results.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
 #include "elf_writer.h"
 #include "elf_writer_quick.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "linker/vector_output_stream.h"
 #include "mirror/class-inl.h"
-#include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
 #include "oat_file-inl.h"
 #include "oat_writer.h"
 #include "scoped_thread_state_change.h"
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 90ac499..47dcfd5 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -29,11 +29,11 @@
 #include "class_linker.h"
 #include "compiled_class.h"
 #include "compiled_method.h"
-#include "dex_file-inl.h"
+#include "debug/method_debug_info.h"
 #include "dex/verification_results.h"
+#include "dex_file-inl.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space.h"
 #include "handle_scope-inl.h"
@@ -811,7 +811,7 @@
         // Record debug information for this function if we are doing that.
         const uint32_t quick_code_start = quick_code_offset -
             writer_->oat_header_->GetExecutableOffset() - thumb_offset;
-        writer_->method_info_.push_back(dwarf::MethodDebugInfo {
+        writer_->method_info_.push_back(debug::MethodDebugInfo {
             dex_file_,
             class_def_index_,
             it.GetMemberIndex(),
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 14c6d50..5a55fc6 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -43,9 +43,9 @@
 class TypeLookupTable;
 class ZipEntry;
 
-namespace dwarf {
+namespace debug {
 struct MethodDebugInfo;
-}  // namespace dwarf
+}  // namespace debug
 
 // OatHeader         variable length with count of D OatDexFiles
 //
@@ -193,8 +193,8 @@
 
   ~OatWriter();
 
-  ArrayRef<const dwarf::MethodDebugInfo> GetMethodDebugInfo() const {
-    return ArrayRef<const dwarf::MethodDebugInfo>(method_info_);
+  ArrayRef<const debug::MethodDebugInfo> GetMethodDebugInfo() const {
+    return ArrayRef<const debug::MethodDebugInfo>(method_info_);
   }
 
   const CompilerDriver* GetCompilerDriver() {
@@ -289,7 +289,7 @@
   // We need this because we keep plain pointers to the strings' c_str().
   std::list<std::string> zipped_dex_file_locations_;
 
-  dchecked_vector<dwarf::MethodDebugInfo> method_info_;
+  dchecked_vector<debug::MethodDebugInfo> method_info_;
 
   const CompilerDriver* compiler_driver_;
   ImageWriter* image_writer_;
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index eee6116..ba1b168 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -63,9 +63,10 @@
     return true;
   }
 
+  // Return true if instruction can be expressed as "left_instruction + right_constant".
   static bool IsAddOrSubAConstant(HInstruction* instruction,
-                                  HInstruction** left_instruction,
-                                  int* right_constant) {
+                                  /* out */ HInstruction** left_instruction,
+                                  /* out */ int32_t* right_constant) {
     if (instruction->IsAdd() || instruction->IsSub()) {
       HBinaryOperation* bin_op = instruction->AsBinaryOperation();
       HInstruction* left = bin_op->GetLeft();
@@ -82,9 +83,22 @@
     return false;
   }
 
+  // Expresses any instruction as a value bound.
+  static ValueBound AsValueBound(HInstruction* instruction) {
+    if (instruction->IsIntConstant()) {
+      return ValueBound(nullptr, instruction->AsIntConstant()->GetValue());
+    }
+    HInstruction *left;
+    int32_t right;
+    if (IsAddOrSubAConstant(instruction, &left, &right)) {
+      return ValueBound(left, right);
+    }
+    return ValueBound(instruction, 0);
+  }
+
   // Try to detect useful value bound format from an instruction, e.g.
   // a constant or array length related value.
-  static ValueBound DetectValueBoundFromValue(HInstruction* instruction, bool* found) {
+  static ValueBound DetectValueBoundFromValue(HInstruction* instruction, /* out */ bool* found) {
     DCHECK(instruction != nullptr);
     if (instruction->IsIntConstant()) {
       *found = true;
@@ -227,7 +241,7 @@
   // Add a constant to a ValueBound.
   // `overflow` or `underflow` will return whether the resulting bound may
   // overflow or underflow an int.
-  ValueBound Add(int32_t c, bool* overflow, bool* underflow) const {
+  ValueBound Add(int32_t c, /* out */ bool* overflow, /* out */ bool* underflow) const {
     *overflow = *underflow = false;
     if (c == 0) {
       return *this;
@@ -488,10 +502,10 @@
   // the deoptimization technique.
   static constexpr size_t kThresholdForAddingDeoptimize = 2;
 
-  // Very large constant index is considered as an anomaly. This is a threshold
-  // beyond which we don't bother to apply the deoptimization technique since
-  // it's likely some AIOOBE will be thrown.
-  static constexpr int32_t kMaxConstantForAddingDeoptimize =
+  // Very large lengths are considered an anomaly. This is a threshold beyond which we don't
+  // bother to apply the deoptimization technique since it's likely, or sometimes certain,
+  // an AIOOBE will be thrown.
+  static constexpr uint32_t kMaxLengthForAddingDeoptimize =
       std::numeric_limits<int32_t>::max() - 1024 * 1024;
 
   // Added blocks for loop body entry test.
@@ -508,7 +522,7 @@
                   std::less<int>(),
                   graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
               graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
-        first_constant_index_bounds_check_map_(
+        first_index_bounds_check_map_(
             std::less<int>(),
             graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
         early_exit_loop_(
@@ -518,23 +532,16 @@
             std::less<uint32_t>(),
             graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
         finite_loop_(graph->GetArena()->Adapter(kArenaAllocBoundsCheckElimination)),
-        need_to_revisit_block_(false),
-        has_deoptimization_on_constant_subscripts_(false),
+        has_dom_based_dynamic_bce_(false),
         initial_block_size_(graph->GetBlocks().size()),
         side_effects_(side_effects),
         induction_range_(induction_analysis) {}
 
   void VisitBasicBlock(HBasicBlock* block) OVERRIDE {
     DCHECK(!IsAddedBlock(block));
-    first_constant_index_bounds_check_map_.clear();
+    first_index_bounds_check_map_.clear();
     HGraphVisitor::VisitBasicBlock(block);
-    if (need_to_revisit_block_) {
-      AddComparesWithDeoptimization(block);
-      need_to_revisit_block_ = false;
-      first_constant_index_bounds_check_map_.clear();
-      GetValueRangeMap(block)->clear();
-      HGraphVisitor::VisitBasicBlock(block);
-    }
+    AddComparesWithDeoptimization(block);
   }
 
   void Finish() {
@@ -555,8 +562,7 @@
       // Added blocks don't keep value ranges.
       return nullptr;
     }
-    uint32_t block_id = basic_block->GetBlockId();
-    return &maps_[block_id];
+    return &maps_[basic_block->GetBlockId()];
   }
 
   // Traverse up the dominator tree to look for value range info.
@@ -576,6 +582,11 @@
     return nullptr;
   }
 
+  // Helper method to assign a new range to an instruction in given basic block.
+  void AssignRange(HBasicBlock* basic_block, HInstruction* instruction, ValueRange* range) {
+    GetValueRangeMap(basic_block)->Overwrite(instruction->GetId(), range);
+  }
+
   // Narrow the value range of `instruction` at the end of `basic_block` with `range`,
   // and push the narrowed value range to `successor`.
   void ApplyRangeFromComparison(HInstruction* instruction, HBasicBlock* basic_block,
@@ -583,7 +594,7 @@
     ValueRange* existing_range = LookupValueRange(instruction, basic_block);
     if (existing_range == nullptr) {
       if (range != nullptr) {
-        GetValueRangeMap(successor)->Overwrite(instruction->GetId(), range);
+        AssignRange(successor, instruction, range);
       }
       return;
     }
@@ -595,8 +606,7 @@
         return;
       }
     }
-    ValueRange* narrowed_range = existing_range->Narrow(range);
-    GetValueRangeMap(successor)->Overwrite(instruction->GetId(), narrowed_range);
+    AssignRange(successor, instruction, existing_range->Narrow(range));
   }
 
   // Special case that we may simultaneously narrow two MonotonicValueRange's to
@@ -778,37 +788,37 @@
            array_length->IsPhi());
     bool try_dynamic_bce = true;
 
+    // Analyze index range.
     if (!index->IsIntConstant()) {
-      // Non-constant subscript.
+      // Non-constant index.
       ValueBound lower = ValueBound(nullptr, 0);        // constant 0
       ValueBound upper = ValueBound(array_length, -1);  // array_length - 1
       ValueRange array_range(GetGraph()->GetArena(), lower, upper);
-      // Try range obtained by dominator-based analysis.
+      // Try index range obtained by dominator-based analysis.
       ValueRange* index_range = LookupValueRange(index, block);
       if (index_range != nullptr && index_range->FitsIn(&array_range)) {
         ReplaceInstruction(bounds_check, index);
         return;
       }
-      // Try range obtained by induction variable analysis.
+      // Try index range obtained by induction variable analysis.
       // Disables dynamic bce if OOB is certain.
       if (InductionRangeFitsIn(&array_range, bounds_check, index, &try_dynamic_bce)) {
         ReplaceInstruction(bounds_check, index);
         return;
       }
     } else {
-      // Constant subscript.
+      // Constant index.
       int32_t constant = index->AsIntConstant()->GetValue();
       if (constant < 0) {
         // Will always throw exception.
         return;
-      }
-      if (array_length->IsIntConstant()) {
+      } else if (array_length->IsIntConstant()) {
         if (constant < array_length->AsIntConstant()->GetValue()) {
           ReplaceInstruction(bounds_check, index);
         }
         return;
       }
-
+      // Analyze array length range.
       DCHECK(array_length->IsArrayLength());
       ValueRange* existing_range = LookupValueRange(array_length, block);
       if (existing_range != nullptr) {
@@ -823,37 +833,35 @@
           // bounds check.
         }
       }
-
-      if (first_constant_index_bounds_check_map_.find(array_length->GetId()) ==
-          first_constant_index_bounds_check_map_.end()) {
-        // Remember the first bounds check against array_length of a constant index.
-        // That bounds check instruction has an associated HEnvironment where we
-        // may add an HDeoptimize to eliminate bounds checks of constant indices
-        // against array_length.
-        first_constant_index_bounds_check_map_.Put(array_length->GetId(), bounds_check);
-      } else {
-        // We've seen it at least twice. It's beneficial to introduce a compare with
-        // deoptimization fallback to eliminate the bounds checks.
-        need_to_revisit_block_ = true;
-      }
-
       // Once we have an array access like 'array[5] = 1', we record array.length >= 6.
       // We currently don't do it for non-constant index since a valid array[i] can't prove
       // a valid array[i-1] yet due to the lower bound side.
       if (constant == std::numeric_limits<int32_t>::max()) {
         // Max() as an index will definitely throw AIOOBE.
         return;
+      } else {
+        ValueBound lower = ValueBound(nullptr, constant + 1);
+        ValueBound upper = ValueBound::Max();
+        ValueRange* range = new (GetGraph()->GetArena())
+            ValueRange(GetGraph()->GetArena(), lower, upper);
+        AssignRange(block, array_length, range);
       }
-      ValueBound lower = ValueBound(nullptr, constant + 1);
-      ValueBound upper = ValueBound::Max();
-      ValueRange* range = new (GetGraph()->GetArena())
-          ValueRange(GetGraph()->GetArena(), lower, upper);
-      GetValueRangeMap(block)->Overwrite(array_length->GetId(), range);
     }
 
     // If static analysis fails, and OOB is not certain, try dynamic elimination.
     if (try_dynamic_bce) {
-      TryDynamicBCE(bounds_check);
+      // Try loop-based dynamic elimination.
+      if (TryDynamicBCE(bounds_check)) {
+        return;
+      }
+      // Prepare dominator-based dynamic elimination.
+      if (first_index_bounds_check_map_.find(array_length->GetId()) ==
+          first_index_bounds_check_map_.end()) {
+        // Remember the first bounds check against each array_length. That bounds check
+        // instruction has an associated HEnvironment where we may add an HDeoptimize
+        // to eliminate subsequent bounds checks against the same array_length.
+        first_index_bounds_check_map_.Put(array_length->GetId(), bounds_check);
+      }
     }
   }
 
@@ -914,7 +922,7 @@
                 increment,
                 bound);
           }
-          GetValueRangeMap(phi->GetBlock())->Overwrite(phi->GetId(), range);
+          AssignRange(phi->GetBlock(), phi, range);
         }
       }
     }
@@ -942,7 +950,7 @@
       }
       ValueRange* range = left_range->Add(right->AsIntConstant()->GetValue());
       if (range != nullptr) {
-        GetValueRangeMap(add->GetBlock())->Overwrite(add->GetId(), range);
+        AssignRange(add->GetBlock(), add, range);
       }
     }
   }
@@ -957,7 +965,7 @@
       }
       ValueRange* range = left_range->Add(-right->AsIntConstant()->GetValue());
       if (range != nullptr) {
-        GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+        AssignRange(sub->GetBlock(), sub, range);
         return;
       }
     }
@@ -997,7 +1005,7 @@
                     GetGraph()->GetArena(),
                     ValueBound(nullptr, right_const - upper.GetConstant()),
                     ValueBound(array_length, right_const - lower.GetConstant()));
-                GetValueRangeMap(sub->GetBlock())->Overwrite(sub->GetId(), range);
+                AssignRange(sub->GetBlock(), sub, range);
               }
             }
           }
@@ -1045,7 +1053,7 @@
           GetGraph()->GetArena(),
           ValueBound(nullptr, std::numeric_limits<int32_t>::min()),
           ValueBound(left, 0));
-      GetValueRangeMap(instruction->GetBlock())->Overwrite(instruction->GetId(), range);
+      AssignRange(instruction->GetBlock(), instruction, range);
     }
   }
 
@@ -1071,7 +1079,7 @@
             GetGraph()->GetArena(),
             ValueBound(nullptr, 0),
             ValueBound(nullptr, constant));
-        GetValueRangeMap(instruction->GetBlock())->Overwrite(instruction->GetId(), range);
+        AssignRange(instruction->GetBlock(), instruction, range);
       }
     }
   }
@@ -1095,30 +1103,11 @@
         if (existing_range != nullptr) {
           range = existing_range->Narrow(range);
         }
-        GetValueRangeMap(new_array->GetBlock())->Overwrite(left->GetId(), range);
+        AssignRange(new_array->GetBlock(), left, range);
       }
     }
   }
 
-  void VisitDeoptimize(HDeoptimize* deoptimize) OVERRIDE {
-    if (!deoptimize->InputAt(0)->IsLessThanOrEqual()) {
-      return;
-    }
-    // If this instruction was added by AddCompareWithDeoptimization(), narrow
-    // the range accordingly in subsequent basic blocks.
-    HLessThanOrEqual* less_than_or_equal = deoptimize->InputAt(0)->AsLessThanOrEqual();
-    HInstruction* instruction = less_than_or_equal->InputAt(0);
-    if (instruction->IsArrayLength()) {
-      HInstruction* constant = less_than_or_equal->InputAt(1);
-      DCHECK(constant->IsIntConstant());
-      DCHECK(constant->AsIntConstant()->GetValue() <= kMaxConstantForAddingDeoptimize);
-      ValueBound lower = ValueBound(nullptr, constant->AsIntConstant()->GetValue() + 1);
-      ValueRange* range = new (GetGraph()->GetArena())
-          ValueRange(GetGraph()->GetArena(), lower, ValueBound::Max());
-      GetValueRangeMap(deoptimize->GetBlock())->Overwrite(instruction->GetId(), range);
-    }
-  }
-
   /**
     * After null/bounds checks are eliminated, some invariant array references
     * may be exposed underneath which can be hoisted out of the loop to the
@@ -1130,13 +1119,12 @@
     *     a[i][j] = 0;               --a[i]--+
     * }
     *
-    * Note: this optimization is no longer applied after deoptimization on array references
-    * with constant subscripts has occurred (see AddCompareWithDeoptimization()), since in
-    * those cases it would be unsafe to hoist array references across their deoptimization
-    * instruction inside a loop.
+    * Note: this optimization is no longer applied after dominator-based dynamic deoptimization
+    * has occurred (see AddCompareWithDeoptimization()), since in those cases it would be
+    * unsafe to hoist array references across their deoptimization instruction inside a loop.
     */
   void VisitArrayGet(HArrayGet* array_get) OVERRIDE {
-    if (!has_deoptimization_on_constant_subscripts_ && array_get->IsInLoop()) {
+    if (!has_dom_based_dynamic_bce_ && array_get->IsInLoop()) {
       HLoopInformation* loop = array_get->GetBlock()->GetLoopInformation();
       if (loop->IsDefinedOutOfTheLoop(array_get->InputAt(0)) &&
           loop->IsDefinedOutOfTheLoop(array_get->InputAt(1))) {
@@ -1148,69 +1136,105 @@
     }
   }
 
-  void AddCompareWithDeoptimization(HInstruction* array_length,
-                                    HIntConstant* const_instr,
-                                    HBasicBlock* block) {
-    DCHECK(array_length->IsArrayLength());
-    ValueRange* range = LookupValueRange(array_length, block);
-    ValueBound lower_bound = range->GetLower();
-    DCHECK(lower_bound.IsConstant());
-    DCHECK(const_instr->GetValue() <= kMaxConstantForAddingDeoptimize);
-    // Note that the lower bound of the array length may have been refined
-    // through other instructions (such as `HNewArray(length - 4)`).
-    DCHECK_LE(const_instr->GetValue() + 1, lower_bound.GetConstant());
-
-    // If array_length is less than lower_const, deoptimize.
-    HBoundsCheck* bounds_check = first_constant_index_bounds_check_map_.Get(
-        array_length->GetId())->AsBoundsCheck();
-    HCondition* cond = new (GetGraph()->GetArena()) HLessThanOrEqual(array_length, const_instr);
-    HDeoptimize* deoptimize = new (GetGraph()->GetArena())
-        HDeoptimize(cond, bounds_check->GetDexPc());
-    block->InsertInstructionBefore(cond, bounds_check);
-    block->InsertInstructionBefore(deoptimize, bounds_check);
-    deoptimize->CopyEnvironmentFrom(bounds_check->GetEnvironment());
-    // Flag that this kind of deoptimization on array references with constant
-    // subscripts has occurred to prevent further hoisting of these references.
-    has_deoptimization_on_constant_subscripts_ = true;
+  // Perform dominator-based dynamic elimination on suitable set of bounds checks.
+  void AddCompareWithDeoptimization(HBasicBlock* block,
+                                    HInstruction* array_length,
+                                    HInstruction* base,
+                                    int32_t min_c, int32_t max_c) {
+    HBoundsCheck* bounds_check =
+        first_index_bounds_check_map_.Get(array_length->GetId())->AsBoundsCheck();
+    // Construct deoptimization on single or double bounds on range [base-min_c,base+max_c],
+    // for example either for a[0]..a[3] just 3 or for a[base-1]..a[base+3] both base-1
+    // and base+3, since we made the assumption any in between value may occur too.
+    static_assert(kMaxLengthForAddingDeoptimize < std::numeric_limits<int32_t>::max(),
+                  "Incorrect max length may be subject to arithmetic wrap-around");
+    HInstruction* upper = GetGraph()->GetIntConstant(max_c);
+    if (base == nullptr) {
+      DCHECK_GE(min_c, 0);
+    } else {
+      HInstruction* lower = new (GetGraph()->GetArena())
+          HAdd(Primitive::kPrimInt, base, GetGraph()->GetIntConstant(min_c));
+      upper = new (GetGraph()->GetArena()) HAdd(Primitive::kPrimInt, base, upper);
+      block->InsertInstructionBefore(lower, bounds_check);
+      block->InsertInstructionBefore(upper, bounds_check);
+      InsertDeoptInBlock(bounds_check, new (GetGraph()->GetArena()) HAbove(lower, upper));
+    }
+    InsertDeoptInBlock(bounds_check, new (GetGraph()->GetArena()) HAboveOrEqual(upper, array_length));
+    // Flag that this kind of deoptimization has occurred.
+    has_dom_based_dynamic_bce_ = true;
   }
 
+  // Attempt dominator-based dynamic elimination on remaining candidates.
   void AddComparesWithDeoptimization(HBasicBlock* block) {
-    for (ArenaSafeMap<int, HBoundsCheck*>::iterator it =
-             first_constant_index_bounds_check_map_.begin();
-         it != first_constant_index_bounds_check_map_.end();
-         ++it) {
-      HBoundsCheck* bounds_check = it->second;
+    for (const auto& entry : first_index_bounds_check_map_) {
+      HBoundsCheck* bounds_check = entry.second;
+      HInstruction* index = bounds_check->InputAt(0);
       HInstruction* array_length = bounds_check->InputAt(1);
       if (!array_length->IsArrayLength()) {
-        // Prior deoptimizations may have changed the array length to a phi.
-        // TODO(mingyao): propagate the range to the phi?
-        DCHECK(array_length->IsPhi()) << array_length->DebugName();
-        continue;
+        continue;  // disregard phis and constants
       }
-      HIntConstant* lower_bound_const_instr = nullptr;
-      int32_t lower_bound_const = std::numeric_limits<int32_t>::min();
-      size_t counter = 0;
-      // Count the constant indexing for which bounds checks haven't
-      // been removed yet.
-      for (HUseIterator<HInstruction*> it2(array_length->GetUses());
-           !it2.Done();
-           it2.Advance()) {
+      // Collect all bounds checks are still there and that are related as "a[base + constant]"
+      // for a base instruction (possibly absent) and various constants. Note that no attempt
+      // is made to partition the set into matching subsets (viz. a[0], a[1] and a[base+1] and
+      // a[base+2] are considered as one set).
+      // TODO: would such a partitioning be worthwhile?
+      ValueBound value = ValueBound::AsValueBound(index);
+      HInstruction* base = value.GetInstruction();
+      int32_t min_c = base == nullptr ? 0 : value.GetConstant();
+      int32_t max_c = value.GetConstant();
+      ArenaVector<HBoundsCheck*> candidates(
+          GetGraph()->GetArena()->Adapter(kArenaAllocBoundsCheckElimination));
+      ArenaVector<HBoundsCheck*> standby(
+          GetGraph()->GetArena()->Adapter(kArenaAllocBoundsCheckElimination));
+      for (HUseIterator<HInstruction*> it2(array_length->GetUses()); !it2.Done(); it2.Advance()) {
+        // Another bounds check in same or dominated block?
         HInstruction* user = it2.Current()->GetUser();
-        if (user->GetBlock() == block &&
-            user->IsBoundsCheck() &&
-            user->AsBoundsCheck()->InputAt(0)->IsIntConstant()) {
-          DCHECK_EQ(array_length, user->AsBoundsCheck()->InputAt(1));
-          HIntConstant* const_instr = user->AsBoundsCheck()->InputAt(0)->AsIntConstant();
-          if (const_instr->GetValue() > lower_bound_const) {
-            lower_bound_const = const_instr->GetValue();
-            lower_bound_const_instr = const_instr;
+        HBasicBlock* other_block = user->GetBlock();
+        if (user->IsBoundsCheck() && block->Dominates(other_block)) {
+          HBoundsCheck* other_bounds_check = user->AsBoundsCheck();
+          HInstruction* other_index = other_bounds_check->InputAt(0);
+          HInstruction* other_array_length = other_bounds_check->InputAt(1);
+          ValueBound other_value = ValueBound::AsValueBound(other_index);
+          if (array_length == other_array_length && base == other_value.GetInstruction()) {
+            int32_t other_c = other_value.GetConstant();
+            // Since a subsequent dominated block could be under a conditional, only accept
+            // the other bounds check if it is in same block or both blocks dominate the exit.
+            // TODO: we could improve this by testing proper post-dominance, or even if this
+            //       constant is seen along *all* conditional paths that follow.
+            HBasicBlock* exit = GetGraph()->GetExitBlock();
+            if (block == user->GetBlock() ||
+                (block->Dominates(exit) && other_block->Dominates(exit))) {
+              min_c = std::min(min_c, other_c);
+              max_c = std::max(max_c, other_c);
+              candidates.push_back(other_bounds_check);
+            } else {
+              // Add this candidate later only if it falls into the range.
+              standby.push_back(other_bounds_check);
+            }
           }
-          counter++;
         }
       }
-      if (counter >= kThresholdForAddingDeoptimize &&
-          lower_bound_const_instr->GetValue() <= kMaxConstantForAddingDeoptimize) {
-        AddCompareWithDeoptimization(array_length, lower_bound_const_instr, block);
+      // Add standby candidates that fall in selected range.
+      for (HBoundsCheck* other_bounds_check : standby) {
+        HInstruction* other_index = other_bounds_check->InputAt(0);
+        int32_t other_c = ValueBound::AsValueBound(other_index).GetConstant();
+        if (min_c <= other_c && other_c <= max_c) {
+          candidates.push_back(other_bounds_check);
+        }
+      }
+      // Perform dominator-based deoptimization if it seems profitable. Note that we reject cases
+      // where the distance min_c:max_c range gets close to the maximum possible array length,
+      // since those cases are likely to always deopt (such situations do not necessarily go
+      // OOB, though, since the programmer could rely on wrap-around from max to min).
+      size_t threshold = kThresholdForAddingDeoptimize + (base == nullptr ? 0 : 1);  // extra test?
+      uint32_t distance = static_cast<uint32_t>(max_c) - static_cast<uint32_t>(min_c);
+      if (candidates.size() >= threshold &&
+          (base != nullptr || min_c >= 0) &&  // reject certain OOB
+           distance <= kMaxLengthForAddingDeoptimize) {  // reject likely/certain deopt
+        AddCompareWithDeoptimization(block, array_length, base, min_c, max_c);
+        for (HInstruction* other_bounds_check : candidates) {
+          ReplaceInstruction(other_bounds_check, other_bounds_check->InputAt(0));
+        }
       }
     }
   }
@@ -1227,27 +1251,28 @@
     InductionVarRange::Value v1;
     InductionVarRange::Value v2;
     bool needs_finite_test = false;
-    induction_range_.GetInductionRange(context, index, &v1, &v2, &needs_finite_test);
-    do {
-      if (v1.is_known && (v1.a_constant == 0 || v1.a_constant == 1) &&
-          v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) {
-        DCHECK(v1.a_constant == 1 || v1.instruction == nullptr);
-        DCHECK(v2.a_constant == 1 || v2.instruction == nullptr);
-        ValueRange index_range(GetGraph()->GetArena(),
-                               ValueBound(v1.instruction, v1.b_constant),
-                               ValueBound(v2.instruction, v2.b_constant));
-        // If analysis reveals a certain OOB, disable dynamic BCE.
-        if (index_range.GetLower().LessThan(array_range->GetLower()) ||
-            index_range.GetUpper().GreaterThan(array_range->GetUpper())) {
-          *try_dynamic_bce = false;
-          return false;
+    if (induction_range_.GetInductionRange(context, index, &v1, &v2, &needs_finite_test)) {
+      do {
+        if (v1.is_known && (v1.a_constant == 0 || v1.a_constant == 1) &&
+            v2.is_known && (v2.a_constant == 0 || v2.a_constant == 1)) {
+          DCHECK(v1.a_constant == 1 || v1.instruction == nullptr);
+          DCHECK(v2.a_constant == 1 || v2.instruction == nullptr);
+          ValueRange index_range(GetGraph()->GetArena(),
+                                 ValueBound(v1.instruction, v1.b_constant),
+                                 ValueBound(v2.instruction, v2.b_constant));
+          // If analysis reveals a certain OOB, disable dynamic BCE.
+          if (index_range.GetLower().LessThan(array_range->GetLower()) ||
+              index_range.GetUpper().GreaterThan(array_range->GetUpper())) {
+            *try_dynamic_bce = false;
+            return false;
+          }
+          // Use analysis for static bce only if loop is finite.
+          if (!needs_finite_test && index_range.FitsIn(array_range)) {
+            return true;
+          }
         }
-        // Use analysis for static bce only if loop is finite.
-        if (!needs_finite_test && index_range.FitsIn(array_range)) {
-          return true;
-        }
-      }
-    } while (induction_range_.RefineOuter(&v1, &v2));
+      } while (induction_range_.RefineOuter(&v1, &v2));
+    }
     return false;
   }
 
@@ -1258,7 +1283,7 @@
    * deoptimization). If no deoptimization occurs, the loop is executed with all corresponding
    * bounds checks and related null checks removed.
    */
-  void TryDynamicBCE(HBoundsCheck* instruction) {
+  bool TryDynamicBCE(HBoundsCheck* instruction) {
     HLoopInformation* loop = instruction->GetBlock()->GetLoopInformation();
     HInstruction* index = instruction->InputAt(0);
     HInstruction* length = instruction->InputAt(1);
@@ -1284,11 +1309,13 @@
       HBasicBlock* block = GetPreHeader(loop, instruction);
       induction_range_.GenerateRangeCode(instruction, index, GetGraph(), block, &lower, &upper);
       if (lower != nullptr) {
-        InsertDeopt(loop, block, new (GetGraph()->GetArena()) HAbove(lower, upper));
+        InsertDeoptInLoop(loop, block, new (GetGraph()->GetArena()) HAbove(lower, upper));
       }
-      InsertDeopt(loop, block, new (GetGraph()->GetArena()) HAboveOrEqual(upper, length));
+      InsertDeoptInLoop(loop, block, new (GetGraph()->GetArena()) HAboveOrEqual(upper, length));
       ReplaceInstruction(instruction, index);
+      return true;
     }
+    return false;
   }
 
   /**
@@ -1381,7 +1408,7 @@
         HBasicBlock* block = GetPreHeader(loop, check);
         HInstruction* cond =
             new (GetGraph()->GetArena()) HEqual(array, GetGraph()->GetNullConstant());
-        InsertDeopt(loop, block, cond);
+        InsertDeoptInLoop(loop, block, cond);
         ReplaceInstruction(check, array);
         return true;
       }
@@ -1447,8 +1474,8 @@
     return loop->GetPreHeader();
   }
 
-  /** Inserts a deoptimization test. */
-  void InsertDeopt(HLoopInformation* loop, HBasicBlock* block, HInstruction* condition) {
+  /** Inserts a deoptimization test in a loop preheader. */
+  void InsertDeoptInLoop(HLoopInformation* loop, HBasicBlock* block, HInstruction* condition) {
     HInstruction* suspend = loop->GetSuspendCheck();
     block->InsertInstructionBefore(condition, block->GetLastInstruction());
     HDeoptimize* deoptimize =
@@ -1460,6 +1487,16 @@
     }
   }
 
+  /** Inserts a deoptimization test right before a bounds check. */
+  void InsertDeoptInBlock(HBoundsCheck* bounds_check, HInstruction* condition) {
+    HBasicBlock* block = bounds_check->GetBlock();
+    block->InsertInstructionBefore(condition, bounds_check);
+    HDeoptimize* deoptimize =
+        new (GetGraph()->GetArena()) HDeoptimize(condition, bounds_check->GetDexPc());
+    block->InsertInstructionBefore(deoptimize, bounds_check);
+    deoptimize->CopyEnvironmentFrom(bounds_check->GetEnvironment());
+  }
+
   /** Hoists instruction out of the loop to preheader or deoptimization block. */
   void HoistToPreHeaderOrDeoptBlock(HLoopInformation* loop, HInstruction* instruction) {
     HBasicBlock* block = GetPreHeader(loop, instruction);
@@ -1627,9 +1664,9 @@
   // A set of maps, one per basic block, from instruction to range.
   ArenaVector<ArenaSafeMap<int, ValueRange*>> maps_;
 
-  // Map an HArrayLength instruction's id to the first HBoundsCheck instruction in
-  // a block that checks a constant index against that HArrayLength.
-  ArenaSafeMap<int, HBoundsCheck*> first_constant_index_bounds_check_map_;
+  // Map an HArrayLength instruction's id to the first HBoundsCheck instruction
+  // in a block that checks an index against that HArrayLength.
+  ArenaSafeMap<int, HBoundsCheck*> first_index_bounds_check_map_;
 
   // Early-exit loop bookkeeping.
   ArenaSafeMap<uint32_t, bool> early_exit_loop_;
@@ -1640,15 +1677,8 @@
   // Finite loop bookkeeping.
   ArenaSet<uint32_t> finite_loop_;
 
-  // For the block, there is at least one HArrayLength instruction for which there
-  // is more than one bounds check instruction with constant indexing. And it's
-  // beneficial to add a compare instruction that has deoptimization fallback and
-  // eliminate those bounds checks.
-  bool need_to_revisit_block_;
-
-  // Flag that denotes whether deoptimization has occurred on array references
-  // with constant subscripts (see AddCompareWithDeoptimization()).
-  bool has_deoptimization_on_constant_subscripts_;
+  // Flag that denotes whether dominator-based dynamic elimination has occurred.
+  bool has_dom_based_dynamic_bce_;
 
   // Initial number of blocks.
   uint32_t initial_block_size_;
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index c7430e7..05e1356 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -32,114 +32,12 @@
 #include "nodes.h"
 #include "primitive.h"
 #include "scoped_thread_state_change.h"
+#include "ssa_builder.h"
 #include "thread.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 
 namespace art {
 
-/**
- * Helper class to add HTemporary instructions. This class is used when
- * converting a DEX instruction to multiple HInstruction, and where those
- * instructions do not die at the following instruction, but instead spans
- * multiple instructions.
- */
-class Temporaries : public ValueObject {
- public:
-  explicit Temporaries(HGraph* graph) : graph_(graph), index_(0) {}
-
-  void Add(HInstruction* instruction) {
-    HInstruction* temp = new (graph_->GetArena()) HTemporary(index_, instruction->GetDexPc());
-    instruction->GetBlock()->AddInstruction(temp);
-
-    DCHECK(temp->GetPrevious() == instruction);
-
-    size_t offset;
-    if (instruction->GetType() == Primitive::kPrimLong
-        || instruction->GetType() == Primitive::kPrimDouble) {
-      offset = 2;
-    } else {
-      offset = 1;
-    }
-    index_ += offset;
-
-    graph_->UpdateTemporariesVRegSlots(index_);
-  }
-
- private:
-  HGraph* const graph_;
-
-  // Current index in the temporary stack, updated by `Add`.
-  size_t index_;
-};
-
-class SwitchTable : public ValueObject {
- public:
-  SwitchTable(const Instruction& instruction, uint32_t dex_pc, bool sparse)
-      : instruction_(instruction), dex_pc_(dex_pc), sparse_(sparse) {
-    int32_t table_offset = instruction.VRegB_31t();
-    const uint16_t* table = reinterpret_cast<const uint16_t*>(&instruction) + table_offset;
-    if (sparse) {
-      CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
-    } else {
-      CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
-    }
-    num_entries_ = table[1];
-    values_ = reinterpret_cast<const int32_t*>(&table[2]);
-  }
-
-  uint16_t GetNumEntries() const {
-    return num_entries_;
-  }
-
-  void CheckIndex(size_t index) const {
-    if (sparse_) {
-      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
-      DCHECK_LT(index, 2 * static_cast<size_t>(num_entries_));
-    } else {
-      // In a packed table, we have the starting key and num_entries_ values.
-      DCHECK_LT(index, 1 + static_cast<size_t>(num_entries_));
-    }
-  }
-
-  int32_t GetEntryAt(size_t index) const {
-    CheckIndex(index);
-    return values_[index];
-  }
-
-  uint32_t GetDexPcForIndex(size_t index) const {
-    CheckIndex(index);
-    return dex_pc_ +
-        (reinterpret_cast<const int16_t*>(values_ + index) -
-         reinterpret_cast<const int16_t*>(&instruction_));
-  }
-
-  // Index of the first value in the table.
-  size_t GetFirstValueIndex() const {
-    if (sparse_) {
-      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
-      return num_entries_;
-    } else {
-      // In a packed table, we have the starting key and num_entries_ values.
-      return 1;
-    }
-  }
-
- private:
-  const Instruction& instruction_;
-  const uint32_t dex_pc_;
-
-  // Whether this is a sparse-switch table (or a packed-switch one).
-  const bool sparse_;
-
-  // This can't be const as it needs to be computed off of the given instruction, and complicated
-  // expressions in the initializer list seemed very ugly.
-  uint16_t num_entries_;
-
-  const int32_t* values_;
-
-  DISALLOW_COPY_AND_ASSIGN(SwitchTable);
-};
-
 void HGraphBuilder::InitializeLocals(uint16_t count) {
   graph_->SetNumberOfVRegs(count);
   locals_.resize(count);
@@ -351,7 +249,7 @@
     // loop for synchronized blocks.
     if (block->HasThrowingInstructions()) {
       // Try to find a TryItem covering the block.
-      DCHECK_NE(block->GetDexPc(), kNoDexPc) << "Block must have a dec_pc to find its TryItem.";
+      DCHECK_NE(block->GetDexPc(), kNoDexPc) << "Block must have a dex_pc to find its TryItem.";
       const int32_t try_item_idx = DexFile::FindTryItem(code_item, block->GetDexPc());
       if (try_item_idx != -1) {
         // Block throwing and in a TryItem. Store the try block information.
@@ -425,7 +323,8 @@
   }
 }
 
-bool HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item) {
+GraphAnalysisResult HGraphBuilder::BuildGraph(const DexFile::CodeItem& code_item,
+                                              StackHandleScopeCollection* handles) {
   DCHECK(graph_->GetBlocks().empty());
 
   const uint16_t* code_ptr = code_item.insns_;
@@ -452,12 +351,12 @@
   // start a new block, and create these blocks.
   if (!ComputeBranchTargets(code_ptr, code_end, &number_of_branches)) {
     MaybeRecordStat(MethodCompilationStat::kNotCompiledBranchOutsideMethodCode);
-    return false;
+    return kAnalysisInvalidBytecode;
   }
 
   // Note that the compiler driver is null when unit testing.
   if ((compiler_driver_ != nullptr) && SkipCompilation(code_item, number_of_branches)) {
-    return false;
+    return kAnalysisInvalidBytecode;
   }
 
   // Find locations where we want to generate extra stackmaps for native debugging.
@@ -488,7 +387,7 @@
       }
     }
     if (!AnalyzeDexInstruction(instruction, dex_pc)) {
-      return false;
+      return kAnalysisInvalidBytecode;
     }
     dex_pc += instruction.SizeInCodeUnits();
     code_ptr += instruction.SizeInCodeUnits();
@@ -507,7 +406,13 @@
   // non-exceptional edges to have been created.
   InsertTryBoundaryBlocks(code_item);
 
-  return true;
+  GraphAnalysisResult result = graph_->BuildDominatorTree();
+  if (result != kAnalysisSuccess) {
+    return result;
+  }
+
+  graph_->InitializeInexactObjectRTI(handles);
+  return SsaBuilder(graph_, handles).BuildSsa();
 }
 
 void HGraphBuilder::MaybeUpdateCurrentBlock(size_t dex_pc) {
@@ -1234,12 +1139,10 @@
   size_t start_index = 0;
   size_t argument_index = 0;
   if (invoke->GetOriginalInvokeType() != InvokeType::kStatic) {  // Instance call.
-    Temporaries temps(graph_);
     HInstruction* arg = LoadLocal(
         is_range ? register_index : args[0], Primitive::kPrimNot, invoke->GetDexPc());
     HNullCheck* null_check = new (arena_) HNullCheck(arg, invoke->GetDexPc());
     current_block_->AddInstruction(null_check);
-    temps.Add(null_check);
     invoke->SetArgumentAt(0, null_check);
     start_index = 1;
     argument_index = 1;
@@ -1337,9 +1240,6 @@
       ? GetFieldAccessType(*dex_file_, field_index)
       : resolved_field->GetTypeAsPrimitiveType();
   if (is_put) {
-    Temporaries temps(graph_);
-    // We need one temporary for the null check.
-    temps.Add(null_check);
     HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
     HInstruction* field_set = nullptr;
     if (resolved_field == nullptr) {
@@ -1524,8 +1424,6 @@
   uint16_t class_def_index = klass->GetDexClassDefIndex();
   if (is_put) {
     // We need to keep the class alive before loading the value.
-    Temporaries temps(graph_);
-    temps.Add(cls);
     HInstruction* value = LoadLocal(source_or_dest_reg, field_type, dex_pc);
     DCHECK_EQ(value->GetType(), field_type);
     current_block_->AddInstruction(new (arena_) HStaticFieldSet(cls,
@@ -1578,9 +1476,7 @@
       || (type == Primitive::kPrimInt && second->AsIntConstant()->GetValue() == 0)
       || (type == Primitive::kPrimLong && second->AsLongConstant()->GetValue() == 0)) {
     second = new (arena_) HDivZeroCheck(second, dex_pc);
-    Temporaries temps(graph_);
     current_block_->AddInstruction(second);
-    temps.Add(current_block_->GetLastInstruction());
   }
 
   if (isDiv) {
@@ -1599,21 +1495,15 @@
   uint8_t array_reg = instruction.VRegB_23x();
   uint8_t index_reg = instruction.VRegC_23x();
 
-  // We need one temporary for the null check, one for the index, and one for the length.
-  Temporaries temps(graph_);
-
   HInstruction* object = LoadLocal(array_reg, Primitive::kPrimNot, dex_pc);
   object = new (arena_) HNullCheck(object, dex_pc);
   current_block_->AddInstruction(object);
-  temps.Add(object);
 
   HInstruction* length = new (arena_) HArrayLength(object, dex_pc);
   current_block_->AddInstruction(length);
-  temps.Add(length);
   HInstruction* index = LoadLocal(index_reg, Primitive::kPrimInt, dex_pc);
   index = new (arena_) HBoundsCheck(index, length, dex_pc);
   current_block_->AddInstruction(index);
-  temps.Add(index);
   if (is_put) {
     HInstruction* value = LoadLocal(source_or_dest_reg, anticipated_type, dex_pc);
     // TODO: Insert a type check node if the type is Object.
@@ -1654,8 +1544,6 @@
   bool is_reference_array = (primitive == 'L') || (primitive == '[');
   Primitive::Type type = is_reference_array ? Primitive::kPrimNot : Primitive::kPrimInt;
 
-  Temporaries temps(graph_);
-  temps.Add(object);
   for (size_t i = 0; i < number_of_vreg_arguments; ++i) {
     HInstruction* value = LoadLocal(is_range ? register_index + i : args[i], type, dex_pc);
     HInstruction* index = graph_->GetIntConstant(i, dex_pc);
@@ -1680,11 +1568,9 @@
 }
 
 void HGraphBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) {
-  Temporaries temps(graph_);
   HInstruction* array = LoadLocal(instruction.VRegA_31t(), Primitive::kPrimNot, dex_pc);
   HNullCheck* null_check = new (arena_) HNullCheck(array, dex_pc);
   current_block_->AddInstruction(null_check);
-  temps.Add(null_check);
 
   HInstruction* length = new (arena_) HArrayLength(null_check, dex_pc);
   current_block_->AddInstruction(length);
@@ -1801,10 +1687,6 @@
       compiler_driver_->CanAssumeTypeIsPresentInDexCache(dex_file, type_index));
   current_block_->AddInstruction(cls);
 
-  // The class needs a temporary before being used by the type check.
-  Temporaries temps(graph_);
-  temps.Add(cls);
-
   TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class);
   if (instruction.Opcode() == Instruction::INSTANCE_OF) {
     current_block_->AddInstruction(new (arena_) HInstanceOf(object, cls, check_kind, dex_pc));
@@ -2883,8 +2765,6 @@
 
     case Instruction::ARRAY_LENGTH: {
       HInstruction* object = LoadLocal(instruction.VRegB_12x(), Primitive::kPrimNot, dex_pc);
-      // No need for a temporary for the null check, it is the only input of the following
-      // instruction.
       object = new (arena_) HNullCheck(object, dex_pc);
       current_block_->AddInstruction(object);
       current_block_->AddInstruction(new (arena_) HArrayLength(object, dex_pc));
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 1d604e7..e3dd0e8 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -30,7 +30,6 @@
 namespace art {
 
 class Instruction;
-class SwitchTable;
 
 class HGraphBuilder : public ValueObject {
  public:
@@ -81,7 +80,8 @@
         null_dex_cache_(),
         dex_cache_(null_dex_cache_) {}
 
-  bool BuildGraph(const DexFile::CodeItem& code);
+  GraphAnalysisResult BuildGraph(const DexFile::CodeItem& code,
+                                 StackHandleScopeCollection* handles);
 
   static constexpr const char* kBuilderPassName = "builder";
 
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index a3bbfdb..c2c8ccf 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -287,19 +287,6 @@
   }
 }
 
-Location CodeGenerator::GetTemporaryLocation(HTemporary* temp) const {
-  uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs();
-  // The type of the previous instruction tells us if we need a single or double stack slot.
-  Primitive::Type type = temp->GetType();
-  int32_t temp_size = (type == Primitive::kPrimLong) || (type == Primitive::kPrimDouble) ? 2 : 1;
-  // Use the temporary region (right below the dex registers).
-  int32_t slot = GetFrameSize() - FrameEntrySpillSize()
-                                - kVRegSize  // filler
-                                - (number_of_locals * kVRegSize)
-                                - ((temp_size + temp->GetIndex()) * kVRegSize);
-  return temp_size == 2 ? Location::DoubleStackSlot(slot) : Location::StackSlot(slot);
-}
-
 int32_t CodeGenerator::GetStackSlot(HLocal* local) const {
   uint16_t reg_number = local->GetRegNumber();
   uint16_t number_of_locals = GetGraph()->GetNumberOfLocalVRegs();
@@ -629,8 +616,76 @@
   return stack_map_stream_.PrepareForFillIn();
 }
 
-void CodeGenerator::BuildStackMaps(MemoryRegion region) {
+static void CheckCovers(uint32_t dex_pc,
+                        const HGraph& graph,
+                        const CodeInfo& code_info,
+                        const ArenaVector<HSuspendCheck*>& loop_headers,
+                        ArenaVector<size_t>* covered) {
+  StackMapEncoding encoding = code_info.ExtractEncoding();
+  for (size_t i = 0; i < loop_headers.size(); ++i) {
+    if (loop_headers[i]->GetDexPc() == dex_pc) {
+      if (graph.IsCompilingOsr()) {
+        DCHECK(code_info.GetOsrStackMapForDexPc(dex_pc, encoding).IsValid());
+      }
+      ++(*covered)[i];
+    }
+  }
+}
+
+// Debug helper to ensure loop entries in compiled code are matched by
+// dex branch instructions.
+static void CheckLoopEntriesCanBeUsedForOsr(const HGraph& graph,
+                                            const CodeInfo& code_info,
+                                            const DexFile::CodeItem& code_item) {
+  if (graph.HasTryCatch()) {
+    // One can write loops through try/catch, which we do not support for OSR anyway.
+    return;
+  }
+  ArenaVector<HSuspendCheck*> loop_headers(graph.GetArena()->Adapter(kArenaAllocMisc));
+  for (HReversePostOrderIterator it(graph); !it.Done(); it.Advance()) {
+    if (it.Current()->IsLoopHeader()) {
+      HSuspendCheck* suspend_check = it.Current()->GetLoopInformation()->GetSuspendCheck();
+      if (!suspend_check->GetEnvironment()->IsFromInlinedInvoke()) {
+        loop_headers.push_back(suspend_check);
+      }
+    }
+  }
+  ArenaVector<size_t> covered(loop_headers.size(), 0, graph.GetArena()->Adapter(kArenaAllocMisc));
+  const uint16_t* code_ptr = code_item.insns_;
+  const uint16_t* code_end = code_item.insns_ + code_item.insns_size_in_code_units_;
+
+  size_t dex_pc = 0;
+  while (code_ptr < code_end) {
+    const Instruction& instruction = *Instruction::At(code_ptr);
+    if (instruction.IsBranch()) {
+      uint32_t target = dex_pc + instruction.GetTargetOffset();
+      CheckCovers(target, graph, code_info, loop_headers, &covered);
+    } else if (instruction.IsSwitch()) {
+      SwitchTable table(instruction, dex_pc, instruction.Opcode() == Instruction::SPARSE_SWITCH);
+      uint16_t num_entries = table.GetNumEntries();
+      size_t offset = table.GetFirstValueIndex();
+
+      // Use a larger loop counter type to avoid overflow issues.
+      for (size_t i = 0; i < num_entries; ++i) {
+        // The target of the case.
+        uint32_t target = dex_pc + table.GetEntryAt(i + offset);
+        CheckCovers(target, graph, code_info, loop_headers, &covered);
+      }
+    }
+    dex_pc += instruction.SizeInCodeUnits();
+    code_ptr += instruction.SizeInCodeUnits();
+  }
+
+  for (size_t i = 0; i < covered.size(); ++i) {
+    DCHECK_NE(covered[i], 0u) << "Loop in compiled code has no dex branch equivalent";
+  }
+}
+
+void CodeGenerator::BuildStackMaps(MemoryRegion region, const DexFile::CodeItem& code_item) {
   stack_map_stream_.FillIn(region);
+  if (kIsDebugBuild) {
+    CheckLoopEntriesCanBeUsedForOsr(*graph_, CodeInfo(region), code_item);
+  }
 }
 
 void CodeGenerator::RecordPcInfo(HInstruction* instruction,
@@ -705,6 +760,46 @@
 
   EmitEnvironment(instruction->GetEnvironment(), slow_path);
   stack_map_stream_.EndStackMapEntry();
+
+  HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
+  if (instruction->IsSuspendCheck() &&
+      (info != nullptr) &&
+      graph_->IsCompilingOsr() &&
+      (inlining_depth == 0)) {
+    DCHECK_EQ(info->GetSuspendCheck(), instruction);
+    // We duplicate the stack map as a marker that this stack map can be an OSR entry.
+    // Duplicating it avoids having the runtime recognize and skip an OSR stack map.
+    DCHECK(info->IsIrreducible());
+    stack_map_stream_.BeginStackMapEntry(
+        dex_pc, native_pc, register_mask, locations->GetStackMask(), outer_environment_size, 0);
+    EmitEnvironment(instruction->GetEnvironment(), slow_path);
+    stack_map_stream_.EndStackMapEntry();
+    if (kIsDebugBuild) {
+      HEnvironment* environment = instruction->GetEnvironment();
+      for (size_t i = 0, environment_size = environment->Size(); i < environment_size; ++i) {
+        HInstruction* in_environment = environment->GetInstructionAt(i);
+        if (in_environment != nullptr) {
+          DCHECK(in_environment->IsPhi() || in_environment->IsConstant());
+          Location location = environment->GetLocationAt(i);
+          DCHECK(location.IsStackSlot() ||
+                 location.IsDoubleStackSlot() ||
+                 location.IsConstant() ||
+                 location.IsInvalid());
+          if (location.IsStackSlot() || location.IsDoubleStackSlot()) {
+            DCHECK_LT(location.GetStackIndex(), static_cast<int32_t>(GetFrameSize()));
+          }
+        }
+      }
+    }
+  } else if (kIsDebugBuild) {
+    // Ensure stack maps are unique, by checking that the native pc in the stack map
+    // last emitted is different than the native pc of the stack map just emitted.
+    size_t number_of_stack_maps = stack_map_stream_.GetNumberOfStackMaps();
+    if (number_of_stack_maps > 1) {
+      DCHECK_NE(stack_map_stream_.GetStackMap(number_of_stack_maps - 1).native_pc_offset,
+                stack_map_stream_.GetStackMap(number_of_stack_maps - 2).native_pc_offset);
+    }
+  }
 }
 
 bool CodeGenerator::HasStackMapAtCurrentPc() {
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 4f8f146..49c193e 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -187,7 +187,6 @@
   virtual void GenerateFrameEntry() = 0;
   virtual void GenerateFrameExit() = 0;
   virtual void Bind(HBasicBlock* block) = 0;
-  virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0;
   virtual void MoveConstant(Location destination, int32_t value) = 0;
   virtual void MoveLocation(Location dst, Location src, Primitive::Type dst_type) = 0;
   virtual void AddLocationAsTemp(Location location, LocationSummary* locations) = 0;
@@ -203,7 +202,6 @@
                                 size_t number_of_out_slots,
                                 const ArenaVector<HBasicBlock*>& block_order);
   int32_t GetStackSlot(HLocal* local) const;
-  Location GetTemporaryLocation(HTemporary* temp) const;
 
   uint32_t GetFrameSize() const { return frame_size_; }
   void SetFrameSize(uint32_t size) { frame_size_ = size; }
@@ -288,7 +286,7 @@
     slow_paths_.push_back(slow_path);
   }
 
-  void BuildStackMaps(MemoryRegion region);
+  void BuildStackMaps(MemoryRegion region, const DexFile::CodeItem& code_item);
   size_t ComputeStackMapsSize();
 
   bool IsLeafMethod() const {
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index c2d9edd..87f52c6 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -1195,90 +1195,6 @@
   }
 }
 
-void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
-  LocationSummary* locations = instruction->GetLocations();
-  if (instruction->IsCurrentMethod()) {
-    Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
-  } else if (locations != nullptr && locations->Out().Equals(location)) {
-    return;
-  } 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);
-      if (location.IsRegister()) {
-        __ LoadImmediate(location.AsRegister<Register>(), value);
-      } else {
-        DCHECK(location.IsStackSlot());
-        __ LoadImmediate(IP, value);
-        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
-      }
-    } else {
-      DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName();
-      int64_t value = const_to_move->AsLongConstant()->GetValue();
-      if (location.IsRegisterPair()) {
-        __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value));
-        __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value));
-      } else {
-        DCHECK(location.IsDoubleStackSlot());
-        __ LoadImmediate(IP, Low32Bits(value));
-        __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex());
-        __ LoadImmediate(IP, High32Bits(value));
-        __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize));
-      }
-    }
-  } else if (instruction->IsLoadLocal()) {
-    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
-    switch (instruction->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimFloat:
-        Move32(location, Location::StackSlot(stack_slot));
-        break;
-
-      case Primitive::kPrimLong:
-      case Primitive::kPrimDouble:
-        Move64(location, Location::DoubleStackSlot(stack_slot));
-        break;
-
-      default:
-        LOG(FATAL) << "Unexpected type " << instruction->GetType();
-    }
-  } else if (instruction->IsTemporary()) {
-    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
-    if (temp_location.IsStackSlot()) {
-      Move32(location, temp_location);
-    } else {
-      DCHECK(temp_location.IsDoubleStackSlot());
-      Move64(location, temp_location);
-    }
-  } else {
-    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
-    switch (instruction->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimFloat:
-        Move32(location, locations->Out());
-        break;
-
-      case Primitive::kPrimLong:
-      case Primitive::kPrimDouble:
-        Move64(location, locations->Out());
-        break;
-
-      default:
-        LOG(FATAL) << "Unexpected type " << instruction->GetType();
-    }
-  }
-}
-
 void CodeGeneratorARM::MoveConstant(Location location, int32_t value) {
   DCHECK(location.IsRegister());
   __ LoadImmediate(location.AsRegister<Register>(), value);
@@ -2163,6 +2079,8 @@
   switch (result_type) {
     case Primitive::kPrimByte:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to byte is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimShort:
@@ -2181,6 +2099,8 @@
 
     case Primitive::kPrimShort:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to short is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2265,6 +2185,8 @@
 
     case Primitive::kPrimChar:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to char is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2364,6 +2286,10 @@
   switch (result_type) {
     case Primitive::kPrimByte:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to byte is a result of code transformations.
+          __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 8);
+          break;
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimShort:
@@ -2381,6 +2307,10 @@
 
     case Primitive::kPrimShort:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to short is a result of code transformations.
+          __ sbfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
+          break;
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2482,6 +2412,10 @@
 
     case Primitive::kPrimChar:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to char is a result of code transformations.
+          __ ubfx(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>(), 0, 16);
+          break;
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -3750,6 +3684,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
@@ -3779,6 +3714,13 @@
   Primitive::Type type = compare->InputAt(0)->GetType();
   Condition less_cond;
   switch (type) {
+    case Primitive::kPrimInt: {
+      __ LoadImmediate(out, 0);
+      __ cmp(left.AsRegister<Register>(),
+             ShifterOperand(right.AsRegister<Register>()));  // Signed compare.
+      less_cond = LT;
+      break;
+    }
     case Primitive::kPrimLong: {
       __ cmp(left.AsRegisterPairHigh<Register>(),
              ShifterOperand(right.AsRegisterPairHigh<Register>()));  // Signed compare.
@@ -3808,6 +3750,7 @@
       LOG(FATAL) << "Unexpected compare type " << type;
       UNREACHABLE();
   }
+
   __ b(&done, EQ);
   __ b(&less, less_cond);
 
@@ -4924,14 +4867,6 @@
   }
 }
 
-void LocationsBuilderARM::VisitTemporary(HTemporary* temp) {
-  temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
-  // Nothing to do, this is driven by the code generator.
-}
-
 void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
   LOG(FATAL) << "Unreachable";
 }
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 558c9cf..cfd7a3b 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -307,7 +307,6 @@
   void GenerateFrameEntry() OVERRIDE;
   void GenerateFrameExit() OVERRIDE;
   void Bind(HBasicBlock* block) OVERRIDE;
-  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
   void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 4179fab..435ae5e 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1066,54 +1066,6 @@
   __ Bind(GetLabelOf(block));
 }
 
-void CodeGeneratorARM64::Move(HInstruction* instruction,
-                              Location location,
-                              HInstruction* move_for) {
-  LocationSummary* locations = instruction->GetLocations();
-  Primitive::Type type = instruction->GetType();
-  DCHECK_NE(type, Primitive::kPrimVoid);
-
-  if (instruction->IsCurrentMethod()) {
-    MoveLocation(location,
-                 Location::DoubleStackSlot(kCurrentMethodStackOffset),
-                 Primitive::kPrimVoid);
-  } 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);
-      DCHECK(((instruction->IsIntConstant() || instruction->IsNullConstant()) && dst.Is32Bits()) ||
-             (instruction->IsLongConstant() && dst.Is64Bits()));
-      __ Mov(dst, value);
-    } else {
-      DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
-      UseScratchRegisterScope temps(GetVIXLAssembler());
-      Register temp = (instruction->IsIntConstant() || instruction->IsNullConstant())
-          ? temps.AcquireW()
-          : temps.AcquireX();
-      __ Mov(temp, value);
-      __ Str(temp, StackOperandFrom(location));
-    }
-  } else if (instruction->IsTemporary()) {
-    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
-    MoveLocation(location, temp_location, type);
-  } else if (instruction->IsLoadLocal()) {
-    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
-    if (Primitive::Is64BitType(type)) {
-      MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
-    } else {
-      MoveLocation(location, Location::StackSlot(stack_slot), type);
-    }
-
-  } else {
-    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
-    MoveLocation(location, locations->Out(), type);
-  }
-}
-
 void CodeGeneratorARM64::MoveConstant(Location location, int32_t value) {
   DCHECK(location.IsRegister());
   __ Mov(RegisterFrom(location, Primitive::kPrimInt), value);
@@ -2408,6 +2360,7 @@
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   Primitive::Type in_type = compare->InputAt(0)->GetType();
   switch (in_type) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, ARM64EncodableConstantOrRegister(compare->InputAt(1), compare));
@@ -2436,14 +2389,14 @@
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       Register result = OutputRegister(compare);
       Register left = InputRegisterAt(compare, 0);
       Operand right = InputOperandAt(compare, 1);
-
       __ Cmp(left, right);
-      __ Cset(result, ne);
-      __ Cneg(result, result, lt);
+      __ Cset(result, ne);          // result == +1 if NE or 0 otherwise
+      __ Cneg(result, result, lt);  // result == -1 if LT or unchanged otherwise
       break;
     }
     case Primitive::kPrimFloat:
@@ -2975,30 +2928,128 @@
                         /* false_target */ nullptr);
 }
 
+enum SelectVariant {
+  kCsel,
+  kCselFalseConst,
+  kCselTrueConst,
+  kFcsel,
+};
+
+static inline bool IsConditionOnFloatingPointValues(HInstruction* condition) {
+  return condition->IsCondition() &&
+         Primitive::IsFloatingPointType(condition->InputAt(0)->GetType());
+}
+
+static inline bool IsRecognizedCselConstant(HInstruction* constant) {
+  if (constant->IsConstant()) {
+    int64_t value = Int64FromConstant(constant->AsConstant());
+    if ((value == -1) || (value == 0) || (value == 1)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+static inline SelectVariant GetSelectVariant(HSelect* select) {
+  if (Primitive::IsFloatingPointType(select->GetType())) {
+    return kFcsel;
+  } else if (IsRecognizedCselConstant(select->GetFalseValue())) {
+    return kCselFalseConst;
+  } else if (IsRecognizedCselConstant(select->GetTrueValue())) {
+    return kCselTrueConst;
+  } else {
+    return kCsel;
+  }
+}
+
+static inline bool HasSwappedInputs(SelectVariant variant) {
+  return variant == kCselTrueConst;
+}
+
+static inline Condition GetConditionForSelect(HCondition* condition, SelectVariant variant) {
+  IfCondition cond = HasSwappedInputs(variant) ? condition->GetOppositeCondition()
+                                               : condition->GetCondition();
+  return IsConditionOnFloatingPointValues(condition) ? ARM64FPCondition(cond, condition->IsGtBias())
+                                                     : ARM64Condition(cond);
+}
+
 void LocationsBuilderARM64::VisitSelect(HSelect* select) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
-  if (Primitive::IsFloatingPointType(select->GetType())) {
-    locations->SetInAt(0, Location::RequiresFpuRegister());
-    locations->SetInAt(1, Location::RequiresFpuRegister());
-  } else {
-    locations->SetInAt(0, Location::RequiresRegister());
-    locations->SetInAt(1, Location::RequiresRegister());
+  switch (GetSelectVariant(select)) {
+    case kCsel:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister());
+      break;
+    case kCselFalseConst:
+      locations->SetInAt(0, Location::ConstantLocation(select->InputAt(0)->AsConstant()));
+      locations->SetInAt(1, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresRegister());
+      break;
+    case kCselTrueConst:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::ConstantLocation(select->InputAt(1)->AsConstant()));
+      locations->SetOut(Location::RequiresRegister());
+      break;
+    case kFcsel:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister());
+      break;
   }
   if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
     locations->SetInAt(2, Location::RequiresRegister());
   }
-  locations->SetOut(Location::SameAsFirstInput());
 }
 
 void InstructionCodeGeneratorARM64::VisitSelect(HSelect* select) {
-  LocationSummary* locations = select->GetLocations();
-  vixl::Label false_target;
-  GenerateTestAndBranch(select,
-                        /* condition_input_index */ 2,
-                        /* true_target */ nullptr,
-                        &false_target);
-  codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
-  __ Bind(&false_target);
+  HInstruction* cond = select->GetCondition();
+  SelectVariant variant = GetSelectVariant(select);
+  Condition csel_cond;
+
+  if (IsBooleanValueOrMaterializedCondition(cond)) {
+    if (cond->IsCondition() && cond->GetNext() == select) {
+      // Condition codes set from previous instruction.
+      csel_cond = GetConditionForSelect(cond->AsCondition(), variant);
+    } else {
+      __ Cmp(InputRegisterAt(select, 2), 0);
+      csel_cond = HasSwappedInputs(variant) ? eq : ne;
+    }
+  } else if (IsConditionOnFloatingPointValues(cond)) {
+    Location rhs = cond->GetLocations()->InAt(1);
+    if (rhs.IsConstant()) {
+      DCHECK(IsFloatingPointZeroConstant(rhs.GetConstant()));
+      __ Fcmp(InputFPRegisterAt(cond, 0), 0.0);
+    } else {
+      __ Fcmp(InputFPRegisterAt(cond, 0), InputFPRegisterAt(cond, 1));
+    }
+    csel_cond = GetConditionForSelect(cond->AsCondition(), variant);
+  } else {
+    __ Cmp(InputRegisterAt(cond, 0), InputOperandAt(cond, 1));
+    csel_cond = GetConditionForSelect(cond->AsCondition(), variant);
+  }
+
+  switch (variant) {
+    case kCsel:
+    case kCselFalseConst:
+      __ Csel(OutputRegister(select),
+              InputRegisterAt(select, 1),
+              InputOperandAt(select, 0),
+              csel_cond);
+      break;
+    case kCselTrueConst:
+      __ Csel(OutputRegister(select),
+              InputRegisterAt(select, 0),
+              InputOperandAt(select, 1),
+              csel_cond);
+      break;
+    case kFcsel:
+      __ Fcsel(OutputFPRegister(select),
+               InputFPRegisterAt(select, 1),
+               InputFPRegisterAt(select, 0),
+               csel_cond);
+      break;
+  }
 }
 
 void LocationsBuilderARM64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
@@ -4444,14 +4495,6 @@
   GenerateSuspendCheck(instruction, nullptr);
 }
 
-void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) {
-  temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
-  // Nothing to do, this is driven by the code generator.
-}
-
 void LocationsBuilderARM64::VisitThrow(HThrow* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
@@ -4879,20 +4922,18 @@
     static_assert(
         sizeof(mirror::HeapReference<mirror::Object>) == sizeof(int32_t),
         "art::mirror::HeapReference<art::mirror::Object> and int32_t have different sizes.");
-    temp2 = temps.AcquireW();
     // /* HeapReference<Object> */ ref =
     //     *(obj + offset + index * sizeof(HeapReference<Object>))
-    MemOperand source = HeapOperand(obj);
+    const size_t shift_amount = Primitive::ComponentSizeShift(type);
     if (index.IsConstant()) {
-      uint32_t computed_offset =
-          offset + (Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type));
-      source = HeapOperand(obj, computed_offset);
+      uint32_t computed_offset = offset + (Int64ConstantFrom(index) << shift_amount);
+      Load(type, ref_reg, HeapOperand(obj, computed_offset));
     } else {
+      temp2 = temps.AcquireW();
       __ Add(temp2, obj, offset);
-      source = HeapOperand(temp2, XRegisterFrom(index), LSL, Primitive::ComponentSizeShift(type));
+      Load(type, ref_reg, HeapOperand(temp2, XRegisterFrom(index), LSL, shift_amount));
+      temps.Release(temp2);
     }
-    Load(type, ref_reg, source);
-    temps.Release(temp2);
   } else {
     // /* HeapReference<Object> */ ref = *(obj + offset)
     MemOperand field = HeapOperand(obj, offset);
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index a9d1bbd..360488e 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -350,8 +350,6 @@
     return CommonGetLabelOf<vixl::Label>(block_labels_, block);
   }
 
-  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
-
   size_t GetWordSize() const OVERRIDE {
     return kArm64WordSize;
   }
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 961fe62..3eda863 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -976,46 +976,6 @@
   __ LoadConst32(dst, value);
 }
 
-void CodeGeneratorMIPS::Move(HInstruction* instruction,
-                             Location location,
-                             HInstruction* move_for) {
-  LocationSummary* locations = instruction->GetLocations();
-  Primitive::Type type = instruction->GetType();
-  DCHECK_NE(type, Primitive::kPrimVoid);
-
-  if (instruction->IsCurrentMethod()) {
-    Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
-  } else if (locations != nullptr && locations->Out().Equals(location)) {
-    return;
-  } else if (instruction->IsIntConstant()
-             || instruction->IsLongConstant()
-             || instruction->IsNullConstant()) {
-    MoveConstant(location, instruction->AsConstant());
-  } else if (instruction->IsTemporary()) {
-    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
-    if (temp_location.IsStackSlot()) {
-      Move32(location, temp_location);
-    } else {
-      DCHECK(temp_location.IsDoubleStackSlot());
-      Move64(location, temp_location);
-    }
-  } else if (instruction->IsLoadLocal()) {
-    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
-    if (Primitive::Is64BitType(type)) {
-      Move64(location, Location::DoubleStackSlot(stack_slot));
-    } else {
-      Move32(location, Location::StackSlot(stack_slot));
-    }
-  } else {
-    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
-    if (Primitive::Is64BitType(type)) {
-      Move64(location, locations->Out());
-    } else {
-      Move32(location, locations->Out());
-    }
-  }
-}
-
 void CodeGeneratorMIPS::AddLocationAsTemp(Location location, LocationSummary* locations) {
   if (location.IsRegister()) {
     locations->AddTemp(location);
@@ -2123,6 +2083,7 @@
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
 
   switch (in_type) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RequiresRegister());
@@ -2153,6 +2114,14 @@
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
+    case Primitive::kPrimInt: {
+      Register lhs = locations->InAt(0).AsRegister<Register>();
+      Register rhs = locations->InAt(1).AsRegister<Register>();
+      __ Slt(TMP, lhs, rhs);
+      __ Slt(res, rhs, lhs);
+      __ Subu(res, res, TMP);
+      break;
+    }
     case Primitive::kPrimLong: {
       MipsLabel done;
       Register lhs_high = locations->InAt(0).AsRegisterPairHigh<Register>();
@@ -4786,14 +4755,6 @@
   GenerateSuspendCheck(instruction, nullptr);
 }
 
-void LocationsBuilderMIPS::VisitTemporary(HTemporary* temp) {
-  temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorMIPS::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
-  // Nothing to do, this is driven by the code generator.
-}
-
 void LocationsBuilderMIPS::VisitThrow(HThrow* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 2cde0ed..12964b0 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -268,7 +268,6 @@
 
   void Bind(HBasicBlock* block) OVERRIDE;
 
-  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
   void Move32(Location destination, Location source);
   void Move64(Location destination, Location source);
   void MoveConstant(Location location, HConstant* c);
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 3e1563c..119084e 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -869,65 +869,6 @@
   }
 }
 
-void CodeGeneratorMIPS64::Move(HInstruction* instruction,
-                               Location location,
-                               HInstruction* move_for) {
-  LocationSummary* locations = instruction->GetLocations();
-  Primitive::Type type = instruction->GetType();
-  DCHECK_NE(type, Primitive::kPrimVoid);
-
-  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>();
-      if (instruction->IsNullConstant() || instruction->IsIntConstant()) {
-        __ LoadConst32(dst, GetInt32ValueOf(instruction->AsConstant()));
-      } else {
-        __ LoadConst64(dst, instruction->AsLongConstant()->GetValue());
-      }
-    } else {
-      DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot());
-      // Move to stack from constant
-      GpuRegister gpr = ZERO;
-      if (location.IsStackSlot()) {
-        int32_t value = GetInt32ValueOf(instruction->AsConstant());
-        if (value != 0) {
-          gpr = TMP;
-          __ LoadConst32(gpr, value);
-        }
-        __ StoreToOffset(kStoreWord, gpr, SP, location.GetStackIndex());
-      } else {
-        DCHECK(location.IsDoubleStackSlot());
-        int64_t value = instruction->AsLongConstant()->GetValue();
-        if (value != 0) {
-          gpr = TMP;
-          __ LoadConst64(gpr, value);
-        }
-        __ StoreToOffset(kStoreDoubleword, gpr, SP, location.GetStackIndex());
-      }
-    }
-  } else if (instruction->IsTemporary()) {
-    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
-    MoveLocation(location, temp_location, type);
-  } else if (instruction->IsLoadLocal()) {
-    uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
-    if (Primitive::Is64BitType(type)) {
-      MoveLocation(location, Location::DoubleStackSlot(stack_slot), type);
-    } else {
-      MoveLocation(location, Location::StackSlot(stack_slot), type);
-    }
-  } else {
-    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
-    MoveLocation(location, locations->Out(), type);
-  }
-}
-
 void CodeGeneratorMIPS64::MoveConstant(Location location, int32_t value) {
   DCHECK(location.IsRegister());
   __ LoadConst32(location.AsRegister<GpuRegister>(), value);
@@ -1763,6 +1704,7 @@
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
 
   switch (in_type) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong:
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::RegisterOrConstant(compare->InputAt(1)));
@@ -1791,16 +1733,25 @@
   //  1 if: left  > right
   // -1 if: left  < right
   switch (in_type) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       GpuRegister lhs = locations->InAt(0).AsRegister<GpuRegister>();
       Location rhs_location = locations->InAt(1);
       bool use_imm = rhs_location.IsConstant();
       GpuRegister rhs = ZERO;
       if (use_imm) {
-        int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
-        if (value != 0) {
-          rhs = AT;
-          __ LoadConst64(rhs, value);
+        if (in_type == Primitive::kPrimInt) {
+          int32_t value = CodeGenerator::GetInt32ValueOf(rhs_location.GetConstant()->AsConstant());
+          if (value != 0) {
+            rhs = AT;
+            __ LoadConst32(rhs, value);
+          }
+        } else {
+          int64_t value = CodeGenerator::GetInt64ValueOf(rhs_location.GetConstant()->AsConstant());
+          if (value != 0) {
+            rhs = AT;
+            __ LoadConst64(rhs, value);
+          }
         }
       } else {
         rhs = rhs_location.AsRegister<GpuRegister>();
@@ -3936,14 +3887,6 @@
   GenerateSuspendCheck(instruction, nullptr);
 }
 
-void LocationsBuilderMIPS64::VisitTemporary(HTemporary* temp) {
-  temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorMIPS64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
-  // Nothing to do, this is driven by the code generator.
-}
-
 void LocationsBuilderMIPS64::VisitThrow(HThrow* instruction) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
@@ -4000,18 +3943,26 @@
         __ Andi(dst, src, 0xFFFF);
         break;
       case Primitive::kPrimByte:
-        // long is never converted into types narrower than int directly,
-        // so SEB and SEH can be used without ever causing unpredictable results
-        // on 64-bit inputs
-        DCHECK(input_type != Primitive::kPrimLong);
-        __ Seb(dst, src);
+        if (input_type == Primitive::kPrimLong) {
+          // Type conversion from long to types narrower than int is a result of code
+          // transformations. To avoid unpredictable results for SEB and SEH, we first
+          // need to sign-extend the low 32-bit value into bits 32 through 63.
+          __ Sll(dst, src, 0);
+          __ Seb(dst, dst);
+        } else {
+          __ Seb(dst, src);
+        }
         break;
       case Primitive::kPrimShort:
-        // long is never converted into types narrower than int directly,
-        // so SEB and SEH can be used without ever causing unpredictable results
-        // on 64-bit inputs
-        DCHECK(input_type != Primitive::kPrimLong);
-        __ Seh(dst, src);
+        if (input_type == Primitive::kPrimLong) {
+          // Type conversion from long to types narrower than int is a result of code
+          // transformations. To avoid unpredictable results for SEB and SEH, we first
+          // need to sign-extend the low 32-bit value into bits 32 through 63.
+          __ Sll(dst, src, 0);
+          __ Seh(dst, dst);
+        } else {
+          __ Seh(dst, src);
+        }
         break;
       case Primitive::kPrimInt:
       case Primitive::kPrimLong:
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index c836f83..1161253 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -268,8 +268,6 @@
 
   void Bind(HBasicBlock* block) OVERRIDE;
 
-  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
-
   size_t GetWordSize() const OVERRIDE { return kMips64DoublewordSize; }
 
   size_t GetFloatingPointSpillSlotSize() const OVERRIDE { return kMips64DoublewordSize; }
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index da054ba..3c880c2 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1127,91 +1127,6 @@
   }
 }
 
-void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
-  LocationSummary* locations = instruction->GetLocations();
-  if (instruction->IsCurrentMethod()) {
-    Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
-  } else if (locations != nullptr && locations->Out().Equals(location)) {
-    return;
-  } 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));
-      if (location.IsRegister()) {
-        __ movl(location.AsRegister<Register>(), imm);
-      } else if (location.IsStackSlot()) {
-        __ movl(Address(ESP, location.GetStackIndex()), imm);
-      } else {
-        DCHECK(location.IsConstant());
-        DCHECK_EQ(location.GetConstant(), const_to_move);
-      }
-    } else if (const_to_move->IsLongConstant()) {
-      int64_t value = const_to_move->AsLongConstant()->GetValue();
-      if (location.IsRegisterPair()) {
-        __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
-        __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
-      } else if (location.IsDoubleStackSlot()) {
-        __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
-        __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
-                Immediate(High32Bits(value)));
-      } else {
-        DCHECK(location.IsConstant());
-        DCHECK_EQ(location.GetConstant(), instruction);
-      }
-    }
-  } else if (instruction->IsTemporary()) {
-    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
-    if (temp_location.IsStackSlot()) {
-      Move32(location, temp_location);
-    } else {
-      DCHECK(temp_location.IsDoubleStackSlot());
-      Move64(location, temp_location);
-    }
-  } else if (instruction->IsLoadLocal()) {
-    int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
-    switch (instruction->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimFloat:
-        Move32(location, Location::StackSlot(slot));
-        break;
-
-      case Primitive::kPrimLong:
-      case Primitive::kPrimDouble:
-        Move64(location, Location::DoubleStackSlot(slot));
-        break;
-
-      default:
-        LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
-    }
-  } else {
-    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
-    switch (instruction->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimFloat:
-        Move32(location, locations->Out());
-        break;
-
-      case Primitive::kPrimLong:
-      case Primitive::kPrimDouble:
-        Move64(location, locations->Out());
-        break;
-
-      default:
-        LOG(FATAL) << "Unexpected type " << instruction->GetType();
-    }
-  }
-}
-
 void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
   DCHECK(location.IsRegister());
   __ movl(location.AsRegister<Register>(), Immediate(value));
@@ -1350,11 +1265,7 @@
     int32_t val_high = High32Bits(value);
     int32_t val_low = Low32Bits(value);
 
-    if (val_high == 0) {
-      __ testl(left_high, left_high);
-    } else {
-      __ cmpl(left_high, Immediate(val_high));
-    }
+    codegen_->Compare32BitValue(left_high, val_high);
     if (if_cond == kCondNE) {
       __ j(X86Condition(true_high_cond), true_label);
     } else if (if_cond == kCondEQ) {
@@ -1364,12 +1275,8 @@
       __ 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 {
+    codegen_->Compare32BitValue(left_low, val_low);
+  } else if (right.IsRegisterPair()) {
     Register right_high = right.AsRegisterPairHigh<Register>();
     Register right_low = right.AsRegisterPairLow<Register>();
 
@@ -1384,11 +1291,58 @@
     }
     // Must be equal high, so compare the lows.
     __ cmpl(left_low, right_low);
+  } else {
+    DCHECK(right.IsDoubleStackSlot());
+    __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
+    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, Address(ESP, right.GetStackIndex()));
   }
   // The last comparison might be unsigned.
   __ j(final_condition, true_label);
 }
 
+void InstructionCodeGeneratorX86::GenerateFPCompare(Location lhs,
+                                                    Location rhs,
+                                                    HInstruction* insn,
+                                                    bool is_double) {
+  HX86LoadFromConstantTable* const_area = insn->InputAt(1)->AsX86LoadFromConstantTable();
+  if (is_double) {
+    if (rhs.IsFpuRegister()) {
+      __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+    } else if (const_area != nullptr) {
+      DCHECK(const_area->IsEmittedAtUseSite());
+      __ ucomisd(lhs.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralDoubleAddress(
+                   const_area->GetConstant()->AsDoubleConstant()->GetValue(),
+                   const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+    } else {
+      DCHECK(rhs.IsDoubleStackSlot());
+      __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex()));
+    }
+  } else {
+    if (rhs.IsFpuRegister()) {
+      __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+    } else if (const_area != nullptr) {
+      DCHECK(const_area->IsEmittedAtUseSite());
+      __ ucomiss(lhs.AsFpuRegister<XmmRegister>(),
+                 codegen_->LiteralFloatAddress(
+                   const_area->GetConstant()->AsFloatConstant()->GetValue(),
+                   const_area->GetLocations()->InAt(0).AsRegister<Register>()));
+    } else {
+      DCHECK(rhs.IsStackSlot());
+      __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), Address(ESP, rhs.GetStackIndex()));
+    }
+  }
+}
+
 template<class LabelType>
 void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HCondition* condition,
                                                                LabelType* true_target_in,
@@ -1409,11 +1363,11 @@
       GenerateLongComparesAndJumps(condition, true_target, false_target);
       break;
     case Primitive::kPrimFloat:
-      __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPCompare(left, right, condition, false);
       GenerateFPJumps(condition, true_target, false_target);
       break;
     case Primitive::kPrimDouble:
-      __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPCompare(left, right, condition, true);
       GenerateFPJumps(condition, true_target, false_target);
       break;
     default:
@@ -1513,11 +1467,7 @@
       __ 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));
-      }
+      codegen_->Compare32BitValue(lhs.AsRegister<Register>(), constant);
     } else {
       __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
     }
@@ -1656,7 +1606,7 @@
   switch (cond->InputAt(0)->GetType()) {
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
-      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
+      locations->SetInAt(1, Location::Any());
       if (!cond->IsEmittedAtUseSite()) {
         locations->SetOut(Location::RequiresRegister());
       }
@@ -1665,7 +1615,13 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::RequiresFpuRegister());
+      if (cond->InputAt(1)->IsX86LoadFromConstantTable()) {
+        DCHECK(cond->InputAt(1)->IsEmittedAtUseSite());
+      } else if (cond->InputAt(1)->IsConstant()) {
+        locations->SetInAt(1, Location::RequiresFpuRegister());
+      } else {
+        locations->SetInAt(1, Location::Any());
+      }
       if (!cond->IsEmittedAtUseSite()) {
         locations->SetOut(Location::RequiresRegister());
       }
@@ -1704,11 +1660,7 @@
         __ 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));
-        }
+        codegen_->Compare32BitValue(lhs.AsRegister<Register>(), constant);
       } else {
         __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
       }
@@ -1719,11 +1671,11 @@
       GenerateLongComparesAndJumps(cond, &true_label, &false_label);
       break;
     case Primitive::kPrimFloat:
-      __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+      GenerateFPCompare(lhs, rhs, cond, false);
       GenerateFPJumps(cond, &true_label, &false_label);
       break;
     case Primitive::kPrimDouble:
-      __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+      GenerateFPCompare(lhs, rhs, cond, true);
       GenerateFPJumps(cond, &true_label, &false_label);
       break;
   }
@@ -2159,6 +2111,32 @@
   }
 }
 
+void LocationsBuilderX86::VisitX86FPNeg(HX86FPNeg* neg) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
+  DCHECK(Primitive::IsFloatingPointType(neg->GetType()));
+  locations->SetInAt(0, Location::RequiresFpuRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::SameAsFirstInput());
+  locations->AddTemp(Location::RequiresFpuRegister());
+}
+
+void InstructionCodeGeneratorX86::VisitX86FPNeg(HX86FPNeg* neg) {
+  LocationSummary* locations = neg->GetLocations();
+  Location out = locations->Out();
+  DCHECK(locations->InAt(0).Equals(out));
+
+  Register constant_area = locations->InAt(1).AsRegister<Register>();
+  XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+  if (neg->GetType() == Primitive::kPrimFloat) {
+    __ movss(mask, codegen_->LiteralInt32Address(INT32_C(0x80000000), constant_area));
+    __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
+  } else {
+     __ movsd(mask, codegen_->LiteralInt64Address(INT64_C(0x8000000000000000), constant_area));
+     __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
+  }
+}
+
 void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
   Primitive::Type result_type = conversion->GetResultType();
   Primitive::Type input_type = conversion->GetInputType();
@@ -2180,6 +2158,18 @@
   switch (result_type) {
     case Primitive::kPrimByte:
       switch (input_type) {
+        case Primitive::kPrimLong: {
+          // Type conversion from long to byte is a result of code transformations.
+          HInstruction* input = conversion->InputAt(0);
+          Location input_location = input->IsConstant()
+              ? Location::ConstantLocation(input->AsConstant())
+              : Location::RegisterPairLocation(EAX, EDX);
+          locations->SetInAt(0, input_location);
+          // Make the output overlap to please the register allocator. This greatly simplifies
+          // the validation of the linear scan implementation
+          locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
+          break;
+        }
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimShort:
@@ -2200,6 +2190,8 @@
 
     case Primitive::kPrimShort:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to short is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2277,6 +2269,8 @@
 
     case Primitive::kPrimChar:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to char is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2371,6 +2365,16 @@
   switch (result_type) {
     case Primitive::kPrimByte:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to byte is a result of code transformations.
+          if (in.IsRegisterPair()) {
+            __ movsxb(out.AsRegister<Register>(), in.AsRegisterPairLow<ByteRegister>());
+          } else {
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
+          }
+          break;
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimShort:
@@ -2394,6 +2398,18 @@
 
     case Primitive::kPrimShort:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to short is a result of code transformations.
+          if (in.IsRegisterPair()) {
+            __ movsxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
+          }
+          break;
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2530,6 +2546,18 @@
 
     case Primitive::kPrimChar:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to short is a result of code transformations.
+          if (in.IsRegisterPair()) {
+            __ movzxw(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
+          } else if (in.IsDoubleStackSlot()) {
+            __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
+          } else {
+            DCHECK(in.GetConstant()->IsLongConstant());
+            int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
+            __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
+          }
+          break;
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -4077,6 +4105,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
@@ -4086,7 +4115,13 @@
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble: {
       locations->SetInAt(0, Location::RequiresFpuRegister());
-      locations->SetInAt(1, Location::RequiresFpuRegister());
+      if (compare->InputAt(1)->IsX86LoadFromConstantTable()) {
+        DCHECK(compare->InputAt(1)->IsEmittedAtUseSite());
+      } else if (compare->InputAt(1)->IsConstant()) {
+        locations->SetInAt(1, Location::RequiresFpuRegister());
+      } else {
+        locations->SetInAt(1, Location::Any());
+      }
       locations->SetOut(Location::RequiresRegister());
       break;
     }
@@ -4102,7 +4137,21 @@
   Location right = locations->InAt(1);
 
   NearLabel less, greater, done;
+  Condition less_cond = kLess;
+
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimInt: {
+      Register left_reg = left.AsRegister<Register>();
+      if (right.IsConstant()) {
+        int32_t value = right.GetConstant()->AsIntConstant()->GetValue();
+        codegen_->Compare32BitValue(left_reg, value);
+      } else if (right.IsStackSlot()) {
+        __ cmpl(left_reg, Address(ESP, right.GetStackIndex()));
+      } else {
+        __ cmpl(left_reg, right.AsRegister<Register>());
+      }
+      break;
+    }
     case Primitive::kPrimLong: {
       Register left_low = left.AsRegisterPairLow<Register>();
       Register left_high = left.AsRegisterPairHigh<Register>();
@@ -4124,11 +4173,7 @@
         __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
       } else {
         DCHECK(right_is_const) << right;
-        if (val_high == 0) {
-          __ testl(left_high, left_high);
-        } else {
-          __ cmpl(left_high, Immediate(val_high));
-        }
+        codegen_->Compare32BitValue(left_high, val_high);
       }
       __ j(kLess, &less);  // Signed compare.
       __ j(kGreater, &greater);  // Signed compare.
@@ -4138,30 +4183,30 @@
         __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
       } else {
         DCHECK(right_is_const) << right;
-        if (val_low == 0) {
-          __ testl(left_low, left_low);
-        } else {
-          __ cmpl(left_low, Immediate(val_low));
-        }
+        codegen_->Compare32BitValue(left_low, val_low);
       }
+      less_cond = kBelow;  // for CF (unsigned).
       break;
     }
     case Primitive::kPrimFloat: {
-      __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPCompare(left, right, compare, false);
       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      less_cond = kBelow;  // for CF (floats).
       break;
     }
     case Primitive::kPrimDouble: {
-      __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPCompare(left, right, compare, true);
       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      less_cond = kBelow;  // for CF (floats).
       break;
     }
     default:
       LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
   }
+
   __ movl(out, Immediate(0));
   __ j(kEqual, &done);
-  __ j(kBelow, &less);  // kBelow is for CF (unsigned & floats).
+  __ j(less_cond, &less);
 
   __ Bind(&greater);
   __ movl(out, Immediate(1));
@@ -5446,14 +5491,6 @@
   }
 }
 
-void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
-  temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
-  // Nothing to do, this is driven by the code generator.
-}
-
 void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
   LOG(FATAL) << "Unreachable";
 }
@@ -7121,6 +7158,22 @@
   return Address(reg, kDummy32BitOffset, fixup);
 }
 
+void CodeGeneratorX86::Load32BitValue(Register dest, int32_t value) {
+  if (value == 0) {
+    __ xorl(dest, dest);
+  } else {
+    __ movl(dest, Immediate(value));
+  }
+}
+
+void CodeGeneratorX86::Compare32BitValue(Register dest, int32_t value) {
+  if (value == 0) {
+    __ testl(dest, dest);
+  } else {
+    __ cmpl(dest, Immediate(value));
+  }
+}
+
 Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr,
                                            Register reg,
                                            Register value) {
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 0aef478..2fb6d60 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -296,6 +296,8 @@
                                    HBasicBlock* switch_block,
                                    HBasicBlock* default_block);
 
+  void GenerateFPCompare(Location lhs, Location rhs, HInstruction* insn, bool is_double);
+
   X86Assembler* const assembler_;
   CodeGeneratorX86* const codegen_;
 
@@ -315,7 +317,6 @@
   void GenerateFrameEntry() OVERRIDE;
   void GenerateFrameExit() OVERRIDE;
   void Bind(HBasicBlock* block) OVERRIDE;
-  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
   void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
@@ -450,6 +451,12 @@
   Address LiteralInt32Address(int32_t v, Register reg);
   Address LiteralInt64Address(int64_t v, Register reg);
 
+  // Load a 32-bit value into a register in the most efficient manner.
+  void Load32BitValue(Register dest, int32_t value);
+
+  // Compare a register with a 32-bit value in the most efficient manner.
+  void Compare32BitValue(Register dest, int32_t value);
+
   Address LiteralCaseTable(HX86PackedSwitch* switch_instr, Register reg, Register value);
 
   void Finalize(CodeAllocator* allocator) OVERRIDE;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 6795488..a53a6be 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1126,30 +1126,43 @@
     return;
   }
   if (destination.IsRegister()) {
+    CpuRegister dest = destination.AsRegister<CpuRegister>();
     if (source.IsRegister()) {
-      __ movq(destination.AsRegister<CpuRegister>(), source.AsRegister<CpuRegister>());
+      __ movq(dest, source.AsRegister<CpuRegister>());
     } else if (source.IsFpuRegister()) {
-      __ movd(destination.AsRegister<CpuRegister>(), source.AsFpuRegister<XmmRegister>());
+      __ movd(dest, source.AsFpuRegister<XmmRegister>());
     } else if (source.IsStackSlot()) {
-      __ movl(destination.AsRegister<CpuRegister>(),
-              Address(CpuRegister(RSP), source.GetStackIndex()));
+      __ movl(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
+    } else if (source.IsConstant()) {
+      HConstant* constant = source.GetConstant();
+      if (constant->IsLongConstant()) {
+        Load64BitValue(dest, constant->AsLongConstant()->GetValue());
+      } else {
+        Load32BitValue(dest, GetInt32ValueOf(constant));
+      }
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      __ movq(destination.AsRegister<CpuRegister>(),
-              Address(CpuRegister(RSP), source.GetStackIndex()));
+      __ movq(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
     }
   } else if (destination.IsFpuRegister()) {
+    XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
     if (source.IsRegister()) {
-      __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<CpuRegister>());
+      __ movd(dest, source.AsRegister<CpuRegister>());
     } else if (source.IsFpuRegister()) {
-      __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
+      __ movaps(dest, source.AsFpuRegister<XmmRegister>());
+    } else if (source.IsConstant()) {
+      HConstant* constant = source.GetConstant();
+      int64_t value = CodeGenerator::GetInt64ValueOf(constant);
+      if (constant->IsFloatConstant()) {
+        Load32BitValue(dest, static_cast<int32_t>(value));
+      } else {
+        Load64BitValue(dest, value);
+      }
     } else if (source.IsStackSlot()) {
-      __ movss(destination.AsFpuRegister<XmmRegister>(),
-              Address(CpuRegister(RSP), source.GetStackIndex()));
+      __ movss(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
     } else {
       DCHECK(source.IsDoubleStackSlot());
-      __ movsd(destination.AsFpuRegister<XmmRegister>(),
-               Address(CpuRegister(RSP), source.GetStackIndex()));
+      __ movsd(dest, Address(CpuRegister(RSP), source.GetStackIndex()));
     }
   } else if (destination.IsStackSlot()) {
     if (source.IsRegister()) {
@@ -1193,82 +1206,6 @@
   }
 }
 
-void CodeGeneratorX86_64::Move(HInstruction* instruction,
-                               Location location,
-                               HInstruction* move_for) {
-  LocationSummary* locations = instruction->GetLocations();
-  if (instruction->IsCurrentMethod()) {
-    Move(location, Location::DoubleStackSlot(kCurrentMethodStackOffset));
-  } else if (locations != nullptr && locations->Out().Equals(location)) {
-    return;
-  } 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));
-      if (location.IsRegister()) {
-        __ movl(location.AsRegister<CpuRegister>(), imm);
-      } else if (location.IsStackSlot()) {
-        __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
-      } else {
-        DCHECK(location.IsConstant());
-        DCHECK_EQ(location.GetConstant(), const_to_move);
-      }
-    } else if (const_to_move->IsLongConstant()) {
-      int64_t value = const_to_move->AsLongConstant()->GetValue();
-      if (location.IsRegister()) {
-        Load64BitValue(location.AsRegister<CpuRegister>(), value);
-      } else if (location.IsDoubleStackSlot()) {
-        Store64BitValueToStack(location, value);
-      } else {
-        DCHECK(location.IsConstant());
-        DCHECK_EQ(location.GetConstant(), const_to_move);
-      }
-    }
-  } else if (instruction->IsLoadLocal()) {
-    switch (instruction->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimFloat:
-        Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
-        break;
-
-      case Primitive::kPrimLong:
-      case Primitive::kPrimDouble:
-        Move(location,
-             Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
-        break;
-
-      default:
-        LOG(FATAL) << "Unexpected local type " << instruction->GetType();
-    }
-  } else if (instruction->IsTemporary()) {
-    Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
-    Move(location, temp_location);
-  } else {
-    DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
-    switch (instruction->GetType()) {
-      case Primitive::kPrimBoolean:
-      case Primitive::kPrimByte:
-      case Primitive::kPrimChar:
-      case Primitive::kPrimShort:
-      case Primitive::kPrimInt:
-      case Primitive::kPrimNot:
-      case Primitive::kPrimLong:
-      case Primitive::kPrimFloat:
-      case Primitive::kPrimDouble:
-        Move(location, locations->Out());
-        break;
-
-      default:
-        LOG(FATAL) << "Unexpected type " << instruction->GetType();
-    }
-  }
-}
-
 void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) {
   DCHECK(location.IsRegister());
   Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value));
@@ -1345,42 +1282,44 @@
   __ j(X86_64FPCondition(cond->GetCondition()), true_label);
 }
 
-template<class LabelType>
-void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition,
-                                                                  LabelType* true_target_in,
-                                                                  LabelType* false_target_in) {
-  // Generated branching requires both targets to be explicit. If either of the
-  // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
-  LabelType fallthrough_target;
-  LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
-  LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
-
+void InstructionCodeGeneratorX86_64::GenerateCompareTest(HCondition* condition) {
   LocationSummary* locations = condition->GetLocations();
+
   Location left = locations->InAt(0);
   Location right = locations->InAt(1);
-
   Primitive::Type type = condition->InputAt(0)->GetType();
   switch (type) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+    case Primitive::kPrimNot: {
+      CpuRegister left_reg = left.AsRegister<CpuRegister>();
+      if (right.IsConstant()) {
+        int32_t value = CodeGenerator::GetInt32ValueOf(right.GetConstant());
+        if (value == 0) {
+          __ testl(left_reg, left_reg);
+        } else {
+          __ cmpl(left_reg, Immediate(value));
+        }
+      } else if (right.IsStackSlot()) {
+        __ cmpl(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
+      } else {
+        __ cmpl(left_reg, right.AsRegister<CpuRegister>());
+      }
+      break;
+    }
     case Primitive::kPrimLong: {
       CpuRegister left_reg = left.AsRegister<CpuRegister>();
       if (right.IsConstant()) {
         int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
-        if (IsInt<32>(value)) {
-          if (value == 0) {
-            __ testq(left_reg, left_reg);
-          } else {
-            __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
-          }
-        } else {
-          // Value won't fit in a 32-bit integer.
-          __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
-        }
+        codegen_->Compare64BitValue(left_reg, value);
       } else if (right.IsDoubleStackSlot()) {
         __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
       } else {
         __ cmpq(left_reg, right.AsRegister<CpuRegister>());
       }
-      __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
       break;
     }
     case Primitive::kPrimFloat: {
@@ -1395,7 +1334,6 @@
         __ ucomiss(left.AsFpuRegister<XmmRegister>(),
                    Address(CpuRegister(RSP), right.GetStackIndex()));
       }
-      GenerateFPJumps(condition, true_target, false_target);
       break;
     }
     case Primitive::kPrimDouble: {
@@ -1410,6 +1348,38 @@
         __ ucomisd(left.AsFpuRegister<XmmRegister>(),
                    Address(CpuRegister(RSP), right.GetStackIndex()));
       }
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected condition type " << type;
+  }
+}
+
+template<class LabelType>
+void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HCondition* condition,
+                                                                  LabelType* true_target_in,
+                                                                  LabelType* false_target_in) {
+  // Generated branching requires both targets to be explicit. If either of the
+  // targets is nullptr (fallthrough) use and bind `fallthrough_target` instead.
+  LabelType fallthrough_target;
+  LabelType* true_target = true_target_in == nullptr ? &fallthrough_target : true_target_in;
+  LabelType* false_target = false_target_in == nullptr ? &fallthrough_target : false_target_in;
+
+  // Generate the comparison to set the CC.
+  GenerateCompareTest(condition);
+
+  // Now generate the correct jump(s).
+  Primitive::Type type = condition->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong: {
+      __ j(X86_64IntegerCondition(condition->GetCondition()), true_target);
+      break;
+    }
+    case Primitive::kPrimFloat: {
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    }
+    case Primitive::kPrimDouble: {
       GenerateFPJumps(condition, true_target, false_target);
       break;
     }
@@ -1508,11 +1478,7 @@
       __ 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));
-      }
+      codegen_->Compare32BitValue(lhs.AsRegister<CpuRegister>(), constant);
     } else {
       __ cmpl(lhs.AsRegister<CpuRegister>(),
               Address(CpuRegister(RSP), rhs.GetStackIndex()));
@@ -1564,14 +1530,39 @@
                                /* false_target */ nullptr);
 }
 
+static bool SelectCanUseCMOV(HSelect* select) {
+  // There are no conditional move instructions for XMMs.
+  if (Primitive::IsFloatingPointType(select->GetType())) {
+    return false;
+  }
+
+  // A FP condition doesn't generate the single CC that we need.
+  HInstruction* condition = select->GetCondition();
+  if (condition->IsCondition() &&
+      Primitive::IsFloatingPointType(condition->InputAt(0)->GetType())) {
+    return false;
+  }
+
+  // We can generate a CMOV for this Select.
+  return true;
+}
+
 void LocationsBuilderX86_64::VisitSelect(HSelect* select) {
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(select);
   if (Primitive::IsFloatingPointType(select->GetType())) {
     locations->SetInAt(0, Location::RequiresFpuRegister());
-    locations->SetInAt(1, Location::RequiresFpuRegister());
+    locations->SetInAt(1, Location::Any());
   } else {
     locations->SetInAt(0, Location::RequiresRegister());
-    locations->SetInAt(1, Location::RequiresRegister());
+    if (SelectCanUseCMOV(select)) {
+      if (select->InputAt(1)->IsConstant()) {
+        locations->SetInAt(1, Location::RequiresRegister());
+      } else {
+        locations->SetInAt(1, Location::Any());
+      }
+    } else {
+      locations->SetInAt(1, Location::Any());
+    }
   }
   if (IsBooleanValueOrMaterializedCondition(select->GetCondition())) {
     locations->SetInAt(2, Location::RequiresRegister());
@@ -1581,13 +1572,59 @@
 
 void InstructionCodeGeneratorX86_64::VisitSelect(HSelect* select) {
   LocationSummary* locations = select->GetLocations();
-  NearLabel false_target;
-  GenerateTestAndBranch<NearLabel>(select,
-                                   /* condition_input_index */ 2,
-                                   /* true_target */ nullptr,
-                                   &false_target);
-  codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
-  __ Bind(&false_target);
+  if (SelectCanUseCMOV(select)) {
+    // If both the condition and the source types are integer, we can generate
+    // a CMOV to implement Select.
+    CpuRegister value_false = locations->InAt(0).AsRegister<CpuRegister>();
+    Location value_true_loc = locations->InAt(1);
+    DCHECK(locations->InAt(0).Equals(locations->Out()));
+
+    HInstruction* select_condition = select->GetCondition();
+    Condition cond = kNotEqual;
+
+    // Figure out how to test the 'condition'.
+    if (select_condition->IsCondition()) {
+      HCondition* condition = select_condition->AsCondition();
+      if (!condition->IsEmittedAtUseSite()) {
+        // This was a previously materialized condition.
+        // Can we use the existing condition code?
+        if (AreEflagsSetFrom(condition, select)) {
+          // Materialization was the previous instruction.  Condition codes are right.
+          cond = X86_64IntegerCondition(condition->GetCondition());
+        } else {
+          // No, we have to recreate the condition code.
+          CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
+          __ testl(cond_reg, cond_reg);
+        }
+      } else {
+        GenerateCompareTest(condition);
+        cond = X86_64IntegerCondition(condition->GetCondition());
+      }
+    } else {
+      // Must be a boolean condition, which needs to be compared to 0.
+      CpuRegister cond_reg = locations->InAt(2).AsRegister<CpuRegister>();
+      __ testl(cond_reg, cond_reg);
+    }
+
+    // If the condition is true, overwrite the output, which already contains false.
+    // Generate the correct sized CMOV.
+    bool is_64_bit = Primitive::Is64BitType(select->GetType());
+    if (value_true_loc.IsRegister()) {
+      __ cmov(cond, value_false, value_true_loc.AsRegister<CpuRegister>(), is_64_bit);
+    } else {
+      __ cmov(cond,
+              value_false,
+              Address(CpuRegister(RSP), value_true_loc.GetStackIndex()), is_64_bit);
+    }
+  } else {
+    NearLabel false_target;
+    GenerateTestAndBranch<NearLabel>(select,
+                                     /* condition_input_index */ 2,
+                                     /* true_target */ nullptr,
+                                     &false_target);
+    codegen_->MoveLocation(locations->Out(), locations->InAt(1), select->GetType());
+    __ Bind(&false_target);
+  }
 }
 
 void LocationsBuilderX86_64::VisitNativeDebugInfo(HNativeDebugInfo* info) {
@@ -1691,11 +1728,7 @@
         __ 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));
-        }
+        codegen_->Compare32BitValue(lhs.AsRegister<CpuRegister>(), constant);
       } else {
         __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
       }
@@ -1709,16 +1742,7 @@
         __ 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));
-        }
+        codegen_->Compare64BitValue(lhs.AsRegister<CpuRegister>(), value);
       } else {
         __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
       }
@@ -1850,6 +1874,7 @@
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
   switch (compare->InputAt(0)->GetType()) {
+    case Primitive::kPrimInt:
     case Primitive::kPrimLong: {
       locations->SetInAt(0, Location::RequiresRegister());
       locations->SetInAt(1, Location::Any());
@@ -1876,21 +1901,26 @@
 
   NearLabel less, greater, done;
   Primitive::Type type = compare->InputAt(0)->GetType();
+  Condition less_cond = kLess;
+
   switch (type) {
+    case Primitive::kPrimInt: {
+      CpuRegister left_reg = left.AsRegister<CpuRegister>();
+      if (right.IsConstant()) {
+        int32_t value = right.GetConstant()->AsIntConstant()->GetValue();
+        codegen_->Compare32BitValue(left_reg, value);
+      } else if (right.IsStackSlot()) {
+        __ cmpl(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
+      } else {
+        __ cmpl(left_reg, right.AsRegister<CpuRegister>());
+      }
+      break;
+    }
     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 int.
-          __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
-        }
+        codegen_->Compare64BitValue(left_reg, value);
       } else if (right.IsDoubleStackSlot()) {
         __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
       } else {
@@ -1909,6 +1939,7 @@
         __ ucomiss(left_reg, right.AsFpuRegister<XmmRegister>());
       }
       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      less_cond = kBelow;  //  ucomis{s,d} sets CF
       break;
     }
     case Primitive::kPrimDouble: {
@@ -1922,14 +1953,16 @@
         __ ucomisd(left_reg, right.AsFpuRegister<XmmRegister>());
       }
       __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
+      less_cond = kBelow;  //  ucomis{s,d} sets CF
       break;
     }
     default:
       LOG(FATAL) << "Unexpected compare type " << type;
   }
+
   __ movl(out, Immediate(0));
   __ j(kEqual, &done);
-  __ j(type == Primitive::kPrimLong ? kLess : kBelow, &less);  //  ucomis{s,d} sets CF (kBelow)
+  __ j(less_cond, &less);
 
   __ Bind(&greater);
   __ movl(out, Immediate(1));
@@ -2339,6 +2372,8 @@
   switch (result_type) {
     case Primitive::kPrimByte:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to byte is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimShort:
@@ -2357,6 +2392,8 @@
 
     case Primitive::kPrimShort:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to short is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2434,6 +2471,8 @@
 
     case Primitive::kPrimChar:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to char is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2528,6 +2567,8 @@
   switch (result_type) {
     case Primitive::kPrimByte:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to byte is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimShort:
@@ -2536,13 +2577,12 @@
           // Processing a Dex `int-to-byte' instruction.
           if (in.IsRegister()) {
             __ movsxb(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
-          } else if (in.IsStackSlot()) {
+          } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
             __ movsxb(out.AsRegister<CpuRegister>(),
                       Address(CpuRegister(RSP), in.GetStackIndex()));
           } else {
-            DCHECK(in.GetConstant()->IsIntConstant());
             __ movl(out.AsRegister<CpuRegister>(),
-                    Immediate(static_cast<int8_t>(in.GetConstant()->AsIntConstant()->GetValue())));
+                    Immediate(static_cast<int8_t>(Int64FromConstant(in.GetConstant()))));
           }
           break;
 
@@ -2554,6 +2594,8 @@
 
     case Primitive::kPrimShort:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to short is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2562,13 +2604,12 @@
           // Processing a Dex `int-to-short' instruction.
           if (in.IsRegister()) {
             __ movsxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
-          } else if (in.IsStackSlot()) {
+          } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
             __ movsxw(out.AsRegister<CpuRegister>(),
                       Address(CpuRegister(RSP), in.GetStackIndex()));
           } else {
-            DCHECK(in.GetConstant()->IsIntConstant());
             __ movl(out.AsRegister<CpuRegister>(),
-                    Immediate(static_cast<int16_t>(in.GetConstant()->AsIntConstant()->GetValue())));
+                    Immediate(static_cast<int16_t>(Int64FromConstant(in.GetConstant()))));
           }
           break;
 
@@ -2711,6 +2752,8 @@
 
     case Primitive::kPrimChar:
       switch (input_type) {
+        case Primitive::kPrimLong:
+          // Type conversion from long to char is a result of code transformations.
         case Primitive::kPrimBoolean:
           // Boolean input is a result of code transformations.
         case Primitive::kPrimByte:
@@ -2719,14 +2762,12 @@
           // Processing a Dex `int-to-char' instruction.
           if (in.IsRegister()) {
             __ movzxw(out.AsRegister<CpuRegister>(), in.AsRegister<CpuRegister>());
-          } else if (in.IsStackSlot()) {
+          } else if (in.IsStackSlot() || in.IsDoubleStackSlot()) {
             __ movzxw(out.AsRegister<CpuRegister>(),
                       Address(CpuRegister(RSP), in.GetStackIndex()));
           } else {
-            DCHECK(in.GetConstant()->IsIntConstant());
             __ movl(out.AsRegister<CpuRegister>(),
-                    Immediate(static_cast<uint16_t>(
-                        in.GetConstant()->AsIntConstant()->GetValue())));
+                    Immediate(static_cast<uint16_t>(Int64FromConstant(in.GetConstant()))));
           }
           break;
 
@@ -2750,11 +2791,7 @@
           } else if (in.IsConstant()) {
             int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
             XmmRegister dest = out.AsFpuRegister<XmmRegister>();
-            if (v == 0) {
-              __ xorps(dest, dest);
-            } else {
-              __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
-            }
+            codegen_->Load32BitValue(dest, static_cast<float>(v));
           } else {
             __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
                         Address(CpuRegister(RSP), in.GetStackIndex()), false);
@@ -2768,11 +2805,7 @@
           } else if (in.IsConstant()) {
             int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
             XmmRegister dest = out.AsFpuRegister<XmmRegister>();
-            if (v == 0) {
-              __ xorps(dest, dest);
-            } else {
-              __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
-            }
+            codegen_->Load64BitValue(dest, static_cast<double>(v));
           } else {
             __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(),
                         Address(CpuRegister(RSP), in.GetStackIndex()), true);
@@ -2786,11 +2819,7 @@
           } else if (in.IsConstant()) {
             double v = in.GetConstant()->AsDoubleConstant()->GetValue();
             XmmRegister dest = out.AsFpuRegister<XmmRegister>();
-            if (bit_cast<int64_t, double>(v) == 0) {
-              __ xorps(dest, dest);
-            } else {
-              __ movss(dest, codegen_->LiteralFloatAddress(static_cast<float>(v)));
-            }
+            codegen_->Load32BitValue(dest, static_cast<float>(v));
           } else {
             __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(),
                         Address(CpuRegister(RSP), in.GetStackIndex()));
@@ -2817,11 +2846,7 @@
           } else if (in.IsConstant()) {
             int32_t v = in.GetConstant()->AsIntConstant()->GetValue();
             XmmRegister dest = out.AsFpuRegister<XmmRegister>();
-            if (v == 0) {
-              __ xorpd(dest, dest);
-            } else {
-              __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
-            }
+            codegen_->Load64BitValue(dest, static_cast<double>(v));
           } else {
             __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
                         Address(CpuRegister(RSP), in.GetStackIndex()), false);
@@ -2835,11 +2860,7 @@
           } else if (in.IsConstant()) {
             int64_t v = in.GetConstant()->AsLongConstant()->GetValue();
             XmmRegister dest = out.AsFpuRegister<XmmRegister>();
-            if (v == 0) {
-              __ xorpd(dest, dest);
-            } else {
-              __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
-            }
+            codegen_->Load64BitValue(dest, static_cast<double>(v));
           } else {
             __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(),
                         Address(CpuRegister(RSP), in.GetStackIndex()), true);
@@ -2853,11 +2874,7 @@
           } else if (in.IsConstant()) {
             float v = in.GetConstant()->AsFloatConstant()->GetValue();
             XmmRegister dest = out.AsFpuRegister<XmmRegister>();
-            if (bit_cast<int32_t, float>(v) == 0) {
-              __ xorpd(dest, dest);
-            } else {
-              __ movsd(dest, codegen_->LiteralDoubleAddress(static_cast<double>(v)));
-            }
+            codegen_->Load64BitValue(dest, static_cast<double>(v));
           } else {
             __ cvtss2sd(out.AsFpuRegister<XmmRegister>(),
                         Address(CpuRegister(RSP), in.GetStackIndex()));
@@ -5066,14 +5083,6 @@
   }
 }
 
-void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
-  temp->SetLocations(nullptr);
-}
-
-void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp ATTRIBUTE_UNUSED) {
-  // Nothing to do, this is driven by the code generator.
-}
-
 void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction ATTRIBUTE_UNUSED) {
   LOG(FATAL) << "Unimplemented";
 }
@@ -5196,18 +5205,12 @@
       }
     } else if (constant->IsFloatConstant()) {
       float fp_value = constant->AsFloatConstant()->GetValue();
-      int32_t value = bit_cast<int32_t, float>(fp_value);
       if (destination.IsFpuRegister()) {
         XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
-        if (value == 0) {
-          // easy FP 0.0.
-          __ xorps(dest, dest);
-        } else {
-          __ movss(dest, codegen_->LiteralFloatAddress(fp_value));
-        }
+        codegen_->Load32BitValue(dest, fp_value);
       } else {
         DCHECK(destination.IsStackSlot()) << destination;
-        Immediate imm(value);
+        Immediate imm(bit_cast<int32_t, float>(fp_value));
         __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
       }
     } else {
@@ -5216,11 +5219,7 @@
       int64_t value = bit_cast<int64_t, double>(fp_value);
       if (destination.IsFpuRegister()) {
         XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
-        if (value == 0) {
-          __ xorpd(dest, dest);
-        } else {
-          __ movsd(dest, codegen_->LiteralDoubleAddress(fp_value));
-        }
+        codegen_->Load64BitValue(dest, fp_value);
       } else {
         DCHECK(destination.IsDoubleStackSlot()) << destination;
         codegen_->Store64BitValueToStack(destination, value);
@@ -5774,19 +5773,20 @@
                                                            is_type_check_slow_path_fatal);
   codegen_->AddSlowPath(type_check_slow_path);
 
-  NearLabel done;
-  // Avoid null check if we know obj is not null.
-  if (instruction->MustDoNullCheck()) {
-    __ testl(obj, obj);
-    __ j(kEqual, &done);
-  }
-
-  // /* HeapReference<Class> */ temp = obj->klass_
-  GenerateReferenceLoadTwoRegisters(instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
-
   switch (type_check_kind) {
     case TypeCheckKind::kExactCheck:
     case TypeCheckKind::kArrayCheck: {
+      NearLabel done;
+      // Avoid null check if we know obj is not null.
+      if (instruction->MustDoNullCheck()) {
+        __ testl(obj, obj);
+        __ j(kEqual, &done);
+      }
+
+      // /* HeapReference<Class> */ temp = obj->klass_
+      GenerateReferenceLoadTwoRegisters(
+          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
+
       if (cls.IsRegister()) {
         __ cmpl(temp, cls.AsRegister<CpuRegister>());
       } else {
@@ -5796,10 +5796,22 @@
       // Jump to slow path for throwing the exception or doing a
       // more involved array check.
       __ j(kNotEqual, type_check_slow_path->GetEntryLabel());
+      __ Bind(&done);
       break;
     }
 
     case TypeCheckKind::kAbstractClassCheck: {
+      NearLabel done;
+      // Avoid null check if we know obj is not null.
+      if (instruction->MustDoNullCheck()) {
+        __ testl(obj, obj);
+        __ j(kEqual, &done);
+      }
+
+      // /* HeapReference<Class> */ temp = obj->klass_
+      GenerateReferenceLoadTwoRegisters(
+          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
+
       // If the class is abstract, we eagerly fetch the super class of the
       // object to avoid doing a comparison we know will fail.
       NearLabel loop, compare_classes;
@@ -5830,10 +5842,22 @@
         __ cmpl(temp, Address(CpuRegister(RSP), cls.GetStackIndex()));
       }
       __ j(kNotEqual, &loop);
+      __ Bind(&done);
       break;
     }
 
     case TypeCheckKind::kClassHierarchyCheck: {
+      NearLabel done;
+      // Avoid null check if we know obj is not null.
+      if (instruction->MustDoNullCheck()) {
+        __ testl(obj, obj);
+        __ j(kEqual, &done);
+      }
+
+      // /* HeapReference<Class> */ temp = obj->klass_
+      GenerateReferenceLoadTwoRegisters(
+          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
+
       // Walk over the class hierarchy to find a match.
       NearLabel loop;
       __ Bind(&loop);
@@ -5861,10 +5885,26 @@
       GenerateReferenceLoadTwoRegisters(
           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
       __ jmp(type_check_slow_path->GetEntryLabel());
+      __ Bind(&done);
       break;
     }
 
     case TypeCheckKind::kArrayObjectCheck: {
+      // We cannot use a NearLabel here, as its range might be too
+      // short in some cases when read barriers are enabled.  This has
+      // been observed for instance when the code emitted for this
+      // case uses high x86-64 registers (R8-R15).
+      Label done;
+      // Avoid null check if we know obj is not null.
+      if (instruction->MustDoNullCheck()) {
+        __ testl(obj, obj);
+        __ j(kEqual, &done);
+      }
+
+      // /* HeapReference<Class> */ temp = obj->klass_
+      GenerateReferenceLoadTwoRegisters(
+          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
+
       // Do an exact check.
       NearLabel check_non_primitive_component_type;
       if (cls.IsRegister()) {
@@ -5903,11 +5943,23 @@
       GenerateReferenceLoadTwoRegisters(
           instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
       __ jmp(type_check_slow_path->GetEntryLabel());
+      __ Bind(&done);
       break;
     }
 
     case TypeCheckKind::kUnresolvedCheck:
     case TypeCheckKind::kInterfaceCheck:
+      NearLabel done;
+      // Avoid null check if we know obj is not null.
+      if (instruction->MustDoNullCheck()) {
+        __ testl(obj, obj);
+        __ j(kEqual, &done);
+      }
+
+      // /* HeapReference<Class> */ temp = obj->klass_
+      GenerateReferenceLoadTwoRegisters(
+          instruction, temp_loc, obj_loc, class_offset, maybe_temp2_loc);
+
       // We always go into the type check slow path for the unresolved
       // and interface check cases.
       //
@@ -5926,9 +5978,9 @@
       // call to the runtime not using a type checking slow path).
       // This should also be beneficial for the other cases above.
       __ jmp(type_check_slow_path->GetEntryLabel());
+      __ Bind(&done);
       break;
   }
-  __ Bind(&done);
 
   __ Bind(type_check_slow_path->GetExitLabel());
 }
@@ -6467,6 +6519,51 @@
   }
 }
 
+void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, int32_t value) {
+  if (value == 0) {
+    __ xorps(dest, dest);
+  } else {
+    __ movss(dest, LiteralInt32Address(value));
+  }
+}
+
+void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, int64_t value) {
+  if (value == 0) {
+    __ xorpd(dest, dest);
+  } else {
+    __ movsd(dest, LiteralInt64Address(value));
+  }
+}
+
+void CodeGeneratorX86_64::Load32BitValue(XmmRegister dest, float value) {
+  Load32BitValue(dest, bit_cast<int32_t, float>(value));
+}
+
+void CodeGeneratorX86_64::Load64BitValue(XmmRegister dest, double value) {
+  Load64BitValue(dest, bit_cast<int64_t, double>(value));
+}
+
+void CodeGeneratorX86_64::Compare32BitValue(CpuRegister dest, int32_t value) {
+  if (value == 0) {
+    __ testl(dest, dest);
+  } else {
+    __ cmpl(dest, Immediate(value));
+  }
+}
+
+void CodeGeneratorX86_64::Compare64BitValue(CpuRegister dest, int64_t value) {
+  if (IsInt<32>(value)) {
+    if (value == 0) {
+      __ testq(dest, dest);
+    } else {
+      __ cmpq(dest, Immediate(static_cast<int32_t>(value)));
+    }
+  } else {
+    // Value won't fit in an int.
+    __ cmpq(dest, LiteralInt64Address(value));
+  }
+}
+
 void CodeGeneratorX86_64::Store64BitValueToStack(Location dest, int64_t value) {
   DCHECK(dest.IsDoubleStackSlot());
   if (IsInt<32>(value)) {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 318087e..97f6f84 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -264,6 +264,7 @@
   void GenerateExplicitNullCheck(HNullCheck* instruction);
   void PushOntoFPStack(Location source, uint32_t temp_offset,
                        uint32_t stack_adjustment, bool is_float);
+  void GenerateCompareTest(HCondition* condition);
   template<class LabelType>
   void GenerateTestAndBranch(HInstruction* instruction,
                              size_t condition_input_index,
@@ -298,7 +299,6 @@
   void GenerateFrameEntry() OVERRIDE;
   void GenerateFrameExit() OVERRIDE;
   void Bind(HBasicBlock* block) OVERRIDE;
-  void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE;
   void MoveConstant(Location destination, int32_t value) OVERRIDE;
   void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
@@ -478,9 +478,17 @@
   Address LiteralInt32Address(int32_t v);
   Address LiteralInt64Address(int64_t v);
 
-  // Load a 32/64 bit value into a register in the most efficient manner.
+  // Load a 32/64-bit value into a register in the most efficient manner.
   void Load32BitValue(CpuRegister dest, int32_t value);
   void Load64BitValue(CpuRegister dest, int64_t value);
+  void Load32BitValue(XmmRegister dest, int32_t value);
+  void Load64BitValue(XmmRegister dest, int64_t value);
+  void Load32BitValue(XmmRegister dest, float value);
+  void Load64BitValue(XmmRegister dest, double value);
+
+  // Compare a register with a 32/64-bit value in the most efficient manner.
+  void Compare32BitValue(CpuRegister dest, int32_t value);
+  void Compare64BitValue(CpuRegister dest, int64_t value);
 
   Address LiteralCaseTable(HPackedSwitch* switch_instr);
 
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index 322a577..6be79fa 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -206,10 +206,13 @@
                     std::function<void(HGraph*)> hook_before_codegen,
                     bool has_result,
                     Expected expected) {
-  ASSERT_TRUE(graph->IsInSsaForm());
-
-  SSAChecker graph_checker(graph);
+  GraphChecker graph_checker(graph);
   graph_checker.Run();
+  if (!graph_checker.IsValid()) {
+    for (auto error : graph_checker.GetErrors()) {
+      std::cout << error << std::endl;
+    }
+  }
   ASSERT_TRUE(graph_checker.IsValid());
 
   SsaLivenessAnalysis liveness(graph, codegen);
@@ -292,14 +295,9 @@
   for (InstructionSet target_isa : GetTargetISAs()) {
     ArenaPool pool;
     ArenaAllocator arena(&pool);
-    HGraph* graph = CreateGraph(&arena);
-    HGraphBuilder builder(graph);
-    const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-    bool graph_built = builder.BuildGraph(*item);
-    ASSERT_TRUE(graph_built);
+    HGraph* graph = CreateCFG(&arena, data);
     // Remove suspend checks, they cannot be executed in this context.
     RemoveSuspendChecks(graph);
-    TransformToSsa(graph);
     RunCode(target_isa, graph, [](HGraph*) {}, has_result, expected);
   }
 }
@@ -310,14 +308,9 @@
   for (InstructionSet target_isa : GetTargetISAs()) {
     ArenaPool pool;
     ArenaAllocator arena(&pool);
-    HGraph* graph = CreateGraph(&arena);
-    HGraphBuilder builder(graph, Primitive::kPrimLong);
-    const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-    bool graph_built = builder.BuildGraph(*item);
-    ASSERT_TRUE(graph_built);
+    HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
     // Remove suspend checks, they cannot be executed in this context.
     RemoveSuspendChecks(graph);
-    TransformToSsa(graph);
     RunCode(target_isa, graph, [](HGraph*) {}, has_result, expected);
   }
 }
@@ -640,6 +633,7 @@
     ArenaAllocator allocator(&pool);
 
     HGraph* graph = CreateGraph(&allocator);
+
     HBasicBlock* entry = new (&allocator) HBasicBlock(graph);
     graph->AddBlock(entry);
     graph->SetEntryBlock(entry);
@@ -672,7 +666,7 @@
     else_block->AddInstruction(new (&allocator) HReturn(constant1));
 
     ASSERT_FALSE(equal->IsEmittedAtUseSite());
-    TransformToSsa(graph);
+    graph->BuildDominatorTree();
     PrepareForRegisterAllocation(graph).Run();
     ASSERT_TRUE(equal->IsEmittedAtUseSite());
 
@@ -723,7 +717,7 @@
       HReturn ret(&cmp_lt);
       code_block->AddInstruction(&ret);
 
-      TransformToSsa(graph);
+      graph->BuildDominatorTree();
       auto hook_before_codegen = [](HGraph* graph_in) {
         HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
         HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
@@ -777,9 +771,9 @@
       HIntConstant* cst_rhs = graph->GetIntConstant(rhs[i]);
       HLessThan cmp_lt(cst_lhs, cst_rhs);
       if_block->AddInstruction(&cmp_lt);
-      // We insert a temporary to separate the HIf from the HLessThan and force
-      // the materialization of the condition.
-      HTemporary force_materialization(0);
+      // We insert a dummy instruction to separate the HIf from the HLessThan
+      // and force the materialization of the condition.
+      HMemoryBarrier force_materialization(MemBarrierKind::kAnyAny, 0);
       if_block->AddInstruction(&force_materialization);
       HIf if_lt(&cmp_lt);
       if_block->AddInstruction(&if_lt);
@@ -791,7 +785,7 @@
       HReturn ret_ge(cst_ge);
       if_false_block->AddInstruction(&ret_ge);
 
-      TransformToSsa(graph);
+      graph->BuildDominatorTree();
       auto hook_before_codegen = [](HGraph* graph_in) {
         HBasicBlock* block = graph_in->GetEntryBlock()->GetSuccessors()[0];
         HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
@@ -907,7 +901,7 @@
   block->AddInstruction(comparison);
   block->AddInstruction(new (&allocator) HReturn(comparison));
 
-  TransformToSsa(graph);
+  graph->BuildDominatorTree();
   RunCode(target_isa, graph, [](HGraph*) {}, true, expected_result);
 }
 
diff --git a/compiler/optimizing/constant_folding_test.cc b/compiler/optimizing/constant_folding_test.cc
index a8f65bf..9c69f8c 100644
--- a/compiler/optimizing/constant_folding_test.cc
+++ b/compiler/optimizing/constant_folding_test.cc
@@ -56,7 +56,6 @@
                             const std::string& expected_after_dce,
                             std::function<void(HGraph*)> check_after_cf) {
     ASSERT_NE(graph_, nullptr);
-    TransformToSsa(graph_);
 
     StringPrettyPrinter printer_before(graph_);
     printer_before.VisitInsertionOrder();
@@ -67,9 +66,9 @@
         X86InstructionSetFeatures::FromCppDefines());
     x86::CodeGeneratorX86 codegenX86(graph_, *features_x86.get(), CompilerOptions());
     HConstantFolding(graph_).Run();
-    SSAChecker ssa_checker_cf(graph_);
-    ssa_checker_cf.Run();
-    ASSERT_TRUE(ssa_checker_cf.IsValid());
+    GraphChecker graph_checker_cf(graph_);
+    graph_checker_cf.Run();
+    ASSERT_TRUE(graph_checker_cf.IsValid());
 
     StringPrettyPrinter printer_after_cf(graph_);
     printer_after_cf.VisitInsertionOrder();
@@ -79,9 +78,9 @@
     check_after_cf(graph_);
 
     HDeadCodeElimination(graph_).Run();
-    SSAChecker ssa_checker_dce(graph_);
-    ssa_checker_dce.Run();
-    ASSERT_TRUE(ssa_checker_dce.IsValid());
+    GraphChecker graph_checker_dce(graph_);
+    graph_checker_dce.Run();
+    ASSERT_TRUE(graph_checker_dce.IsValid());
 
     StringPrettyPrinter printer_after_dce(graph_);
     printer_after_dce.VisitInsertionOrder();
@@ -775,76 +774,87 @@
   HInstruction* zero = graph_->GetIntConstant(0);
   HInstruction* last;
   block->AddInstruction(last = new (&allocator_) HAbove(zero, parameter));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
   block->AddInstruction(last = new (&allocator_) HAbove(parameter, zero));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
   block->AddInstruction(last = new (&allocator_) HAboveOrEqual(zero, parameter));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
   block->AddInstruction(last = new (&allocator_) HAboveOrEqual(parameter, zero));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
   block->AddInstruction(last = new (&allocator_) HBelow(zero, parameter));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
   block->AddInstruction(last = new (&allocator_) HBelow(parameter, zero));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
   block->AddInstruction(last = new (&allocator_) HBelowOrEqual(zero, parameter));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
   block->AddInstruction(last = new (&allocator_) HBelowOrEqual(parameter, zero));
-  block->AddInstruction(new (&allocator_) HDeoptimize(last, 0));
+  block->AddInstruction(new (&allocator_) HSelect(last, parameter, parameter, 0));
 
   entry_block->AddInstruction(new (&allocator_) HGoto());
   block->AddInstruction(new (&allocator_) HReturn(zero));
   exit_block->AddInstruction(new (&allocator_) HExit());
 
+  graph_->BuildDominatorTree();
+
   const std::string expected_before =
       "BasicBlock 0, succ: 1\n"
-      "  0: ParameterValue [16, 14, 12, 10, 8, 6, 4, 2]\n"
+      "  0: ParameterValue [17, 17, 16, 15, 15, 14, 13, 13, 12, 11, 11, 10, 9, 9, "
+                           "8, 7, 7, 6, 5, 5, 4, 3, 3, 2]\n"
       "  1: IntConstant [19, 16, 14, 12, 10, 8, 6, 4, 2]\n"
       "  18: Goto 1\n"
       "BasicBlock 1, pred: 0, succ: 2\n"
       "  2: Above(1, 0) [3]\n"
-      "  3: Deoptimize(2)\n"
+      "  3: Select(0, 0, 2)\n"
       "  4: Above(0, 1) [5]\n"
-      "  5: Deoptimize(4)\n"
+      "  5: Select(0, 0, 4)\n"
       "  6: AboveOrEqual(1, 0) [7]\n"
-      "  7: Deoptimize(6)\n"
+      "  7: Select(0, 0, 6)\n"
       "  8: AboveOrEqual(0, 1) [9]\n"
-      "  9: Deoptimize(8)\n"
+      "  9: Select(0, 0, 8)\n"
       "  10: Below(1, 0) [11]\n"
-      "  11: Deoptimize(10)\n"
+      "  11: Select(0, 0, 10)\n"
       "  12: Below(0, 1) [13]\n"
-      "  13: Deoptimize(12)\n"
+      "  13: Select(0, 0, 12)\n"
       "  14: BelowOrEqual(1, 0) [15]\n"
-      "  15: Deoptimize(14)\n"
+      "  15: Select(0, 0, 14)\n"
       "  16: BelowOrEqual(0, 1) [17]\n"
-      "  17: Deoptimize(16)\n"
+      "  17: Select(0, 0, 16)\n"
       "  19: Return(1)\n"
       "BasicBlock 2, pred: 1\n"
       "  20: Exit\n";
 
   const std::string expected_after_cf =
       "BasicBlock 0, succ: 1\n"
-      "  0: ParameterValue [16, 10, 6, 4]\n"
+      "  0: ParameterValue [17, 17, 16, 15, 15, 13, 13, 11, 11, 10, 9, 9, 7, 7, 6, 5, 5, 4, 3, 3]\n"
       "  1: IntConstant [13, 3, 19, 16, 10, 6, 4]\n"
       "  21: IntConstant [15, 9]\n"
       "  18: Goto 1\n"
       "BasicBlock 1, pred: 0, succ: 2\n"
-      "  3: Deoptimize(1)\n"
+      "  3: Select(0, 0, 1)\n"
       "  4: Above(0, 1) [5]\n"
-      "  5: Deoptimize(4)\n"
+      "  5: Select(0, 0, 4)\n"
       "  6: AboveOrEqual(1, 0) [7]\n"
-      "  7: Deoptimize(6)\n"
-      "  9: Deoptimize(21)\n"
+      "  7: Select(0, 0, 6)\n"
+      "  9: Select(0, 0, 21)\n"
       "  10: Below(1, 0) [11]\n"
-      "  11: Deoptimize(10)\n"
-      "  13: Deoptimize(1)\n"
-      "  15: Deoptimize(21)\n"
+      "  11: Select(0, 0, 10)\n"
+      "  13: Select(0, 0, 1)\n"
+      "  15: Select(0, 0, 21)\n"
       "  16: BelowOrEqual(0, 1) [17]\n"
-      "  17: Deoptimize(16)\n"
+      "  17: Select(0, 0, 16)\n"
       "  19: Return(1)\n"
       "BasicBlock 2, pred: 1\n"
       "  20: Exit\n";
 
-  const std::string expected_after_dce = expected_after_cf;
+  const std::string expected_after_dce =
+      "BasicBlock 0, succ: 1\n"
+      "  0: ParameterValue\n"
+      "  1: IntConstant [19]\n"
+      "  18: Goto 1\n"
+      "BasicBlock 1, pred: 0, succ: 2\n"
+      "  19: Return(1)\n"
+      "BasicBlock 2, pred: 1\n"
+      "  20: Exit\n";
 
   auto check_after_cf = [](HGraph* graph) {
     CHECK(graph != nullptr);
diff --git a/compiler/optimizing/dead_code_elimination_test.cc b/compiler/optimizing/dead_code_elimination_test.cc
index f0f98ef..930795b 100644
--- a/compiler/optimizing/dead_code_elimination_test.cc
+++ b/compiler/optimizing/dead_code_elimination_test.cc
@@ -36,8 +36,6 @@
   HGraph* graph = CreateCFG(&allocator, data);
   ASSERT_NE(graph, nullptr);
 
-  TransformToSsa(graph);
-
   StringPrettyPrinter printer_before(graph);
   printer_before.VisitInsertionOrder();
   std::string actual_before = printer_before.str();
@@ -47,9 +45,9 @@
       X86InstructionSetFeatures::FromCppDefines());
   x86::CodeGeneratorX86 codegenX86(graph, *features_x86.get(), CompilerOptions());
   HDeadCodeElimination(graph).Run();
-  SSAChecker ssa_checker(graph);
-  ssa_checker.Run();
-  ASSERT_TRUE(ssa_checker.IsValid());
+  GraphChecker graph_checker(graph);
+  graph_checker.Run();
+  ASSERT_TRUE(graph_checker.IsValid());
 
   StringPrettyPrinter printer_after(graph);
   printer_after.VisitInsertionOrder();
diff --git a/compiler/optimizing/dominator_test.cc b/compiler/optimizing/dominator_test.cc
index feb8b20..50c677a 100644
--- a/compiler/optimizing/dominator_test.cc
+++ b/compiler/optimizing/dominator_test.cc
@@ -24,15 +24,12 @@
 
 namespace art {
 
+class OptimizerTest : public CommonCompilerTest {};
+
 static void TestCode(const uint16_t* data, const uint32_t* blocks, size_t blocks_length) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateGraph(&allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  bool graph_built = builder.BuildGraph(*item);
-  ASSERT_TRUE(graph_built);
-  graph->BuildDominatorTree();
+  HGraph* graph = CreateCFG(&allocator, data);
   ASSERT_EQ(graph->GetBlocks().size(), blocks_length);
   for (size_t i = 0, e = blocks_length; i < e; ++i) {
     if (blocks[i] == kInvalidBlockId) {
@@ -50,7 +47,7 @@
   }
 }
 
-TEST(OptimizerTest, ReturnVoid) {
+TEST_F(OptimizerTest, ReturnVoid) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
       Instruction::RETURN_VOID);  // Block number 1
 
@@ -63,7 +60,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG1) {
+TEST_F(OptimizerTest, CFG1) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,  // Block number 1
     Instruction::RETURN_VOID);  // Block number 2
@@ -78,7 +75,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG2) {
+TEST_F(OptimizerTest, CFG2) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x100,  // Block number 1
     Instruction::GOTO | 0x100,  // Block number 2
@@ -95,7 +92,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG3) {
+TEST_F(OptimizerTest, CFG3) {
   const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x200,    // Block number 1
     Instruction::RETURN_VOID,     // Block number 2
@@ -126,7 +123,7 @@
   TestCode(data3, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG4) {
+TEST_F(OptimizerTest, CFG4) {
   const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::NOP,
     Instruction::GOTO | 0xFF00);
@@ -146,7 +143,7 @@
   TestCode(data2, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG5) {
+TEST_F(OptimizerTest, CFG5) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::RETURN_VOID,     // Block number 1
     Instruction::GOTO | 0x100,    // Dead block
@@ -163,7 +160,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG6) {
+TEST_F(OptimizerTest, CFG6) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
@@ -182,7 +179,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG7) {
+TEST_F(OptimizerTest, CFG7) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,        // Block number 1
@@ -202,7 +199,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG8) {
+TEST_F(OptimizerTest, CFG8) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,        // Block number 1
@@ -223,7 +220,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG9) {
+TEST_F(OptimizerTest, CFG9) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,        // Block number 1
@@ -244,7 +241,7 @@
   TestCode(data, dominators, sizeof(dominators) / sizeof(int));
 }
 
-TEST(OptimizerTest, CFG10) {
+TEST_F(OptimizerTest, CFG10) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,  // Block number 1
diff --git a/compiler/optimizing/find_loops_test.cc b/compiler/optimizing/find_loops_test.cc
index 4770fa2..04789d9 100644
--- a/compiler/optimizing/find_loops_test.cc
+++ b/compiler/optimizing/find_loops_test.cc
@@ -27,16 +27,9 @@
 
 namespace art {
 
-static HGraph* TestCode(const uint16_t* data, ArenaAllocator* allocator) {
-  HGraph* graph = CreateGraph(allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  builder.BuildGraph(*item);
-  graph->BuildDominatorTree();
-  return graph;
-}
+class FindLoopsTest : public CommonCompilerTest {};
 
-TEST(FindLoopsTest, CFG1) {
+TEST_F(FindLoopsTest, CFG1) {
   // Constant is not used.
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -44,26 +37,26 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   for (HBasicBlock* block : graph->GetBlocks()) {
     ASSERT_EQ(block->GetLoopInformation(), nullptr);
   }
 }
 
-TEST(FindLoopsTest, CFG2) {
+TEST_F(FindLoopsTest, CFG2) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::RETURN);
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   for (HBasicBlock* block : graph->GetBlocks()) {
     ASSERT_EQ(block->GetLoopInformation(), nullptr);
   }
 }
 
-TEST(FindLoopsTest, CFG3) {
+TEST_F(FindLoopsTest, CFG3) {
   const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
     Instruction::CONST_4 | 3 << 12 | 0,
     Instruction::CONST_4 | 4 << 12 | 1 << 8,
@@ -73,13 +66,13 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   for (HBasicBlock* block : graph->GetBlocks()) {
     ASSERT_EQ(block->GetLoopInformation(), nullptr);
   }
 }
 
-TEST(FindLoopsTest, CFG4) {
+TEST_F(FindLoopsTest, CFG4) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 4,
@@ -90,13 +83,13 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   for (HBasicBlock* block : graph->GetBlocks()) {
     ASSERT_EQ(block->GetLoopInformation(), nullptr);
   }
 }
 
-TEST(FindLoopsTest, CFG5) {
+TEST_F(FindLoopsTest, CFG5) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
@@ -105,7 +98,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   for (HBasicBlock* block : graph->GetBlocks()) {
     ASSERT_EQ(block->GetLoopInformation(), nullptr);
   }
@@ -137,7 +130,7 @@
   }
 }
 
-TEST(FindLoopsTest, Loop1) {
+TEST_F(FindLoopsTest, Loop1) {
   // Simple loop with one preheader and one back edge.
   // var a = 0;
   // while (a == a) {
@@ -151,7 +144,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // pre header
@@ -162,7 +155,7 @@
   TestBlock(graph, 5, false, kInvalidBlockId);  // exit block
 }
 
-TEST(FindLoopsTest, Loop2) {
+TEST_F(FindLoopsTest, Loop2) {
   // Make sure we support a preheader of a loop not being the first predecessor
   // in the predecessor list of the header.
   // var a = 0;
@@ -179,7 +172,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // goto block
@@ -191,7 +184,7 @@
   TestBlock(graph, 6, false, kInvalidBlockId);  // exit block
 }
 
-TEST(FindLoopsTest, Loop3) {
+TEST_F(FindLoopsTest, Loop3) {
   // Make sure we create a preheader of a loop when a header originally has two
   // incoming blocks and one back edge.
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
@@ -204,7 +197,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // goto block
@@ -218,7 +211,7 @@
   TestBlock(graph, 8, false, kInvalidBlockId);  // synthesized pre header
 }
 
-TEST(FindLoopsTest, Loop4) {
+TEST_F(FindLoopsTest, Loop4) {
   // Test loop with originally two back edges.
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -230,7 +223,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // pre header
@@ -244,7 +237,7 @@
 }
 
 
-TEST(FindLoopsTest, Loop5) {
+TEST_F(FindLoopsTest, Loop5) {
   // Test loop with two exit edges.
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -256,7 +249,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // pre header
@@ -270,7 +263,7 @@
   TestBlock(graph, 8, false, kInvalidBlockId);  // synthesized block at the loop exit
 }
 
-TEST(FindLoopsTest, InnerLoop) {
+TEST_F(FindLoopsTest, InnerLoop) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 6,
@@ -281,7 +274,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // pre header of outer loop
@@ -301,7 +294,7 @@
                     *graph->GetBlocks()[3]->GetLoopInformation()));
 }
 
-TEST(FindLoopsTest, TwoLoops) {
+TEST_F(FindLoopsTest, TwoLoops) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
@@ -312,7 +305,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // pre header of first loop
@@ -331,7 +324,7 @@
                     *graph->GetBlocks()[4]->GetLoopInformation()));
 }
 
-TEST(FindLoopsTest, NonNaturalLoop) {
+TEST_F(FindLoopsTest, NonNaturalLoop) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
@@ -342,14 +335,14 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   ASSERT_TRUE(graph->GetBlocks()[3]->IsLoopHeader());
   HLoopInformation* info = graph->GetBlocks()[3]->GetLoopInformation();
   ASSERT_EQ(1u, info->NumberOfBackEdges());
   ASSERT_FALSE(info->GetHeader()->Dominates(info->GetBackEdges()[0]));
 }
 
-TEST(FindLoopsTest, DoWhileLoop) {
+TEST_F(FindLoopsTest, DoWhileLoop) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::GOTO | 0x0100,
@@ -358,7 +351,7 @@
 
   ArenaPool arena;
   ArenaAllocator allocator(&arena);
-  HGraph* graph = TestCode(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
 
   TestBlock(graph, 0, false, kInvalidBlockId);  // entry block
   TestBlock(graph, 1, false, kInvalidBlockId);  // pre header of first loop
diff --git a/compiler/optimizing/graph_checker.cc b/compiler/optimizing/graph_checker.cc
index 962e77d..e6e9177 100644
--- a/compiler/optimizing/graph_checker.cc
+++ b/compiler/optimizing/graph_checker.cc
@@ -149,6 +149,103 @@
     }
     current->Accept(this);
   }
+
+  // Ensure that catch blocks are not normal successors, and normal blocks are
+  // never exceptional successors.
+  for (HBasicBlock* successor : block->GetNormalSuccessors()) {
+    if (successor->IsCatchBlock()) {
+      AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
+                            successor->GetBlockId(),
+                            block->GetBlockId()));
+    }
+  }
+  for (HBasicBlock* successor : block->GetExceptionalSuccessors()) {
+    if (!successor->IsCatchBlock()) {
+      AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
+                            successor->GetBlockId(),
+                            block->GetBlockId()));
+    }
+  }
+
+  // Ensure dominated blocks have `block` as the dominator.
+  for (HBasicBlock* dominated : block->GetDominatedBlocks()) {
+    if (dominated->GetDominator() != block) {
+      AddError(StringPrintf("Block %d should be the dominator of %d.",
+                            block->GetBlockId(),
+                            dominated->GetBlockId()));
+    }
+  }
+
+  // Ensure there is no critical edge (i.e., an edge connecting a
+  // block with multiple successors to a block with multiple
+  // predecessors). Exceptional edges are synthesized and hence
+  // not accounted for.
+  if (block->GetSuccessors().size() > 1) {
+    for (HBasicBlock* successor : block->GetNormalSuccessors()) {
+      if (successor->IsExitBlock() &&
+          block->IsSingleTryBoundary() &&
+          block->GetPredecessors().size() == 1u &&
+          block->GetSinglePredecessor()->GetLastInstruction()->IsThrow()) {
+        // Allowed critical edge Throw->TryBoundary->Exit.
+      } else if (successor->GetPredecessors().size() > 1) {
+        AddError(StringPrintf("Critical edge between blocks %d and %d.",
+                              block->GetBlockId(),
+                              successor->GetBlockId()));
+      }
+    }
+  }
+
+  // Ensure try membership information is consistent.
+  if (block->IsCatchBlock()) {
+    if (block->IsTryBlock()) {
+      const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry();
+      AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
+                            "has try entry %s:%d.",
+                            block->GetBlockId(),
+                            try_entry.DebugName(),
+                            try_entry.GetId()));
+    }
+
+    if (block->IsLoopHeader()) {
+      AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
+                            block->GetBlockId()));
+    }
+  } else {
+    for (HBasicBlock* predecessor : block->GetPredecessors()) {
+      const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
+      if (block->IsTryBlock()) {
+        const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry();
+        if (incoming_try_entry == nullptr) {
+          AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
+                                "from predecessor %d.",
+                                block->GetBlockId(),
+                                stored_try_entry.DebugName(),
+                                stored_try_entry.GetId(),
+                                predecessor->GetBlockId()));
+        } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) {
+          AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
+                                "with %s:%d that follows from predecessor %d.",
+                                block->GetBlockId(),
+                                stored_try_entry.DebugName(),
+                                stored_try_entry.GetId(),
+                                incoming_try_entry->DebugName(),
+                                incoming_try_entry->GetId(),
+                                predecessor->GetBlockId()));
+        }
+      } else if (incoming_try_entry != nullptr) {
+        AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows "
+                              "from predecessor %d.",
+                              block->GetBlockId(),
+                              incoming_try_entry->DebugName(),
+                              incoming_try_entry->GetId(),
+                              predecessor->GetBlockId()));
+      }
+    }
+  }
+
+  if (block->IsLoopHeader()) {
+    HandleLoop(block);
+  }
 }
 
 void GraphChecker::VisitBoundsCheck(HBoundsCheck* check) {
@@ -168,7 +265,7 @@
 
   // Ensure that all exception handlers are catch blocks.
   // Note that a normal-flow successor may be a catch block before CFG
-  // simplification. We only test normal-flow successors in SsaChecker.
+  // simplification. We only test normal-flow successors in GraphChecker.
   for (HBasicBlock* handler : handlers) {
     if (!handler->IsCatchBlock()) {
       AddError(StringPrintf("Block %d with %s:%d has exceptional successor %d which "
@@ -303,6 +400,88 @@
                             input->GetId()));
     }
   }
+
+  // Ensure an instruction dominates all its uses.
+  for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
+       !use_it.Done(); use_it.Advance()) {
+    HInstruction* use = use_it.Current()->GetUser();
+    if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
+      AddError(StringPrintf("Instruction %s:%d in block %d does not dominate "
+                            "use %s:%d in block %d.",
+                            instruction->DebugName(),
+                            instruction->GetId(),
+                            current_block_->GetBlockId(),
+                            use->DebugName(),
+                            use->GetId(),
+                            use->GetBlock()->GetBlockId()));
+    }
+  }
+
+  if (instruction->NeedsEnvironment() && !instruction->HasEnvironment()) {
+    AddError(StringPrintf("Instruction %s:%d in block %d requires an environment "
+                          "but does not have one.",
+                          instruction->DebugName(),
+                          instruction->GetId(),
+                          current_block_->GetBlockId()));
+  }
+
+  // Ensure an instruction having an environment is dominated by the
+  // instructions contained in the environment.
+  for (HEnvironment* environment = instruction->GetEnvironment();
+       environment != nullptr;
+       environment = environment->GetParent()) {
+    for (size_t i = 0, e = environment->Size(); i < e; ++i) {
+      HInstruction* env_instruction = environment->GetInstructionAt(i);
+      if (env_instruction != nullptr
+          && !env_instruction->StrictlyDominates(instruction)) {
+        AddError(StringPrintf("Instruction %d in environment of instruction %d "
+                              "from block %d does not dominate instruction %d.",
+                              env_instruction->GetId(),
+                              instruction->GetId(),
+                              current_block_->GetBlockId(),
+                              instruction->GetId()));
+      }
+    }
+  }
+
+  // Ensure that reference type instructions have reference type info.
+  if (instruction->GetType() == Primitive::kPrimNot) {
+    ScopedObjectAccess soa(Thread::Current());
+    if (!instruction->GetReferenceTypeInfo().IsValid()) {
+      AddError(StringPrintf("Reference type instruction %s:%d does not have "
+                            "valid reference type information.",
+                            instruction->DebugName(),
+                            instruction->GetId()));
+    }
+  }
+
+  if (instruction->CanThrowIntoCatchBlock()) {
+    // Find the top-level environment. This corresponds to the environment of
+    // the catch block since we do not inline methods with try/catch.
+    HEnvironment* environment = instruction->GetEnvironment();
+    while (environment->GetParent() != nullptr) {
+      environment = environment->GetParent();
+    }
+
+    // Find all catch blocks and test that `instruction` has an environment
+    // value for each one.
+    const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
+    for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) {
+      for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
+        HPhi* catch_phi = phi_it.Current()->AsPhi();
+        if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) {
+          AddError(StringPrintf("Instruction %s:%d throws into catch block %d "
+                                "with catch phi %d for vreg %d but its "
+                                "corresponding environment slot is empty.",
+                                instruction->DebugName(),
+                                instruction->GetId(),
+                                catch_block->GetBlockId(),
+                                catch_phi->GetId(),
+                                catch_phi->GetRegNumber()));
+        }
+      }
+    }
+  }
 }
 
 void GraphChecker::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
@@ -371,108 +550,7 @@
   }
 }
 
-void SSAChecker::VisitBasicBlock(HBasicBlock* block) {
-  super_type::VisitBasicBlock(block);
-
-  // Ensure that catch blocks are not normal successors, and normal blocks are
-  // never exceptional successors.
-  for (HBasicBlock* successor : block->GetNormalSuccessors()) {
-    if (successor->IsCatchBlock()) {
-      AddError(StringPrintf("Catch block %d is a normal successor of block %d.",
-                            successor->GetBlockId(),
-                            block->GetBlockId()));
-    }
-  }
-  for (HBasicBlock* successor : block->GetExceptionalSuccessors()) {
-    if (!successor->IsCatchBlock()) {
-      AddError(StringPrintf("Normal block %d is an exceptional successor of block %d.",
-                            successor->GetBlockId(),
-                            block->GetBlockId()));
-    }
-  }
-
-  // Ensure dominated blocks have `block` as the dominator.
-  for (HBasicBlock* dominated : block->GetDominatedBlocks()) {
-    if (dominated->GetDominator() != block) {
-      AddError(StringPrintf("Block %d should be the dominator of %d.",
-                            block->GetBlockId(),
-                            dominated->GetBlockId()));
-    }
-  }
-
-  // Ensure there is no critical edge (i.e., an edge connecting a
-  // block with multiple successors to a block with multiple
-  // predecessors). Exceptional edges are synthesized and hence
-  // not accounted for.
-  if (block->GetSuccessors().size() > 1) {
-    for (HBasicBlock* successor : block->GetNormalSuccessors()) {
-      if (successor->IsExitBlock() &&
-          block->IsSingleTryBoundary() &&
-          block->GetPredecessors().size() == 1u &&
-          block->GetSinglePredecessor()->GetLastInstruction()->IsThrow()) {
-        // Allowed critical edge Throw->TryBoundary->Exit.
-      } else if (successor->GetPredecessors().size() > 1) {
-        AddError(StringPrintf("Critical edge between blocks %d and %d.",
-                              block->GetBlockId(),
-                              successor->GetBlockId()));
-      }
-    }
-  }
-
-  // Ensure try membership information is consistent.
-  if (block->IsCatchBlock()) {
-    if (block->IsTryBlock()) {
-      const HTryBoundary& try_entry = block->GetTryCatchInformation()->GetTryEntry();
-      AddError(StringPrintf("Catch blocks should not be try blocks but catch block %d "
-                            "has try entry %s:%d.",
-                            block->GetBlockId(),
-                            try_entry.DebugName(),
-                            try_entry.GetId()));
-    }
-
-    if (block->IsLoopHeader()) {
-      AddError(StringPrintf("Catch blocks should not be loop headers but catch block %d is.",
-                            block->GetBlockId()));
-    }
-  } else {
-    for (HBasicBlock* predecessor : block->GetPredecessors()) {
-      const HTryBoundary* incoming_try_entry = predecessor->ComputeTryEntryOfSuccessors();
-      if (block->IsTryBlock()) {
-        const HTryBoundary& stored_try_entry = block->GetTryCatchInformation()->GetTryEntry();
-        if (incoming_try_entry == nullptr) {
-          AddError(StringPrintf("Block %d has try entry %s:%d but no try entry follows "
-                                "from predecessor %d.",
-                                block->GetBlockId(),
-                                stored_try_entry.DebugName(),
-                                stored_try_entry.GetId(),
-                                predecessor->GetBlockId()));
-        } else if (!incoming_try_entry->HasSameExceptionHandlersAs(stored_try_entry)) {
-          AddError(StringPrintf("Block %d has try entry %s:%d which is not consistent "
-                                "with %s:%d that follows from predecessor %d.",
-                                block->GetBlockId(),
-                                stored_try_entry.DebugName(),
-                                stored_try_entry.GetId(),
-                                incoming_try_entry->DebugName(),
-                                incoming_try_entry->GetId(),
-                                predecessor->GetBlockId()));
-        }
-      } else if (incoming_try_entry != nullptr) {
-        AddError(StringPrintf("Block %d is not a try block but try entry %s:%d follows "
-                              "from predecessor %d.",
-                              block->GetBlockId(),
-                              incoming_try_entry->DebugName(),
-                              incoming_try_entry->GetId(),
-                              predecessor->GetBlockId()));
-      }
-    }
-  }
-
-  if (block->IsLoopHeader()) {
-    CheckLoop(block);
-  }
-}
-
-void SSAChecker::CheckLoop(HBasicBlock* loop_header) {
+void GraphChecker::HandleLoop(HBasicBlock* loop_header) {
   int id = loop_header->GetBlockId();
   HLoopInformation* loop_information = loop_header->GetLoopInformation();
 
@@ -582,92 +660,6 @@
   }
 }
 
-void SSAChecker::VisitInstruction(HInstruction* instruction) {
-  super_type::VisitInstruction(instruction);
-
-  // Ensure an instruction dominates all its uses.
-  for (HUseIterator<HInstruction*> use_it(instruction->GetUses());
-       !use_it.Done(); use_it.Advance()) {
-    HInstruction* use = use_it.Current()->GetUser();
-    if (!use->IsPhi() && !instruction->StrictlyDominates(use)) {
-      AddError(StringPrintf("Instruction %s:%d in block %d does not dominate "
-                            "use %s:%d in block %d.",
-                            instruction->DebugName(),
-                            instruction->GetId(),
-                            current_block_->GetBlockId(),
-                            use->DebugName(),
-                            use->GetId(),
-                            use->GetBlock()->GetBlockId()));
-    }
-  }
-
-  if (instruction->NeedsEnvironment() && !instruction->HasEnvironment()) {
-    AddError(StringPrintf("Instruction %s:%d in block %d requires an environment "
-                          "but does not have one.",
-                          instruction->DebugName(),
-                          instruction->GetId(),
-                          current_block_->GetBlockId()));
-  }
-
-  // Ensure an instruction having an environment is dominated by the
-  // instructions contained in the environment.
-  for (HEnvironment* environment = instruction->GetEnvironment();
-       environment != nullptr;
-       environment = environment->GetParent()) {
-    for (size_t i = 0, e = environment->Size(); i < e; ++i) {
-      HInstruction* env_instruction = environment->GetInstructionAt(i);
-      if (env_instruction != nullptr
-          && !env_instruction->StrictlyDominates(instruction)) {
-        AddError(StringPrintf("Instruction %d in environment of instruction %d "
-                              "from block %d does not dominate instruction %d.",
-                              env_instruction->GetId(),
-                              instruction->GetId(),
-                              current_block_->GetBlockId(),
-                              instruction->GetId()));
-      }
-    }
-  }
-
-  // Ensure that reference type instructions have reference type info.
-  if (instruction->GetType() == Primitive::kPrimNot) {
-    ScopedObjectAccess soa(Thread::Current());
-    if (!instruction->GetReferenceTypeInfo().IsValid()) {
-      AddError(StringPrintf("Reference type instruction %s:%d does not have "
-                            "valid reference type information.",
-                            instruction->DebugName(),
-                            instruction->GetId()));
-    }
-  }
-
-  if (instruction->CanThrowIntoCatchBlock()) {
-    // Find the top-level environment. This corresponds to the environment of
-    // the catch block since we do not inline methods with try/catch.
-    HEnvironment* environment = instruction->GetEnvironment();
-    while (environment->GetParent() != nullptr) {
-      environment = environment->GetParent();
-    }
-
-    // Find all catch blocks and test that `instruction` has an environment
-    // value for each one.
-    const HTryBoundary& entry = instruction->GetBlock()->GetTryCatchInformation()->GetTryEntry();
-    for (HBasicBlock* catch_block : entry.GetExceptionHandlers()) {
-      for (HInstructionIterator phi_it(catch_block->GetPhis()); !phi_it.Done(); phi_it.Advance()) {
-        HPhi* catch_phi = phi_it.Current()->AsPhi();
-        if (environment->GetInstructionAt(catch_phi->GetRegNumber()) == nullptr) {
-          AddError(StringPrintf("Instruction %s:%d throws into catch block %d "
-                                "with catch phi %d for vreg %d but its "
-                                "corresponding environment slot is empty.",
-                                instruction->DebugName(),
-                                instruction->GetId(),
-                                catch_block->GetBlockId(),
-                                catch_phi->GetId(),
-                                catch_phi->GetRegNumber()));
-        }
-      }
-    }
-  }
-}
-
 static Primitive::Type PrimitiveKind(Primitive::Type type) {
   switch (type) {
     case Primitive::kPrimBoolean:
@@ -710,7 +702,7 @@
   }
 }
 
-void SSAChecker::VisitPhi(HPhi* phi) {
+void GraphChecker::VisitPhi(HPhi* phi) {
   VisitInstruction(phi);
 
   // Ensure the first input of a phi is not itself.
@@ -846,7 +838,7 @@
   }
 }
 
-void SSAChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
+void GraphChecker::HandleBooleanInput(HInstruction* instruction, size_t input_index) {
   HInstruction* input = instruction->InputAt(input_index);
   if (input->IsIntConstant()) {
     int32_t value = input->AsIntConstant()->GetValue();
@@ -876,7 +868,7 @@
   }
 }
 
-void SSAChecker::VisitPackedSwitch(HPackedSwitch* instruction) {
+void GraphChecker::VisitPackedSwitch(HPackedSwitch* instruction) {
   VisitInstruction(instruction);
   // Check that the number of block successors matches the switch count plus
   // one for the default block.
@@ -892,22 +884,22 @@
   }
 }
 
-void SSAChecker::VisitIf(HIf* instruction) {
+void GraphChecker::VisitIf(HIf* instruction) {
   VisitInstruction(instruction);
   HandleBooleanInput(instruction, 0);
 }
 
-void SSAChecker::VisitSelect(HSelect* instruction) {
+void GraphChecker::VisitSelect(HSelect* instruction) {
   VisitInstruction(instruction);
   HandleBooleanInput(instruction, 2);
 }
 
-void SSAChecker::VisitBooleanNot(HBooleanNot* instruction) {
+void GraphChecker::VisitBooleanNot(HBooleanNot* instruction) {
   VisitInstruction(instruction);
   HandleBooleanInput(instruction, 0);
 }
 
-void SSAChecker::VisitCondition(HCondition* op) {
+void GraphChecker::VisitCondition(HCondition* op) {
   VisitInstruction(op);
   if (op->GetType() != Primitive::kPrimBoolean) {
     AddError(StringPrintf(
@@ -937,7 +929,7 @@
   }
 }
 
-void SSAChecker::VisitBinaryOperation(HBinaryOperation* op) {
+void GraphChecker::VisitBinaryOperation(HBinaryOperation* op) {
   VisitInstruction(op);
   if (op->IsUShr() || op->IsShr() || op->IsShl() || op->IsRor()) {
     if (PrimitiveKind(op->InputAt(1)->GetType()) != Primitive::kPrimInt) {
@@ -979,7 +971,7 @@
   }
 }
 
-void SSAChecker::VisitConstant(HConstant* instruction) {
+void GraphChecker::VisitConstant(HConstant* instruction) {
   HBasicBlock* block = instruction->GetBlock();
   if (!block->IsEntryBlock()) {
     AddError(StringPrintf(
@@ -990,7 +982,7 @@
   }
 }
 
-void SSAChecker::VisitBoundType(HBoundType* instruction) {
+void GraphChecker::VisitBoundType(HBoundType* instruction) {
   VisitInstruction(instruction);
 
   ScopedObjectAccess soa(Thread::Current());
diff --git a/compiler/optimizing/graph_checker.h b/compiler/optimizing/graph_checker.h
index 8724cde..52252cd 100644
--- a/compiler/optimizing/graph_checker.h
+++ b/compiler/optimizing/graph_checker.h
@@ -32,34 +32,38 @@
       dump_prefix_(dump_prefix),
       seen_ids_(graph->GetArena(), graph->GetCurrentInstructionId(), false) {}
 
-  // Check the whole graph (in insertion order).
-  virtual void Run() { VisitInsertionOrder(); }
+  // Check the whole graph (in reverse post-order).
+  void Run() {
+    // VisitReversePostOrder is used instead of VisitInsertionOrder,
+    // as the latter might visit dead blocks removed by the dominator
+    // computation.
+    VisitReversePostOrder();
+  }
 
-  // Check `block`.
   void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
 
-  // Check `instruction`.
   void VisitInstruction(HInstruction* instruction) OVERRIDE;
+  void VisitPhi(HPhi* phi) OVERRIDE;
 
-  // Perform control-flow graph checks on instruction.
-  void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE;
-
-  // Check that the HasBoundsChecks() flag is set for bounds checks.
+  void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE;
+  void VisitBooleanNot(HBooleanNot* instruction) OVERRIDE;
+  void VisitBoundType(HBoundType* instruction) OVERRIDE;
   void VisitBoundsCheck(HBoundsCheck* check) OVERRIDE;
-
-  // Check successors of blocks ending in TryBoundary.
-  void VisitTryBoundary(HTryBoundary* try_boundary) OVERRIDE;
-
-  // Check that LoadException is the first instruction in a catch block.
-  void VisitLoadException(HLoadException* load) OVERRIDE;
-
-  // Check that HCheckCast and HInstanceOf have HLoadClass as second input.
   void VisitCheckCast(HCheckCast* check) OVERRIDE;
+  void VisitCondition(HCondition* op) OVERRIDE;
+  void VisitConstant(HConstant* instruction) OVERRIDE;
+  void VisitIf(HIf* instruction) OVERRIDE;
   void VisitInstanceOf(HInstanceOf* check) OVERRIDE;
-
-  // Check that the Return and ReturnVoid jump to the exit block.
+  void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE;
+  void VisitLoadException(HLoadException* load) OVERRIDE;
+  void VisitPackedSwitch(HPackedSwitch* instruction) OVERRIDE;
   void VisitReturn(HReturn* ret) OVERRIDE;
   void VisitReturnVoid(HReturnVoid* ret) OVERRIDE;
+  void VisitSelect(HSelect* instruction) OVERRIDE;
+  void VisitTryBoundary(HTryBoundary* try_boundary) OVERRIDE;
+
+  void HandleLoop(HBasicBlock* loop_header);
+  void HandleBooleanInput(HInstruction* instruction, size_t input_index);
 
   // Was the last visit of the graph valid?
   bool IsValid() const {
@@ -97,46 +101,6 @@
   DISALLOW_COPY_AND_ASSIGN(GraphChecker);
 };
 
-
-// An SSA graph visitor performing various checks.
-class SSAChecker : public GraphChecker {
- public:
-  typedef GraphChecker super_type;
-
-  explicit SSAChecker(HGraph* graph)
-    : GraphChecker(graph, "art::SSAChecker: ") {}
-
-  // Check the whole graph (in reverse post-order).
-  void Run() OVERRIDE {
-    // VisitReversePostOrder is used instead of VisitInsertionOrder,
-    // as the latter might visit dead blocks removed by the dominator
-    // computation.
-    VisitReversePostOrder();
-  }
-
-  // Perform SSA form checks on `block`.
-  void VisitBasicBlock(HBasicBlock* block) OVERRIDE;
-  // Loop-related checks from block `loop_header`.
-  void CheckLoop(HBasicBlock* loop_header);
-
-  // Perform SSA form checks on instructions.
-  void VisitInstruction(HInstruction* instruction) OVERRIDE;
-  void VisitPhi(HPhi* phi) OVERRIDE;
-  void VisitBinaryOperation(HBinaryOperation* op) OVERRIDE;
-  void VisitCondition(HCondition* op) OVERRIDE;
-  void VisitIf(HIf* instruction) OVERRIDE;
-  void VisitPackedSwitch(HPackedSwitch* instruction) OVERRIDE;
-  void VisitSelect(HSelect* instruction) OVERRIDE;
-  void VisitBooleanNot(HBooleanNot* instruction) OVERRIDE;
-  void VisitConstant(HConstant* instruction) OVERRIDE;
-  void VisitBoundType(HBoundType* instruction) OVERRIDE;
-
-  void HandleBooleanInput(HInstruction* instruction, size_t input_index);
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(SSAChecker);
-};
-
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_GRAPH_CHECKER_H_
diff --git a/compiler/optimizing/graph_checker_test.cc b/compiler/optimizing/graph_checker_test.cc
index d10df4c..2b82319 100644
--- a/compiler/optimizing/graph_checker_test.cc
+++ b/compiler/optimizing/graph_checker_test.cc
@@ -38,6 +38,7 @@
   graph->AddBlock(exit_block);
   graph->SetExitBlock(exit_block);
   entry_block->AddSuccessor(exit_block);
+  graph->BuildDominatorTree();
   return graph;
 }
 
@@ -52,28 +53,16 @@
   ASSERT_TRUE(graph_checker.IsValid());
 }
 
-static void TestCodeSSA(const uint16_t* data) {
-  ArenaPool pool;
-  ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateCFG(&allocator, data);
-  ASSERT_NE(graph, nullptr);
+class GraphCheckerTest : public CommonCompilerTest {};
 
-  TransformToSsa(graph);
-
-  SSAChecker ssa_checker(graph);
-  ssa_checker.Run();
-  ASSERT_TRUE(ssa_checker.IsValid());
-}
-
-
-TEST(GraphChecker, ReturnVoid) {
+TEST_F(GraphCheckerTest, ReturnVoid) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
       Instruction::RETURN_VOID);
 
   TestCode(data);
 }
 
-TEST(GraphChecker, CFG1) {
+TEST_F(GraphCheckerTest, CFG1) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
       Instruction::GOTO | 0x100,
       Instruction::RETURN_VOID);
@@ -81,7 +70,7 @@
   TestCode(data);
 }
 
-TEST(GraphChecker, CFG2) {
+TEST_F(GraphCheckerTest, CFG2) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
@@ -91,7 +80,7 @@
   TestCode(data);
 }
 
-TEST(GraphChecker, CFG3) {
+TEST_F(GraphCheckerTest, CFG3) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 3,
@@ -103,7 +92,7 @@
 
 // Test case with an invalid graph containing inconsistent
 // predecessor/successor arcs in CFG.
-TEST(GraphChecker, InconsistentPredecessorsAndSuccessors) {
+TEST_F(GraphCheckerTest, InconsistentPredecessorsAndSuccessors) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
 
@@ -121,7 +110,7 @@
 
 // Test case with an invalid graph containing a non-branch last
 // instruction in a block.
-TEST(GraphChecker, BlockEndingWithNonBranchInstruction) {
+TEST_F(GraphCheckerTest, BlockEndingWithNonBranchInstruction) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
 
@@ -141,9 +130,7 @@
   ASSERT_FALSE(graph_checker.IsValid());
 }
 
-class SSACheckerTest : public CommonCompilerTest {};
-
-TEST_F(SSACheckerTest, SSAPhi) {
+TEST_F(GraphCheckerTest, SSAPhi) {
   // This code creates one Phi function during the conversion to SSA form.
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -151,7 +138,7 @@
     Instruction::CONST_4 | 4 << 12 | 0,
     Instruction::RETURN | 0 << 8);
 
-  TestCodeSSA(data);
+  TestCode(data);
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 9d796c1..4cf0eb1 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -22,6 +22,7 @@
 #include <sstream>
 
 #include "bounds_check_elimination.h"
+#include "builder.h"
 #include "code_generator.h"
 #include "dead_code_elimination.h"
 #include "disassembler.h"
@@ -31,7 +32,6 @@
 #include "optimization.h"
 #include "reference_type_propagation.h"
 #include "register_allocator.h"
-#include "ssa_builder.h"
 #include "ssa_liveness_analysis.h"
 #include "utils/assembler.h"
 
@@ -368,11 +368,13 @@
   }
 
   void VisitCheckCast(HCheckCast* check_cast) OVERRIDE {
+    StartAttributeStream("check_kind") << check_cast->GetTypeCheckKind();
     StartAttributeStream("must_do_null_check") << std::boolalpha
         << check_cast->MustDoNullCheck() << std::noboolalpha;
   }
 
   void VisitInstanceOf(HInstanceOf* instance_of) OVERRIDE {
+    StartAttributeStream("check_kind") << instance_of->GetTypeCheckKind();
     StartAttributeStream("must_do_null_check") << std::boolalpha
         << instance_of->MustDoNullCheck() << std::noboolalpha;
   }
@@ -508,7 +510,7 @@
         || IsPass(HDeadCodeElimination::kInitialDeadCodeEliminationPassName)
         || IsPass(BoundsCheckElimination::kBoundsCheckEliminationPassName)
         || IsPass(RegisterAllocator::kRegisterAllocatorPassName)
-        || IsPass(SsaBuilder::kSsaBuilderPassName)) {
+        || IsPass(HGraphBuilder::kBuilderPassName)) {
       HLoopInformation* info = instruction->GetBlock()->GetLoopInformation();
       if (info == nullptr) {
         StartAttributeStream("loop") << "none";
@@ -525,7 +527,7 @@
       }
     }
 
-    if ((IsPass(SsaBuilder::kSsaBuilderPassName)
+    if ((IsPass(HGraphBuilder::kBuilderPassName)
         || IsPass(HInliner::kInlinerPassName))
         && (instruction->GetType() == Primitive::kPrimNot)) {
       ReferenceTypeInfo info = instruction->IsLoadClass()
@@ -545,7 +547,7 @@
         // doesn't run or doesn't inline anything, the NullConstant remains untyped.
         // So we should check NullConstants for validity only after reference type propagation.
         DCHECK(graph_in_bad_state_ ||
-               (!is_after_pass_ && IsPass(SsaBuilder::kSsaBuilderPassName)))
+               (!is_after_pass_ && IsPass(HGraphBuilder::kBuilderPassName)))
             << instruction->DebugName() << instruction->GetId() << " has invalid rti "
             << (is_after_pass_ ? "after" : "before") << " pass " << pass_name_;
       }
diff --git a/compiler/optimizing/gvn_test.cc b/compiler/optimizing/gvn_test.cc
index 1f4eaf3..56dc088 100644
--- a/compiler/optimizing/gvn_test.cc
+++ b/compiler/optimizing/gvn_test.cc
@@ -100,7 +100,7 @@
   ASSERT_EQ(different_offset->GetBlock(), block);
   ASSERT_EQ(use_after_kill->GetBlock(), block);
 
-  TransformToSsa(graph);
+  graph->BuildDominatorTree();
   SideEffectsAnalysis side_effects(graph);
   side_effects.Run();
   GVNOptimization(graph, side_effects).Run();
@@ -182,7 +182,7 @@
                                                           0));
   join->AddInstruction(new (&allocator) HExit());
 
-  TransformToSsa(graph);
+  graph->BuildDominatorTree();
   SideEffectsAnalysis side_effects(graph);
   side_effects.Run();
   GVNOptimization(graph, side_effects).Run();
@@ -288,7 +288,7 @@
   ASSERT_EQ(field_get_in_loop_body->GetBlock(), loop_body);
   ASSERT_EQ(field_get_in_exit->GetBlock(), exit);
 
-  TransformToSsa(graph);
+  graph->BuildDominatorTree();
   {
     SideEffectsAnalysis side_effects(graph);
     side_effects.Run();
@@ -364,7 +364,7 @@
   inner_loop_exit->AddInstruction(new (&allocator) HGoto());
   outer_loop_exit->AddInstruction(new (&allocator) HExit());
 
-  TransformToSsa(graph);
+  graph->BuildDominatorTree();
 
   ASSERT_TRUE(inner_loop_header->GetLoopInformation()->IsIn(
       *outer_loop_header->GetLoopInformation()));
diff --git a/compiler/optimizing/induction_var_analysis_test.cc b/compiler/optimizing/induction_var_analysis_test.cc
index 29a1845..89e4690 100644
--- a/compiler/optimizing/induction_var_analysis_test.cc
+++ b/compiler/optimizing/induction_var_analysis_test.cc
@@ -86,39 +86,28 @@
     constant1_ = graph_->GetIntConstant(1);
     constant100_ = graph_->GetIntConstant(100);
     float_constant0_ = graph_->GetFloatConstant(0.0f);
-    induc_ = new (&allocator_) HLocal(n);
-    entry_->AddInstruction(induc_);
-    entry_->AddInstruction(new (&allocator_) HStoreLocal(induc_, constant0_));
-    tmp_ = new (&allocator_) HLocal(n + 1);
-    entry_->AddInstruction(tmp_);
-    entry_->AddInstruction(new (&allocator_) HStoreLocal(tmp_, constant100_));
-    dum_ = new (&allocator_) HLocal(n + 2);
-    entry_->AddInstruction(dum_);
     return_->AddInstruction(new (&allocator_) HReturnVoid());
     exit_->AddInstruction(new (&allocator_) HExit());
 
     // Provide loop instructions.
     for (int d = 0; d < n; d++) {
-      basic_[d] = new (&allocator_) HLocal(d);
-      entry_->AddInstruction(basic_[d]);
-      loop_preheader_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], constant0_));
+      basic_[d] = new (&allocator_) HPhi(&allocator_, d, 0, Primitive::kPrimInt);
       loop_preheader_[d]->AddInstruction(new (&allocator_) HGoto());
-      HInstruction* load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
-      loop_header_[d]->AddInstruction(load);
-      HInstruction* compare = new (&allocator_) HLessThan(load, constant100_);
+      loop_header_[d]->AddPhi(basic_[d]);
+      HInstruction* compare = new (&allocator_) HLessThan(basic_[d], constant100_);
       loop_header_[d]->AddInstruction(compare);
       loop_header_[d]->AddInstruction(new (&allocator_) HIf(compare));
-      load = new (&allocator_) HLoadLocal(basic_[d], Primitive::kPrimInt);
-      loop_body_[d]->AddInstruction(load);
-      increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, load, constant1_);
+      increment_[d] = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[d], constant1_);
       loop_body_[d]->AddInstruction(increment_[d]);
-      loop_body_[d]->AddInstruction(new (&allocator_) HStoreLocal(basic_[d], increment_[d]));
       loop_body_[d]->AddInstruction(new (&allocator_) HGoto());
+
+      basic_[d]->AddInput(constant0_);
+      basic_[d]->AddInput(increment_[d]);
     }
   }
 
   // Builds if-statement at depth d.
-  void BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
+  HPhi* BuildIf(int d, HBasicBlock** ifT, HBasicBlock **ifF) {
     HBasicBlock* cond = new (&allocator_) HBasicBlock(graph_);
     HBasicBlock* ifTrue = new (&allocator_) HBasicBlock(graph_);
     HBasicBlock* ifFalse = new (&allocator_) HBasicBlock(graph_);
@@ -134,6 +123,10 @@
     cond->AddInstruction(new (&allocator_) HIf(parameter_));
     *ifT = ifTrue;
     *ifF = ifFalse;
+
+    HPhi* select_phi = new (&allocator_) HPhi(&allocator_, -1, 0, Primitive::kPrimInt);
+    loop_body_[d]->AddPhi(select_phi);
+    return select_phi;
   }
 
   // Inserts instruction right before increment at depth d.
@@ -142,25 +135,20 @@
     return instruction;
   }
 
-  // Inserts local load at depth d.
-  HInstruction* InsertLocalLoad(HLocal* local, int d) {
-    return InsertInstruction(new (&allocator_) HLoadLocal(local, Primitive::kPrimInt), d);
+  // Inserts a phi to loop header at depth d and returns it.
+  HPhi* InsertLoopPhi(int vreg, int d) {
+    HPhi* phi = new (&allocator_) HPhi(&allocator_, vreg, 0, Primitive::kPrimInt);
+    loop_header_[d]->AddPhi(phi);
+    return phi;
   }
 
-  // Inserts local store at depth d.
-  HInstruction* InsertLocalStore(HLocal* local, HInstruction* rhs, int d) {
-    return InsertInstruction(new (&allocator_) HStoreLocal(local, rhs), d);
-  }
-
-  // Inserts an array store with given local as subscript at depth d to
+  // Inserts an array store with given `subscript` at depth d to
   // enable tests to inspect the computed induction at that point easily.
-  HInstruction* InsertArrayStore(HLocal* subscript, int d) {
-    HInstruction* load = InsertInstruction(
-        new (&allocator_) HLoadLocal(subscript, Primitive::kPrimInt), d);
+  HInstruction* InsertArrayStore(HInstruction* subscript, int d) {
     // ArraySet is given a float value in order to avoid SsaBuilder typing
     // it from the array's non-existent reference type info.
     return InsertInstruction(new (&allocator_) HArraySet(
-        parameter_, load, float_constant0_, Primitive::kPrimFloat, 0), d);
+        parameter_, subscript, float_constant0_, Primitive::kPrimFloat, 0), d);
   }
 
   // Returns induction information of instruction in loop at depth d.
@@ -171,7 +159,7 @@
 
   // Performs InductionVarAnalysis (after proper set up).
   void PerformInductionVarAnalysis() {
-    TransformToSsa(graph_);
+    graph_->BuildDominatorTree();
     iva_ = new (&allocator_) HInductionVarAnalysis(graph_);
     iva_->Run();
   }
@@ -191,16 +179,13 @@
   HInstruction* constant1_;
   HInstruction* constant100_;
   HInstruction* float_constant0_;
-  HLocal* induc_;  // "vreg_n", the "k"
-  HLocal* tmp_;    // "vreg_n+1"
-  HLocal* dum_;    // "vreg_n+2"
 
   // Loop specifics.
   HBasicBlock* loop_preheader_[10];
   HBasicBlock* loop_header_[10];
   HBasicBlock* loop_body_[10];
   HInstruction* increment_[10];
-  HLocal* basic_[10];  // "vreg_d", the "i_d"
+  HPhi* basic_[10];  // "vreg_d", the "i_d"
 };
 
 //
@@ -216,7 +201,7 @@
   //   ..
   // }
   BuildLoopNest(10);
-  TransformToSsa(graph_);
+  graph_->BuildDominatorTree();
   ASSERT_EQ(entry_->GetLoopInformation(), nullptr);
   for (int d = 0; d < 1; d++) {
     ASSERT_EQ(loop_preheader_[d]->GetLoopInformation(),
@@ -258,20 +243,15 @@
   // }
   BuildLoopNest(1);
   HInstruction *add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
-  InsertLocalStore(induc_, add, 0);
+      new (&allocator_) HAdd(Primitive::kPrimInt, constant100_, basic_[0]), 0);
   HInstruction *sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
-  InsertLocalStore(induc_, sub, 0);
+      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
   HInstruction *mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
-  InsertLocalStore(induc_, mul, 0);
+      new (&allocator_) HMul(Primitive::kPrimInt, constant100_, basic_[0]), 0);
   HInstruction *shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0);
-  InsertLocalStore(induc_, shl, 0);
+      new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0);
   HInstruction *neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0)), 0);
-  InsertLocalStore(induc_, neg, 0);
+      new (&allocator_) HNeg(Primitive::kPrimInt, basic_[0]), 0);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("((1) * i + (100))", GetInductionInfo(add, 0).c_str());
@@ -291,14 +271,16 @@
   //   a[k] = 0;
   // }
   BuildLoopNest(1);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant0_);
+
   HInstruction *add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
-  InsertLocalStore(induc_, add, 0);
-  HInstruction* store1 = InsertArrayStore(induc_, 0);
+      new (&allocator_) HAdd(Primitive::kPrimInt, k, constant100_), 0);
+  HInstruction* store1 = InsertArrayStore(add, 0);
   HInstruction *sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
-  InsertLocalStore(induc_, sub, 0);
-  HInstruction* store2 = InsertArrayStore(induc_, 0);
+      new (&allocator_) HSub(Primitive::kPrimInt, add, constant1_), 0);
+  HInstruction* store2 = InsertArrayStore(sub, 0);
+  k->AddInput(sub);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("(((100) - (1)) * i + (100))",
@@ -316,23 +298,24 @@
   //   a[k] = 0;
   // }
   BuildLoopNest(1);
+  HPhi* k_header = InsertLoopPhi(0, 0);
+  k_header->AddInput(constant0_);
+
   HBasicBlock* ifTrue;
   HBasicBlock* ifFalse;
-  BuildIf(0, &ifTrue, &ifFalse);
+  HPhi* k_body = BuildIf(0, &ifTrue, &ifFalse);
+
   // True-branch.
-  HInstruction* load1 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
-  ifTrue->AddInstruction(load1);
-  HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
+  HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
   ifTrue->AddInstruction(inc1);
-  ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
+  k_body->AddInput(inc1);
   // False-branch.
-  HInstruction* load2 = new (&allocator_) HLoadLocal(induc_, Primitive::kPrimInt);
-  ifFalse->AddInstruction(load2);
-  HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
+  HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, k_header, constant1_);
   ifFalse->AddInstruction(inc2);
-  ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
+  k_body->AddInput(inc2);
   // Merge over a phi.
-  HInstruction* store = InsertArrayStore(induc_, 0);
+  HInstruction* store = InsertArrayStore(k_body, 0);
+  k_header->AddInput(k_body);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
@@ -348,21 +331,18 @@
   BuildLoopNest(1);
   HBasicBlock* ifTrue;
   HBasicBlock* ifFalse;
-  BuildIf(0, &ifTrue, &ifFalse);
+  HPhi* k = BuildIf(0, &ifTrue, &ifFalse);
+
   // True-branch.
-  HInstruction* load1 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
-  ifTrue->AddInstruction(load1);
-  HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, load1, constant1_);
+  HInstruction* inc1 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
   ifTrue->AddInstruction(inc1);
-  ifTrue->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc1));
+  k->AddInput(inc1);
   // False-branch.
-  HInstruction* load2 = new (&allocator_) HLoadLocal(basic_[0], Primitive::kPrimInt);
-  ifFalse->AddInstruction(load2);
-  HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, load2, constant1_);
+  HInstruction* inc2 = new (&allocator_) HAdd(Primitive::kPrimInt, basic_[0], constant1_);
   ifFalse->AddInstruction(inc2);
-  ifFalse->AddInstruction(new (&allocator_) HStoreLocal(induc_, inc2));
+  k->AddInput(inc2);
   // Merge over a phi.
-  HInstruction* store = InsertArrayStore(induc_, 0);
+  HInstruction* store = InsertArrayStore(k, 0);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("((1) * i + (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
@@ -376,10 +356,13 @@
   //   k = 100 - i;
   // }
   BuildLoopNest(1);
-  HInstruction* store = InsertArrayStore(induc_, 0);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant0_);
+
+  HInstruction* store = InsertArrayStore(k, 0);
   HInstruction *sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
-  InsertLocalStore(induc_, sub, 0);
+      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0]), 0);
+  k->AddInput(sub);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("wrap((0), (( - (1)) * i + (100)))",
@@ -396,11 +379,16 @@
   //   t = 100 - i;
   // }
   BuildLoopNest(1);
-  HInstruction* store = InsertArrayStore(induc_, 0);
-  InsertLocalStore(induc_, InsertLocalLoad(tmp_, 0), 0);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant0_);
+  HPhi* t = InsertLoopPhi(1, 0);
+  t->AddInput(constant100_);
+
+  HInstruction* store = InsertArrayStore(k, 0);
+  k->AddInput(t);
   HInstruction *sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, InsertLocalLoad(basic_[0], 0)), 0);
-  InsertLocalStore(tmp_, sub, 0);
+      new (&allocator_) HSub(Primitive::kPrimInt, constant100_, basic_[0], 0), 0);
+  t->AddInput(sub);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("wrap((0), wrap((100), (( - (1)) * i + (100))))",
@@ -419,26 +407,21 @@
   //   k = i << 1;
   // }
   BuildLoopNest(1);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant0_);
+
   HInstruction *add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
-  InsertLocalStore(tmp_, add, 0);
+      new (&allocator_) HAdd(Primitive::kPrimInt, k, constant100_), 0);
   HInstruction *sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
-  InsertLocalStore(tmp_, sub, 0);
+      new (&allocator_) HSub(Primitive::kPrimInt, k, constant100_), 0);
   HInstruction *mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
-  InsertLocalStore(tmp_, mul, 0);
+      new (&allocator_) HMul(Primitive::kPrimInt, k, constant100_), 0);
   HInstruction *shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
-  InsertLocalStore(tmp_, shl, 0);
+      new (&allocator_) HShl(Primitive::kPrimInt, k, constant1_), 0);
   HInstruction *neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
-  InsertLocalStore(tmp_, neg, 0);
-  InsertLocalStore(
-      induc_,
-      InsertInstruction(
-          new (&allocator_)
-          HShl(Primitive::kPrimInt, InsertLocalLoad(basic_[0], 0), constant1_), 0), 0);
+      new (&allocator_) HNeg(Primitive::kPrimInt, k), 0);
+  k->AddInput(
+      InsertInstruction(new (&allocator_) HShl(Primitive::kPrimInt, basic_[0], constant1_), 0));
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("wrap((100), ((2) * i + (100)))", GetInductionInfo(add, 0).c_str());
@@ -461,11 +444,15 @@
   //   k = d;
   // }
   BuildLoopNest(1);
-  HInstruction* store1 = InsertArrayStore(induc_, 0);
-  HInstruction* store2 = InsertArrayStore(tmp_, 0);
-  InsertLocalStore(dum_, InsertLocalLoad(tmp_, 0), 0);
-  InsertLocalStore(tmp_, InsertLocalLoad(induc_, 0), 0);
-  InsertLocalStore(induc_, InsertLocalLoad(dum_, 0), 0);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant0_);
+  HPhi* t = InsertLoopPhi(1, 0);
+  t->AddInput(constant100_);
+
+  HInstruction* store1 = InsertArrayStore(k, 0);
+  HInstruction* store2 = InsertArrayStore(t, 0);
+  k->AddInput(t);
+  t->AddInput(k);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("periodic((0), (100))", GetInductionInfo(store1->InputAt(1), 0).c_str());
@@ -480,10 +467,13 @@
   //   k = 1 - k;
   // }
   BuildLoopNest(1);
-  HInstruction* store = InsertArrayStore(induc_, 0);
+  HPhi* k = InsertLoopPhi(0, 0);
+  k->AddInput(constant0_);
+
+  HInstruction* store = InsertArrayStore(k, 0);
   HInstruction *sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0);
-  InsertLocalStore(induc_, sub, 0);
+      new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k), 0);
+  k->AddInput(sub);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("periodic((0), (1))", GetInductionInfo(store->InputAt(1), 0).c_str());
@@ -502,26 +492,24 @@
   //   t = - k;
   // }
   BuildLoopNest(1);
-  InsertLocalStore(
-      induc_,
-      InsertInstruction(new (&allocator_)
-                        HSub(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 0)), 0), 0);
+  HPhi* k_header = InsertLoopPhi(0, 0);
+  k_header->AddInput(constant0_);
+
+  HInstruction* k_body = InsertInstruction(
+      new (&allocator_) HSub(Primitive::kPrimInt, constant1_, k_header), 0);
+  k_header->AddInput(k_body);
+
   // Derived expressions.
   HInstruction *add = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
-  InsertLocalStore(tmp_, add, 0);
+      new (&allocator_) HAdd(Primitive::kPrimInt, k_body, constant100_), 0);
   HInstruction *sub = InsertInstruction(
-      new (&allocator_) HSub(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
-  InsertLocalStore(tmp_, sub, 0);
+      new (&allocator_) HSub(Primitive::kPrimInt, k_body, constant100_), 0);
   HInstruction *mul = InsertInstruction(
-      new (&allocator_) HMul(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant100_), 0);
-  InsertLocalStore(tmp_, mul, 0);
+      new (&allocator_) HMul(Primitive::kPrimInt, k_body, constant100_), 0);
   HInstruction *shl = InsertInstruction(
-      new (&allocator_) HShl(Primitive::kPrimInt, InsertLocalLoad(induc_, 0), constant1_), 0);
-  InsertLocalStore(tmp_, shl, 0);
+      new (&allocator_) HShl(Primitive::kPrimInt, k_body, constant1_), 0);
   HInstruction *neg = InsertInstruction(
-      new (&allocator_) HNeg(Primitive::kPrimInt, InsertLocalLoad(induc_, 0)), 0);
-  InsertLocalStore(tmp_, neg, 0);
+      new (&allocator_) HNeg(Primitive::kPrimInt, k_body), 0);
   PerformInductionVarAnalysis();
 
   EXPECT_STREQ("periodic(((1) + (100)), (100))", GetInductionInfo(add, 0).c_str());
@@ -543,10 +531,20 @@
   //   ..
   // }
   BuildLoopNest(10);
+
+  HPhi* k[10];
+  for (int d = 0; d < 10; d++) {
+    k[d] = InsertLoopPhi(0, d);
+  }
+
   HInstruction *inc = InsertInstruction(
-      new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, InsertLocalLoad(induc_, 9)), 9);
-  InsertLocalStore(induc_, inc, 9);
-  HInstruction* store = InsertArrayStore(induc_, 9);
+      new (&allocator_) HAdd(Primitive::kPrimInt, constant1_, k[9]), 9);
+  HInstruction* store = InsertArrayStore(inc, 9);
+
+  for (int d = 0; d < 10; d++) {
+    k[d]->AddInput((d != 0) ? k[d - 1] : constant0_);
+    k[d]->AddInput((d != 9) ? k[d + 1] : inc);
+  }
   PerformInductionVarAnalysis();
 
   // Avoid exact phi number, since that depends on the SSA building phase.
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index ae15fcf..9566c29 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -93,7 +93,7 @@
   DCHECK(induction_analysis != nullptr);
 }
 
-void InductionVarRange::GetInductionRange(HInstruction* context,
+bool InductionVarRange::GetInductionRange(HInstruction* context,
                                           HInstruction* instruction,
                                           /*out*/Value* min_val,
                                           /*out*/Value* max_val,
@@ -111,12 +111,9 @@
     *min_val = GetVal(info, trip, in_body, /* is_min */ true);
     *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
     *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
-  } else {
-    // No loop to analyze.
-    *min_val = Value();
-    *max_val = Value();
-    *needs_finite_test = false;
+    return true;
   }
+  return false;  // Nothing known
 }
 
 bool InductionVarRange::RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) const {
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
index 974b8fb..3cb7b4b 100644
--- a/compiler/optimizing/induction_var_range.h
+++ b/compiler/optimizing/induction_var_range.h
@@ -60,13 +60,13 @@
    * Given a context denoted by the first instruction, returns a possibly conservative
    * lower and upper bound on the instruction's value in the output parameters min_val
    * and max_val, respectively. The need_finite_test flag denotes if an additional finite-test
-   * is needed to protect the range evaluation inside its loop.
+   * is needed to protect the range evaluation inside its loop. Returns false on failure.
    */
-  void GetInductionRange(HInstruction* context,
+  bool GetInductionRange(HInstruction* context,
                          HInstruction* instruction,
-                         /*out*/Value* min_val,
-                         /*out*/Value* max_val,
-                         /*out*/bool* needs_finite_test);
+                         /*out*/ Value* min_val,
+                         /*out*/ Value* max_val,
+                         /*out*/ bool* needs_finite_test);
 
   /** Refines the values with induction of next outer loop. Returns true on change. */
   bool RefineOuter(/*in-out*/Value* min_val, /*in-out*/Value* max_val) const;
@@ -79,8 +79,8 @@
    */
   bool CanGenerateCode(HInstruction* context,
                        HInstruction* instruction,
-                       /*out*/bool* needs_finite_test,
-                       /*out*/bool* needs_taken_test);
+                       /*out*/ bool* needs_finite_test,
+                       /*out*/ bool* needs_taken_test);
 
   /**
    * Generates the actual code in the HIR for the lower and upper bound expressions on the
@@ -101,8 +101,8 @@
                          HInstruction* instruction,
                          HGraph* graph,
                          HBasicBlock* block,
-                         /*out*/HInstruction** lower,
-                         /*out*/HInstruction** upper);
+                         /*out*/ HInstruction** lower,
+                         /*out*/ HInstruction** upper);
 
   /**
    * Generates explicit taken-test for the loop in the given context. Code is generated in
@@ -113,7 +113,7 @@
   void GenerateTakenTest(HInstruction* context,
                          HGraph* graph,
                          HBasicBlock* block,
-                         /*out*/HInstruction** taken_test);
+                         /*out*/ HInstruction** taken_test);
 
  private:
   bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const;
@@ -168,17 +168,17 @@
                     HInstruction* instruction,
                     HGraph* graph,
                     HBasicBlock* block,
-                    /*out*/HInstruction** lower,
-                    /*out*/HInstruction** upper,
-                    /*out*/HInstruction** taken_test,
-                    /*out*/bool* needs_finite_test,
-                    /*out*/bool* needs_taken_test) const;
+                    /*out*/ HInstruction** lower,
+                    /*out*/ HInstruction** upper,
+                    /*out*/ HInstruction** taken_test,
+                    /*out*/ bool* needs_finite_test,
+                    /*out*/ bool* needs_taken_test) const;
 
   bool GenerateCode(HInductionVarAnalysis::InductionInfo* info,
                     HInductionVarAnalysis::InductionInfo* trip,
                     HGraph* graph,
                     HBasicBlock* block,
-                    /*out*/HInstruction** result,
+                    /*out*/ HInstruction** result,
                     bool in_body,
                     bool is_min) const;
 
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index eda9c01..55a654e 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -86,25 +86,20 @@
     loop_body->AddSuccessor(loop_header);
     return_block->AddSuccessor(exit_block_);
     // Instructions.
-    HLocal* induc = new (&allocator_) HLocal(0);
-    entry_block_->AddInstruction(induc);
-    loop_preheader_->AddInstruction(
-        new (&allocator_) HStoreLocal(induc, graph_->GetIntConstant(lower)));  // i = l
     loop_preheader_->AddInstruction(new (&allocator_) HGoto());
-    HInstruction* load = new (&allocator_) HLoadLocal(induc, Primitive::kPrimInt);
-          loop_header->AddInstruction(load);
+    HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
+    loop_header->AddPhi(phi);
+    phi->AddInput(graph_->GetIntConstant(lower));  // i = l
     if (stride > 0) {
-      condition_ = new (&allocator_) HLessThan(load, upper);  // i < u
+      condition_ = new (&allocator_) HLessThan(phi, upper);  // i < u
     } else {
-      condition_ = new (&allocator_) HGreaterThan(load, upper);  // i > u
+      condition_ = new (&allocator_) HGreaterThan(phi, upper);  // i > u
     }
     loop_header->AddInstruction(condition_);
     loop_header->AddInstruction(new (&allocator_) HIf(condition_));
-    load = new (&allocator_) HLoadLocal(induc, Primitive::kPrimInt);
-    loop_body->AddInstruction(load);
-    increment_ = new (&allocator_) HAdd(Primitive::kPrimInt, load, graph_->GetIntConstant(stride));
-    loop_body->AddInstruction(increment_);
-    loop_body->AddInstruction(new (&allocator_) HStoreLocal(induc, increment_));  // i += s
+    increment_ = new (&allocator_) HAdd(Primitive::kPrimInt, phi, graph_->GetIntConstant(stride));
+    loop_body->AddInstruction(increment_);  // i += s
+    phi->AddInput(increment_);
     loop_body->AddInstruction(new (&allocator_) HGoto());
     return_block->AddInstruction(new (&allocator_) HReturnVoid());
     exit_block_->AddInstruction(new (&allocator_) HExit());
@@ -112,7 +107,7 @@
 
   /** Constructs SSA and performs induction variable analysis. */
   void PerformInductionVarAnalysis() {
-    TransformToSsa(graph_);
+    graph_->BuildDominatorTree();
     iva_->Run();
   }
 
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 9b91b53..a5acab8 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -258,8 +258,9 @@
   }
 
   if (actual_method != nullptr) {
-    return TryInline(invoke_instruction, actual_method);
+    return TryInlineAndReplace(invoke_instruction, actual_method, /* do_rtp */ true);
   }
+
   DCHECK(!invoke_instruction->IsInvokeStaticOrDirect());
 
   // Check if we can use an inline cache.
@@ -344,7 +345,7 @@
   HInstruction* cursor = invoke_instruction->GetPrevious();
   HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
 
-  if (!TryInline(invoke_instruction, resolved_method, /* do_rtp */ false)) {
+  if (!TryInlineAndReplace(invoke_instruction, resolved_method, /* do_rtp */ false)) {
     return false;
   }
 
@@ -378,7 +379,7 @@
 
   // Run type propagation to get the guard typed, and eventually propagate the
   // type of the receiver.
-  ReferenceTypePropagation rtp_fixup(graph_, handles_);
+  ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
   rtp_fixup.Run();
 
   MaybeRecordStat(kInlinedMonomorphicCall);
@@ -420,6 +421,9 @@
       actual_method = new_method;
     } else if (actual_method != new_method) {
       // Different methods, bailout.
+      VLOG(compiler) << "Call to " << PrettyMethod(resolved_method)
+                     << " from inline cache is not inlined because it resolves"
+                     << " to different methods";
       return false;
     }
   }
@@ -428,7 +432,7 @@
   HInstruction* cursor = invoke_instruction->GetPrevious();
   HBasicBlock* bb_cursor = invoke_instruction->GetBlock();
 
-  if (!TryInline(invoke_instruction, actual_method, /* do_rtp */ false)) {
+  if (!TryInlineAndReplace(invoke_instruction, actual_method, /* do_rtp */ false)) {
     return false;
   }
 
@@ -474,7 +478,7 @@
   deoptimize->CopyEnvironmentFrom(invoke_instruction->GetEnvironment());
 
   // Run type propagation to get the guard typed.
-  ReferenceTypePropagation rtp_fixup(graph_, handles_);
+  ReferenceTypePropagation rtp_fixup(graph_, handles_, /* is_first_run */ false);
   rtp_fixup.Run();
 
   MaybeRecordStat(kInlinedPolymorphicCall);
@@ -482,14 +486,29 @@
   return true;
 }
 
-bool HInliner::TryInline(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) {
+bool HInliner::TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* method, bool do_rtp) {
+  HInstruction* return_replacement = nullptr;
+  if (!TryBuildAndInline(invoke_instruction, method, &return_replacement)) {
+    return false;
+  }
+  if (return_replacement != nullptr) {
+    invoke_instruction->ReplaceWith(return_replacement);
+  }
+  invoke_instruction->GetBlock()->RemoveInstruction(invoke_instruction);
+  FixUpReturnReferenceType(invoke_instruction, method, return_replacement, do_rtp);
+  return true;
+}
+
+bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction,
+                                 ArtMethod* method,
+                                 HInstruction** return_replacement) {
   const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
 
   // Check whether we're allowed to inline. The outermost compilation unit is the relevant
   // dex file here (though the transitivity of an inline chain would allow checking the calller).
   if (!compiler_driver_->MayInline(method->GetDexFile(),
                                    outer_compilation_unit_.GetDexFile())) {
-    if (TryPatternSubstitution(invoke_instruction, method, do_rtp)) {
+    if (TryPatternSubstitution(invoke_instruction, method, return_replacement)) {
       VLOG(compiler) << "Successfully replaced pattern of invoke " << PrettyMethod(method);
       MaybeRecordStat(kReplacedInvokeWithSimplePattern);
       return true;
@@ -556,7 +575,7 @@
     return false;
   }
 
-  if (!TryBuildAndInline(method, invoke_instruction, same_dex_file, do_rtp)) {
+  if (!TryBuildAndInlineHelper(invoke_instruction, method, same_dex_file, return_replacement)) {
     return false;
   }
 
@@ -583,27 +602,27 @@
 // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
 bool HInliner::TryPatternSubstitution(HInvoke* invoke_instruction,
                                       ArtMethod* resolved_method,
-                                      bool do_rtp) {
+                                      HInstruction** return_replacement) {
   InlineMethod inline_method;
   if (!InlineMethodAnalyser::AnalyseMethodCode(resolved_method, &inline_method)) {
     return false;
   }
 
-  HInstruction* return_replacement = nullptr;
   switch (inline_method.opcode) {
     case kInlineOpNop:
       DCHECK_EQ(invoke_instruction->GetType(), Primitive::kPrimVoid);
+      *return_replacement = nullptr;
       break;
     case kInlineOpReturnArg:
-      return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction,
-                                                         inline_method.d.return_data.arg);
+      *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction,
+                                                          inline_method.d.return_data.arg);
       break;
     case kInlineOpNonWideConst:
       if (resolved_method->GetShorty()[0] == 'L') {
         DCHECK_EQ(inline_method.d.data, 0u);
-        return_replacement = graph_->GetNullConstant();
+        *return_replacement = graph_->GetNullConstant();
       } else {
-        return_replacement = graph_->GetIntConstant(static_cast<int32_t>(inline_method.d.data));
+        *return_replacement = graph_->GetIntConstant(static_cast<int32_t>(inline_method.d.data));
       }
       break;
     case kInlineOpIGet: {
@@ -612,12 +631,13 @@
         // TODO: Needs null check.
         return false;
       }
+      Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
       HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
-      HInstanceFieldGet* iget = CreateInstanceFieldGet(resolved_method, data.field_idx, obj);
+      HInstanceFieldGet* iget = CreateInstanceFieldGet(dex_cache, data.field_idx, obj);
       DCHECK_EQ(iget->GetFieldOffset().Uint32Value(), data.field_offset);
       DCHECK_EQ(iget->IsVolatile() ? 1u : 0u, data.is_volatile);
       invoke_instruction->GetBlock()->InsertInstructionBefore(iget, invoke_instruction);
-      return_replacement = iget;
+      *return_replacement = iget;
       break;
     }
     case kInlineOpIPut: {
@@ -626,37 +646,84 @@
         // TODO: Needs null check.
         return false;
       }
+      Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
       HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, data.object_arg);
       HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, data.src_arg);
-      HInstanceFieldSet* iput = CreateInstanceFieldSet(resolved_method, data.field_idx, obj, value);
+      HInstanceFieldSet* iput = CreateInstanceFieldSet(dex_cache, data.field_idx, obj, value);
       DCHECK_EQ(iput->GetFieldOffset().Uint32Value(), data.field_offset);
       DCHECK_EQ(iput->IsVolatile() ? 1u : 0u, data.is_volatile);
       invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
       if (data.return_arg_plus1 != 0u) {
         size_t return_arg = data.return_arg_plus1 - 1u;
-        return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction, return_arg);
+        *return_replacement = GetInvokeInputForArgVRegIndex(invoke_instruction, return_arg);
       }
       break;
     }
+    case kInlineOpConstructor: {
+      const InlineConstructorData& data = inline_method.d.constructor_data;
+      // Get the indexes to arrays for easier processing.
+      uint16_t iput_field_indexes[] = {
+          data.iput0_field_index, data.iput1_field_index, data.iput2_field_index
+      };
+      uint16_t iput_args[] = { data.iput0_arg, data.iput1_arg, data.iput2_arg };
+      static_assert(arraysize(iput_args) == arraysize(iput_field_indexes), "Size mismatch");
+      // Count valid field indexes.
+      size_t number_of_iputs = 0u;
+      while (number_of_iputs != arraysize(iput_field_indexes) &&
+          iput_field_indexes[number_of_iputs] != DexFile::kDexNoIndex16) {
+        // Check that there are no duplicate valid field indexes.
+        DCHECK_EQ(0, std::count(iput_field_indexes + number_of_iputs + 1,
+                                iput_field_indexes + arraysize(iput_field_indexes),
+                                iput_field_indexes[number_of_iputs]));
+        ++number_of_iputs;
+      }
+      // Check that there are no valid field indexes in the rest of the array.
+      DCHECK_EQ(0, std::count_if(iput_field_indexes + number_of_iputs,
+                                 iput_field_indexes + arraysize(iput_field_indexes),
+                                 [](uint16_t index) { return index != DexFile::kDexNoIndex16; }));
+
+      // Create HInstanceFieldSet for each IPUT that stores non-zero data.
+      Handle<mirror::DexCache> dex_cache;
+      HInstruction* obj = GetInvokeInputForArgVRegIndex(invoke_instruction, /* this */ 0u);
+      bool needs_constructor_barrier = false;
+      for (size_t i = 0; i != number_of_iputs; ++i) {
+        HInstruction* value = GetInvokeInputForArgVRegIndex(invoke_instruction, iput_args[i]);
+        if (!value->IsConstant() ||
+            (!value->AsConstant()->IsZero() && !value->IsNullConstant())) {
+          if (dex_cache.GetReference() == nullptr) {
+            dex_cache = handles_->NewHandle(resolved_method->GetDexCache());
+          }
+          uint16_t field_index = iput_field_indexes[i];
+          HInstanceFieldSet* iput = CreateInstanceFieldSet(dex_cache, field_index, obj, value);
+          invoke_instruction->GetBlock()->InsertInstructionBefore(iput, invoke_instruction);
+
+          // Check whether the field is final. If it is, we need to add a barrier.
+          size_t pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet());
+          ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size);
+          DCHECK(resolved_field != nullptr);
+          if (resolved_field->IsFinal()) {
+            needs_constructor_barrier = true;
+          }
+        }
+      }
+      if (needs_constructor_barrier) {
+        HMemoryBarrier* barrier = new (graph_->GetArena()) HMemoryBarrier(kStoreStore, kNoDexPc);
+        invoke_instruction->GetBlock()->InsertInstructionBefore(barrier, invoke_instruction);
+      }
+      *return_replacement = nullptr;
+      break;
+    }
     default:
       LOG(FATAL) << "UNREACHABLE";
       UNREACHABLE();
   }
-
-  if (return_replacement != nullptr) {
-    invoke_instruction->ReplaceWith(return_replacement);
-  }
-  invoke_instruction->GetBlock()->RemoveInstruction(invoke_instruction);
-
-  FixUpReturnReferenceType(resolved_method, invoke_instruction, return_replacement, do_rtp);
   return true;
 }
 
-HInstanceFieldGet* HInliner::CreateInstanceFieldGet(ArtMethod* resolved_method,
+HInstanceFieldGet* HInliner::CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache,
                                                     uint32_t field_index,
                                                     HInstruction* obj)
     SHARED_REQUIRES(Locks::mutator_lock_) {
-  Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
   size_t pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet());
   ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size);
   DCHECK(resolved_field != nullptr);
@@ -667,24 +734,23 @@
       resolved_field->IsVolatile(),
       field_index,
       resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
-      *resolved_method->GetDexFile(),
+      *dex_cache->GetDexFile(),
       dex_cache,
       // Read barrier generates a runtime call in slow path and we need a valid
       // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
       /* dex_pc */ 0);
   if (iget->GetType() == Primitive::kPrimNot) {
-    ReferenceTypePropagation rtp(graph_, handles_);
+    ReferenceTypePropagation rtp(graph_, handles_, /* is_first_run */ false);
     rtp.Visit(iget);
   }
   return iget;
 }
 
-HInstanceFieldSet* HInliner::CreateInstanceFieldSet(ArtMethod* resolved_method,
+HInstanceFieldSet* HInliner::CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache,
                                                     uint32_t field_index,
                                                     HInstruction* obj,
                                                     HInstruction* value)
     SHARED_REQUIRES(Locks::mutator_lock_) {
-  Handle<mirror::DexCache> dex_cache(handles_->NewHandle(resolved_method->GetDexCache()));
   size_t pointer_size = InstructionSetPointerSize(codegen_->GetInstructionSet());
   ArtField* resolved_field = dex_cache->GetResolvedField(field_index, pointer_size);
   DCHECK(resolved_field != nullptr);
@@ -696,17 +762,18 @@
       resolved_field->IsVolatile(),
       field_index,
       resolved_field->GetDeclaringClass()->GetDexClassDefIndex(),
-      *resolved_method->GetDexFile(),
+      *dex_cache->GetDexFile(),
       dex_cache,
       // Read barrier generates a runtime call in slow path and we need a valid
       // dex pc for the associated stack map. 0 is bogus but valid. Bug: 26854537.
       /* dex_pc */ 0);
   return iput;
 }
-bool HInliner::TryBuildAndInline(ArtMethod* resolved_method,
-                                 HInvoke* invoke_instruction,
-                                 bool same_dex_file,
-                                 bool do_rtp) {
+
+bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction,
+                                       ArtMethod* resolved_method,
+                                       bool same_dex_file,
+                                       HInstruction** return_replacement) {
   ScopedObjectAccess soa(Thread::Current());
   const DexFile::CodeItem* code_item = resolved_method->GetCodeItem();
   const DexFile& callee_dex_file = *resolved_method->GetDexFile();
@@ -758,6 +825,7 @@
       compiler_driver_->GetInstructionSet(),
       invoke_type,
       graph_->IsDebuggable(),
+      /* osr */ false,
       graph_->GetCurrentInstructionId());
   callee_graph->SetArtMethod(resolved_method);
 
@@ -771,7 +839,7 @@
                         resolved_method->GetQuickenedInfo(),
                         dex_cache);
 
-  if (!builder.BuildGraph(*code_item)) {
+  if (builder.BuildGraph(*code_item, handles_) != kAnalysisSuccess) {
     VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
                    << " could not be built, so cannot be inlined";
     return false;
@@ -784,12 +852,6 @@
     return false;
   }
 
-  if (callee_graph->TryBuildingSsa(handles_) != kAnalysisSuccess) {
-    VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
-                   << " could not be transformed to SSA";
-    return false;
-  }
-
   size_t parameter_index = 0;
   for (HInstructionIterator instructions(callee_graph->GetEntryBlock()->GetInstructions());
        !instructions.Done();
@@ -934,12 +996,18 @@
 
       if (current->IsNewInstance() &&
           (current->AsNewInstance()->GetEntrypoint() == kQuickAllocObjectWithAccessCheck)) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+                       << " could not be inlined because it is using an entrypoint"
+                       << " with access checks";
         // Allocation entrypoint does not handle inlined frames.
         return false;
       }
 
       if (current->IsNewArray() &&
           (current->AsNewArray()->GetEntrypoint() == kQuickAllocArrayWithAccessCheck)) {
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+                       << " could not be inlined because it is using an entrypoint"
+                       << " with access checks";
         // Allocation entrypoint does not handle inlined frames.
         return false;
       }
@@ -949,22 +1017,21 @@
           current->IsUnresolvedStaticFieldSet() ||
           current->IsUnresolvedInstanceFieldSet()) {
         // Entrypoint for unresolved fields does not handle inlined frames.
+        VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file)
+                       << " could not be inlined because it is using an unresolved"
+                       << " entrypoint";
         return false;
       }
     }
   }
   number_of_inlined_instructions_ += number_of_instructions;
 
-  HInstruction* return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);
-  if (return_replacement != nullptr) {
-    DCHECK_EQ(graph_, return_replacement->GetBlock()->GetGraph());
-  }
-  FixUpReturnReferenceType(resolved_method, invoke_instruction, return_replacement, do_rtp);
+  *return_replacement = callee_graph->InlineInto(graph_, invoke_instruction);
   return true;
 }
 
-void HInliner::FixUpReturnReferenceType(ArtMethod* resolved_method,
-                                        HInvoke* invoke_instruction,
+void HInliner::FixUpReturnReferenceType(HInvoke* invoke_instruction,
+                                        ArtMethod* resolved_method,
                                         HInstruction* return_replacement,
                                         bool do_rtp) {
   // Check the integrity of reference types and run another type propagation if needed.
@@ -990,13 +1057,13 @@
         if (invoke_rti.IsStrictSupertypeOf(return_rti)
             || (return_rti.IsExact() && !invoke_rti.IsExact())
             || !return_replacement->CanBeNull()) {
-          ReferenceTypePropagation(graph_, handles_).Run();
+          ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
         }
       }
     } else if (return_replacement->IsInstanceOf()) {
       if (do_rtp) {
         // Inlining InstanceOf into an If may put a tighter bound on reference types.
-        ReferenceTypePropagation(graph_, handles_).Run();
+        ReferenceTypePropagation(graph_, handles_, /* is_first_run */ false).Run();
       }
     }
   }
diff --git a/compiler/optimizing/inliner.h b/compiler/optimizing/inliner.h
index 0127d55..9dd9bf5 100644
--- a/compiler/optimizing/inliner.h
+++ b/compiler/optimizing/inliner.h
@@ -61,20 +61,33 @@
   bool TryInline(HInvoke* invoke_instruction);
 
   // Try to inline `resolved_method` in place of `invoke_instruction`. `do_rtp` is whether
-  // reference type propagation can run after the inlining.
-  bool TryInline(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp = true)
+  // reference type propagation can run after the inlining. If the inlining is successful, this
+  // method will replace and remove the `invoke_instruction`.
+  bool TryInlineAndReplace(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp)
     SHARED_REQUIRES(Locks::mutator_lock_);
 
+  bool TryBuildAndInline(HInvoke* invoke_instruction,
+                         ArtMethod* resolved_method,
+                         HInstruction** return_replacement)
+    SHARED_REQUIRES(Locks::mutator_lock_);
+
+  bool TryBuildAndInlineHelper(HInvoke* invoke_instruction,
+                               ArtMethod* resolved_method,
+                               bool same_dex_file,
+                               HInstruction** return_replacement);
+
   // Try to recognize known simple patterns and replace invoke call with appropriate instructions.
-  bool TryPatternSubstitution(HInvoke* invoke_instruction, ArtMethod* resolved_method, bool do_rtp)
+  bool TryPatternSubstitution(HInvoke* invoke_instruction,
+                              ArtMethod* resolved_method,
+                              HInstruction** return_replacement)
     SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Create a new HInstanceFieldGet.
-  HInstanceFieldGet* CreateInstanceFieldGet(ArtMethod* resolved_method,
+  HInstanceFieldGet* CreateInstanceFieldGet(Handle<mirror::DexCache> dex_cache,
                                             uint32_t field_index,
                                             HInstruction* obj);
   // Create a new HInstanceFieldSet.
-  HInstanceFieldSet* CreateInstanceFieldSet(ArtMethod* resolved_method,
+  HInstanceFieldSet* CreateInstanceFieldSet(Handle<mirror::DexCache> dex_cache,
                                             uint32_t field_index,
                                             HInstruction* obj,
                                             HInstruction* value);
@@ -94,18 +107,13 @@
                                 const InlineCache& ic)
     SHARED_REQUIRES(Locks::mutator_lock_);
 
-  bool TryBuildAndInline(ArtMethod* resolved_method,
-                         HInvoke* invoke_instruction,
-                         bool same_dex_file,
-                         bool do_rtp = true);
-
   HInstanceFieldGet* BuildGetReceiverClass(ClassLinker* class_linker,
                                            HInstruction* receiver,
                                            uint32_t dex_pc) const
     SHARED_REQUIRES(Locks::mutator_lock_);
 
-  void FixUpReturnReferenceType(ArtMethod* resolved_method,
-                                HInvoke* invoke_instruction,
+  void FixUpReturnReferenceType(HInvoke* invoke_instruction,
+                                ArtMethod* resolved_method,
                                 HInstruction* return_replacement,
                                 bool do_rtp)
     SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index c1e3863..a48d06f 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -91,6 +91,7 @@
   void SimplifyRotate(HInvoke* invoke, bool is_left);
   void SimplifySystemArrayCopy(HInvoke* invoke);
   void SimplifyStringEquals(HInvoke* invoke);
+  void SimplifyCompare(HInvoke* invoke, bool has_zero_op);
 
   OptimizingCompilerStats* stats_;
   bool simplification_occurred_ = false;
@@ -176,8 +177,8 @@
 
   // We can apply De Morgan's laws if both inputs are Not's and are only used
   // by `op`.
-  if (left->IsNot() &&
-      right->IsNot() &&
+  if (((left->IsNot() && right->IsNot()) ||
+       (left->IsBooleanNot() && right->IsBooleanNot())) &&
       left->HasOnlyOneNonEnvironmentUse() &&
       right->HasOnlyOneNonEnvironmentUse()) {
     // Replace code looking like
@@ -187,8 +188,8 @@
     // with
     //    OR or, a, b         (respectively AND)
     //    NOT dest, or
-    HInstruction* src_left = left->AsNot()->GetInput();
-    HInstruction* src_right = right->AsNot()->GetInput();
+    HInstruction* src_left = left->InputAt(0);
+    HInstruction* src_right = right->InputAt(0);
     uint32_t dex_pc = op->GetDexPc();
 
     // Remove the negations on the inputs.
@@ -204,7 +205,12 @@
     } else {
       hbin = new (GetGraph()->GetArena()) HAnd(type, src_left, src_right, dex_pc);
     }
-    HNot* hnot = new (GetGraph()->GetArena()) HNot(type, hbin, dex_pc);
+    HInstruction* hnot;
+    if (left->IsBooleanNot()) {
+      hnot = new (GetGraph()->GetArena()) HBooleanNot(hbin, dex_pc);
+    } else {
+      hnot = new (GetGraph()->GetArena()) HNot(type, hbin, dex_pc);
+    }
 
     op->GetBlock()->InsertInstructionBefore(hbin, op);
     op->GetBlock()->ReplaceAndRemoveInstructionWith(op, hnot);
@@ -751,11 +757,97 @@
   }
 }
 
+static bool IsTypeConversionImplicit(Primitive::Type input_type, Primitive::Type result_type) {
+  // Besides conversion to the same type, widening integral conversions are implicit,
+  // excluding conversions to long and the byte->char conversion where we need to
+  // clear the high 16 bits of the 32-bit sign-extended representation of byte.
+  return result_type == input_type ||
+      (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimByte) ||
+      (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimShort) ||
+      (result_type == Primitive::kPrimInt && input_type == Primitive::kPrimChar) ||
+      (result_type == Primitive::kPrimShort && input_type == Primitive::kPrimByte);
+}
+
+static bool IsTypeConversionLossless(Primitive::Type input_type, Primitive::Type result_type) {
+  // The conversion to a larger type is loss-less with the exception of two cases,
+  //   - conversion to char, the only unsigned type, where we may lose some bits, and
+  //   - conversion from float to long, the only FP to integral conversion with smaller FP type.
+  // For integral to FP conversions this holds because the FP mantissa is large enough.
+  DCHECK_NE(input_type, result_type);
+  return Primitive::ComponentSize(result_type) > Primitive::ComponentSize(input_type) &&
+      result_type != Primitive::kPrimChar &&
+      !(result_type == Primitive::kPrimLong && input_type == Primitive::kPrimFloat);
+}
+
 void InstructionSimplifierVisitor::VisitTypeConversion(HTypeConversion* instruction) {
-  if (instruction->GetResultType() == instruction->GetInputType()) {
-    // Remove the instruction if it's converting to the same type.
-    instruction->ReplaceWith(instruction->GetInput());
+  HInstruction* input = instruction->GetInput();
+  Primitive::Type input_type = input->GetType();
+  Primitive::Type result_type = instruction->GetResultType();
+  if (IsTypeConversionImplicit(input_type, result_type)) {
+    // Remove the implicit conversion; this includes conversion to the same type.
+    instruction->ReplaceWith(input);
     instruction->GetBlock()->RemoveInstruction(instruction);
+    RecordSimplification();
+    return;
+  }
+
+  if (input->IsTypeConversion()) {
+    HTypeConversion* input_conversion = input->AsTypeConversion();
+    HInstruction* original_input = input_conversion->GetInput();
+    Primitive::Type original_type = original_input->GetType();
+
+    // When the first conversion is lossless, a direct conversion from the original type
+    // to the final type yields the same result, even for a lossy second conversion, for
+    // example float->double->int or int->double->float.
+    bool is_first_conversion_lossless = IsTypeConversionLossless(original_type, input_type);
+
+    // For integral conversions, see if the first conversion loses only bits that the second
+    // doesn't need, i.e. the final type is no wider than the intermediate. If so, direct
+    // conversion yields the same result, for example long->int->short or int->char->short.
+    bool integral_conversions_with_non_widening_second =
+        Primitive::IsIntegralType(input_type) &&
+        Primitive::IsIntegralType(original_type) &&
+        Primitive::IsIntegralType(result_type) &&
+        Primitive::ComponentSize(result_type) <= Primitive::ComponentSize(input_type);
+
+    if (is_first_conversion_lossless || integral_conversions_with_non_widening_second) {
+      // If the merged conversion is implicit, do the simplification unconditionally.
+      if (IsTypeConversionImplicit(original_type, result_type)) {
+        instruction->ReplaceWith(original_input);
+        instruction->GetBlock()->RemoveInstruction(instruction);
+        if (!input_conversion->HasUses()) {
+          // Don't wait for DCE.
+          input_conversion->GetBlock()->RemoveInstruction(input_conversion);
+        }
+        RecordSimplification();
+        return;
+      }
+      // Otherwise simplify only if the first conversion has no other use.
+      if (input_conversion->HasOnlyOneNonEnvironmentUse()) {
+        input_conversion->ReplaceWith(original_input);
+        input_conversion->GetBlock()->RemoveInstruction(input_conversion);
+        RecordSimplification();
+        return;
+      }
+    }
+  } else if (input->IsAnd() &&
+      Primitive::IsIntegralType(result_type) &&
+      input->HasOnlyOneNonEnvironmentUse()) {
+    DCHECK(Primitive::IsIntegralType(input_type));
+    HAnd* input_and = input->AsAnd();
+    HConstant* constant = input_and->GetConstantRight();
+    if (constant != nullptr) {
+      int64_t value = Int64FromConstant(constant);
+      DCHECK_NE(value, -1);  // "& -1" would have been optimized away in VisitAnd().
+      size_t trailing_ones = CTZ(~static_cast<uint64_t>(value));
+      if (trailing_ones >= kBitsPerByte * Primitive::ComponentSize(result_type)) {
+        // The `HAnd` is useless, for example in `(byte) (x & 0xff)`, get rid of it.
+        input_and->ReplaceWith(input_and->GetLeastConstantLeft());
+        input_and->GetBlock()->RemoveInstruction(input_and);
+        RecordSimplification();
+        return;
+      }
+    }
   }
 }
 
@@ -1308,8 +1400,8 @@
 
   HInstruction* left = instruction->GetLeft();
   HInstruction* right = instruction->GetRight();
-  if (left->IsNot() &&
-      right->IsNot() &&
+  if (((left->IsNot() && right->IsNot()) ||
+       (left->IsBooleanNot() && right->IsBooleanNot())) &&
       left->HasOnlyOneNonEnvironmentUse() &&
       right->HasOnlyOneNonEnvironmentUse()) {
     // Replace code looking like
@@ -1318,8 +1410,8 @@
     //    XOR dst, nota, notb
     // with
     //    XOR dst, a, b
-    instruction->ReplaceInput(left->AsNot()->GetInput(), 0);
-    instruction->ReplaceInput(right->AsNot()->GetInput(), 1);
+    instruction->ReplaceInput(left->InputAt(0), 0);
+    instruction->ReplaceInput(right->InputAt(0), 1);
     left->GetBlock()->RemoveInstruction(left);
     right->GetBlock()->RemoveInstruction(right);
     RecordSimplification();
@@ -1441,6 +1533,24 @@
   }
 }
 
+void InstructionSimplifierVisitor::SimplifyCompare(HInvoke* invoke, bool is_signum) {
+  DCHECK(invoke->IsInvokeStaticOrDirect());
+  uint32_t dex_pc = invoke->GetDexPc();
+  HInstruction* left = invoke->InputAt(0);
+  HInstruction* right;
+  Primitive::Type type = left->GetType();
+  if (!is_signum) {
+    right = invoke->InputAt(1);
+  } else if (type == Primitive::kPrimLong) {
+    right = GetGraph()->GetLongConstant(0);
+  } else {
+    right = GetGraph()->GetIntConstant(0);
+  }
+  HCompare* compare = new (GetGraph()->GetArena())
+      HCompare(type, left, right, ComparisonBias::kNoBias, dex_pc);
+  invoke->GetBlock()->ReplaceAndRemoveInstructionWith(invoke, compare);
+}
+
 void InstructionSimplifierVisitor::VisitInvoke(HInvoke* instruction) {
   if (instruction->GetIntrinsic() == Intrinsics::kStringEquals) {
     SimplifyStringEquals(instruction);
@@ -1452,6 +1562,12 @@
   } else if (instruction->GetIntrinsic() == Intrinsics::kIntegerRotateLeft ||
              instruction->GetIntrinsic() == Intrinsics::kLongRotateLeft) {
     SimplifyRotate(instruction, true);
+  } else if (instruction->GetIntrinsic() == Intrinsics::kIntegerCompare ||
+             instruction->GetIntrinsic() == Intrinsics::kLongCompare) {
+    SimplifyCompare(instruction, /* is_signum */ false);
+  } else if (instruction->GetIntrinsic() == Intrinsics::kIntegerSignum ||
+             instruction->GetIntrinsic() == Intrinsics::kLongSignum) {
+    SimplifyCompare(instruction, /* is_signum */ true);
   }
 }
 
diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc
index a6be324..db39bc8 100644
--- a/compiler/optimizing/intrinsics.cc
+++ b/compiler/optimizing/intrinsics.cc
@@ -481,6 +481,7 @@
     case kInlineOpNonWideConst:
     case kInlineOpIGet:
     case kInlineOpIPut:
+    case kInlineOpConstructor:
       return Intrinsics::kNone;
 
     // String init cases, not intrinsics.
diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc
index e8912b3..00a158b 100644
--- a/compiler/optimizing/intrinsics_arm.cc
+++ b/compiler/optimizing/intrinsics_arm.cc
@@ -1580,6 +1580,251 @@
   __ Bind(slow_path->GetExitLabel());
 }
 
+static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  // If the graph is debuggable, all callee-saved floating-point registers are blocked by
+  // the code generator. Furthermore, the register allocator creates fixed live intervals
+  // for all caller-saved registers because we are doing a function call. As a result, if
+  // the input and output locations are unallocated, the register allocator runs out of
+  // registers and fails; however, a debuggable graph is not the common case.
+  if (invoke->GetBlock()->GetGraph()->IsDebuggable()) {
+    return;
+  }
+
+  DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
+  DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
+  DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
+
+  LocationSummary* const locations = new (arena) LocationSummary(invoke,
+                                                                 LocationSummary::kCall,
+                                                                 kIntrinsified);
+  const InvokeRuntimeCallingConvention calling_convention;
+
+  locations->SetInAt(0, Location::RequiresFpuRegister());
+  locations->SetOut(Location::RequiresFpuRegister());
+  // Native code uses the soft float ABI.
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+}
+
+static void CreateFPFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
+  // If the graph is debuggable, all callee-saved floating-point registers are blocked by
+  // the code generator. Furthermore, the register allocator creates fixed live intervals
+  // for all caller-saved registers because we are doing a function call. As a result, if
+  // the input and output locations are unallocated, the register allocator runs out of
+  // registers and fails; however, a debuggable graph is not the common case.
+  if (invoke->GetBlock()->GetGraph()->IsDebuggable()) {
+    return;
+  }
+
+  DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
+  DCHECK_EQ(invoke->InputAt(0)->GetType(), Primitive::kPrimDouble);
+  DCHECK_EQ(invoke->InputAt(1)->GetType(), Primitive::kPrimDouble);
+  DCHECK_EQ(invoke->GetType(), Primitive::kPrimDouble);
+
+  LocationSummary* const locations = new (arena) LocationSummary(invoke,
+                                                                 LocationSummary::kCall,
+                                                                 kIntrinsified);
+  const InvokeRuntimeCallingConvention calling_convention;
+
+  locations->SetInAt(0, Location::RequiresFpuRegister());
+  locations->SetInAt(1, Location::RequiresFpuRegister());
+  locations->SetOut(Location::RequiresFpuRegister());
+  // Native code uses the soft float ABI.
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
+  locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(3)));
+}
+
+static void GenFPToFPCall(HInvoke* invoke,
+                          ArmAssembler* assembler,
+                          CodeGeneratorARM* codegen,
+                          QuickEntrypointEnum entry) {
+  LocationSummary* const locations = invoke->GetLocations();
+  const InvokeRuntimeCallingConvention calling_convention;
+
+  DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
+  DCHECK(locations->WillCall() && locations->Intrinsified());
+  DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0)));
+  DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1)));
+
+  __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value());
+  // Native code uses the soft float ABI.
+  __ vmovrrd(calling_convention.GetRegisterAt(0),
+             calling_convention.GetRegisterAt(1),
+             FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
+  __ blx(LR);
+  codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+  __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
+             calling_convention.GetRegisterAt(0),
+             calling_convention.GetRegisterAt(1));
+}
+
+static void GenFPFPToFPCall(HInvoke* invoke,
+                          ArmAssembler* assembler,
+                          CodeGeneratorARM* codegen,
+                          QuickEntrypointEnum entry) {
+  LocationSummary* const locations = invoke->GetLocations();
+  const InvokeRuntimeCallingConvention calling_convention;
+
+  DCHECK_EQ(invoke->GetNumberOfArguments(), 2U);
+  DCHECK(locations->WillCall() && locations->Intrinsified());
+  DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(0)));
+  DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(1)));
+  DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(2)));
+  DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(calling_convention.GetRegisterAt(3)));
+
+  __ LoadFromOffset(kLoadWord, LR, TR, GetThreadOffset<kArmWordSize>(entry).Int32Value());
+  // Native code uses the soft float ABI.
+  __ vmovrrd(calling_convention.GetRegisterAt(0),
+             calling_convention.GetRegisterAt(1),
+             FromLowSToD(locations->InAt(0).AsFpuRegisterPairLow<SRegister>()));
+  __ vmovrrd(calling_convention.GetRegisterAt(2),
+             calling_convention.GetRegisterAt(3),
+             FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>()));
+  __ blx(LR);
+  codegen->RecordPcInfo(invoke, invoke->GetDexPc());
+  __ vmovdrr(FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()),
+             calling_convention.GetRegisterAt(0),
+             calling_convention.GetRegisterAt(1));
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathCos(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathCos(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCos);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathSin(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathSin(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSin);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAcos(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAcos(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAcos);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAsin(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAsin(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAsin);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAtan(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAtan(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathCbrt(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathCbrt(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCbrt);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathCosh(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathCosh(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickCosh);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathExp(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathExp(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExp);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathExpm1(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathExpm1(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickExpm1);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathLog(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathLog(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathLog10(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathLog10(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickLog10);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathSinh(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathSinh(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickSinh);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathTan(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathTan(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTan);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathTanh(HInvoke* invoke) {
+  CreateFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathTanh(HInvoke* invoke) {
+  GenFPToFPCall(invoke, GetAssembler(), codegen_, kQuickTanh);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathAtan2(HInvoke* invoke) {
+  CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathAtan2(HInvoke* invoke) {
+  GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickAtan2);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathHypot(HInvoke* invoke) {
+  CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathHypot(HInvoke* invoke) {
+  GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickHypot);
+}
+
+void IntrinsicLocationsBuilderARM::VisitMathNextAfter(HInvoke* invoke) {
+  CreateFPFPToFPCallLocations(arena_, invoke);
+}
+
+void IntrinsicCodeGeneratorARM::VisitMathNextAfter(HInvoke* invoke) {
+  GenFPFPToFPCall(invoke, GetAssembler(), codegen_, kQuickNextAfter);
+}
+
 // Unimplemented intrinsics.
 
 #define UNIMPLEMENTED_INTRINSIC(Name)                                                  \
@@ -1610,44 +1855,27 @@
 UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar)
 UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(StringGetCharsNoCheck)
-UNIMPLEMENTED_INTRINSIC(MathCos)
-UNIMPLEMENTED_INTRINSIC(MathSin)
-UNIMPLEMENTED_INTRINSIC(MathAcos)
-UNIMPLEMENTED_INTRINSIC(MathAsin)
-UNIMPLEMENTED_INTRINSIC(MathAtan)
-UNIMPLEMENTED_INTRINSIC(MathAtan2)
-UNIMPLEMENTED_INTRINSIC(MathCbrt)
-UNIMPLEMENTED_INTRINSIC(MathCosh)
-UNIMPLEMENTED_INTRINSIC(MathExp)
-UNIMPLEMENTED_INTRINSIC(MathExpm1)
-UNIMPLEMENTED_INTRINSIC(MathHypot)
-UNIMPLEMENTED_INTRINSIC(MathLog)
-UNIMPLEMENTED_INTRINSIC(MathLog10)
-UNIMPLEMENTED_INTRINSIC(MathNextAfter)
-UNIMPLEMENTED_INTRINSIC(MathSinh)
-UNIMPLEMENTED_INTRINSIC(MathTan)
-UNIMPLEMENTED_INTRINSIC(MathTanh)
 
 UNIMPLEMENTED_INTRINSIC(FloatIsInfinite)
 UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite)
 UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
 UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
 
-UNIMPLEMENTED_INTRINSIC(IntegerCompare)
-UNIMPLEMENTED_INTRINSIC(LongCompare)
 UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+
+// Handled as HIR instructions.
+UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
+UNIMPLEMENTED_INTRINSIC(LongRotateRight)
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
 UNIMPLEMENTED_INTRINSIC(IntegerSignum)
 UNIMPLEMENTED_INTRINSIC(LongSignum)
 
-// Rotate operations are handled as HRor instructions.
-UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
-UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
-UNIMPLEMENTED_INTRINSIC(LongRotateRight)
-
 #undef UNIMPLEMENTED_INTRINSIC
 
 #undef __
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 5dce83a..4140d94 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -284,36 +284,6 @@
   locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
 }
 
-static void GenCompare(LocationSummary* locations, bool is_long, vixl::MacroAssembler* masm) {
-  Location op1 = locations->InAt(0);
-  Location op2 = locations->InAt(1);
-  Location out = locations->Out();
-
-  Register op1_reg = is_long ? XRegisterFrom(op1) : WRegisterFrom(op1);
-  Register op2_reg = is_long ? XRegisterFrom(op2) : WRegisterFrom(op2);
-  Register out_reg = WRegisterFrom(out);
-
-  __ Cmp(op1_reg, op2_reg);
-  __ Cset(out_reg, gt);           // out == +1 if GT or 0 otherwise
-  __ Cinv(out_reg, out_reg, lt);  // out == -1 if LT or unchanged otherwise
-}
-
-void IntrinsicLocationsBuilderARM64::VisitIntegerCompare(HInvoke* invoke) {
-  CreateIntIntToIntLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitIntegerCompare(HInvoke* invoke) {
-  GenCompare(invoke->GetLocations(), /* is_long */ false, GetVIXLAssembler());
-}
-
-void IntrinsicLocationsBuilderARM64::VisitLongCompare(HInvoke* invoke) {
-  CreateIntIntToIntLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitLongCompare(HInvoke* invoke) {
-  GenCompare(invoke->GetLocations(), /* is_long */ true,  GetVIXLAssembler());
-}
-
 static void GenNumberOfLeadingZeros(LocationSummary* locations,
                                     Primitive::Type type,
                                     vixl::MacroAssembler* masm) {
@@ -1456,34 +1426,6 @@
   __ Bind(slow_path->GetExitLabel());
 }
 
-static void GenSignum(LocationSummary* locations, bool is_long, vixl::MacroAssembler* masm) {
-  Location op1 = locations->InAt(0);
-  Location out = locations->Out();
-
-  Register op1_reg = is_long ? XRegisterFrom(op1) : WRegisterFrom(op1);
-  Register out_reg = WRegisterFrom(out);
-
-  __ Cmp(op1_reg, 0);
-  __ Cset(out_reg, gt);           // out == +1 if GT or 0 otherwise
-  __ Cinv(out_reg, out_reg, lt);  // out == -1 if LT or unchanged otherwise
-}
-
-void IntrinsicLocationsBuilderARM64::VisitIntegerSignum(HInvoke* invoke) {
-  CreateIntToIntLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitIntegerSignum(HInvoke* invoke) {
-  GenSignum(invoke->GetLocations(), /* is_long */ false, GetVIXLAssembler());
-}
-
-void IntrinsicLocationsBuilderARM64::VisitLongSignum(HInvoke* invoke) {
-  CreateIntToIntLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorARM64::VisitLongSignum(HInvoke* invoke) {
-  GenSignum(invoke->GetLocations(), /* is_long */ true,  GetVIXLAssembler());
-}
-
 static void CreateFPToFPCallLocations(ArenaAllocator* arena, HInvoke* invoke) {
   DCHECK_EQ(invoke->GetNumberOfArguments(), 1U);
   DCHECK(Primitive::IsFloatingPointType(invoke->InputAt(0)->GetType()));
@@ -1684,11 +1626,15 @@
 UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
 
-// Rotate operations are handled as HRor instructions.
+// Handled as HIR instructions.
 UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateRight)
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
 
 #undef UNIMPLEMENTED_INTRINSIC
 
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 0d9cf09..2294713 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -1019,12 +1019,14 @@
 UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
 UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
 
-UNIMPLEMENTED_INTRINSIC(IntegerCompare)
-UNIMPLEMENTED_INTRINSIC(LongCompare)
 UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+
+// Handled as HIR instructions.
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
 UNIMPLEMENTED_INTRINSIC(IntegerSignum)
 UNIMPLEMENTED_INTRINSIC(LongSignum)
 
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index f681d1f..ac28503 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -1767,12 +1767,14 @@
 UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
 UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
 
-UNIMPLEMENTED_INTRINSIC(IntegerCompare)
-UNIMPLEMENTED_INTRINSIC(LongCompare)
 UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
+
+// Handled as HIR instructions.
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
 UNIMPLEMENTED_INTRINSIC(IntegerSignum)
 UNIMPLEMENTED_INTRINSIC(LongSignum)
 
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index acc40bc..22cefe8 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -37,10 +37,12 @@
 
 static constexpr int kDoubleNaNHigh = 0x7FF80000;
 static constexpr int kDoubleNaNLow = 0x00000000;
-static constexpr int kFloatNaN = 0x7FC00000;
+static constexpr int64_t kDoubleNaN = INT64_C(0x7FF8000000000000);
+static constexpr int32_t kFloatNaN = INT32_C(0x7FC00000);
 
 IntrinsicLocationsBuilderX86::IntrinsicLocationsBuilderX86(CodeGeneratorX86* codegen)
-  : arena_(codegen->GetGraph()->GetArena()), codegen_(codegen) {
+  : arena_(codegen->GetGraph()->GetArena()),
+    codegen_(codegen) {
 }
 
 
@@ -256,15 +258,38 @@
                                                            LocationSummary::kNoCall,
                                                            kIntrinsified);
   locations->SetInAt(0, Location::RequiresFpuRegister());
-  // TODO: Allow x86 to work with memory. This requires assembler support, see below.
-  // locations->SetInAt(0, Location::Any());               // X86 can work on memory directly.
   locations->SetOut(Location::SameAsFirstInput());
+  HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
+  DCHECK(static_or_direct != nullptr);
+  if (static_or_direct->HasSpecialInput() &&
+      invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) {
+    // We need addressibility for the constant area.
+    locations->SetInAt(1, Location::RequiresRegister());
+    // We need a temporary to hold the constant.
+    locations->AddTemp(Location::RequiresFpuRegister());
+  }
 }
 
-static void MathAbsFP(LocationSummary* locations, bool is64bit, X86Assembler* assembler) {
+static void MathAbsFP(LocationSummary* locations,
+                      bool is64bit,
+                      X86Assembler* assembler,
+                      CodeGeneratorX86* codegen) {
   Location output = locations->Out();
 
-  if (output.IsFpuRegister()) {
+  DCHECK(output.IsFpuRegister());
+  if (locations->GetInputCount() == 2 && locations->InAt(1).IsValid()) {
+    DCHECK(locations->InAt(1).IsRegister());
+    // We also have a constant area pointer.
+    Register constant_area = locations->InAt(1).AsRegister<Register>();
+    XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+    if (is64bit) {
+      __ movsd(temp, codegen->LiteralInt64Address(INT64_C(0x7FFFFFFFFFFFFFFF), constant_area));
+      __ andpd(output.AsFpuRegister<XmmRegister>(), temp);
+    } else {
+      __ movss(temp, codegen->LiteralInt32Address(INT32_C(0x7FFFFFFF), constant_area));
+      __ andps(output.AsFpuRegister<XmmRegister>(), temp);
+    }
+  } else {
     // Create the right constant on an aligned stack.
     if (is64bit) {
       __ subl(ESP, Immediate(8));
@@ -277,19 +302,6 @@
       __ andps(output.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
     }
     __ addl(ESP, Immediate(16));
-  } else {
-    // TODO: update when assember support is available.
-    UNIMPLEMENTED(FATAL) << "Needs assembler support.";
-//  Once assembler support is available, in-memory operations look like this:
-//    if (is64bit) {
-//      DCHECK(output.IsDoubleStackSlot());
-//      __ andl(Address(Register(RSP), output.GetHighStackIndex(kX86WordSize)),
-//              Immediate(0x7FFFFFFF));
-//    } else {
-//      DCHECK(output.IsStackSlot());
-//      // Can use and with a literal directly.
-//      __ andl(Address(Register(RSP), output.GetStackIndex()), Immediate(0x7FFFFFFF));
-//    }
   }
 }
 
@@ -298,7 +310,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMathAbsDouble(HInvoke* invoke) {
-  MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler());
+  MathAbsFP(invoke->GetLocations(), /* is64bit */ true, GetAssembler(), codegen_);
 }
 
 void IntrinsicLocationsBuilderX86::VisitMathAbsFloat(HInvoke* invoke) {
@@ -306,7 +318,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMathAbsFloat(HInvoke* invoke) {
-  MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler());
+  MathAbsFP(invoke->GetLocations(), /* is64bit */ false, GetAssembler(), codegen_);
 }
 
 static void CreateAbsIntLocation(ArenaAllocator* arena, HInvoke* invoke) {
@@ -388,8 +400,11 @@
   GenAbsLong(invoke->GetLocations(), GetAssembler());
 }
 
-static void GenMinMaxFP(LocationSummary* locations, bool is_min, bool is_double,
-                        X86Assembler* assembler) {
+static void GenMinMaxFP(LocationSummary* locations,
+                        bool is_min,
+                        bool is_double,
+                        X86Assembler* assembler,
+                        CodeGeneratorX86* codegen) {
   Location op1_loc = locations->InAt(0);
   Location op2_loc = locations->InAt(1);
   Location out_loc = locations->Out();
@@ -450,15 +465,26 @@
 
   // NaN handling.
   __ Bind(&nan);
-  if (is_double) {
-    __ pushl(Immediate(kDoubleNaNHigh));
-    __ pushl(Immediate(kDoubleNaNLow));
-    __ movsd(out, Address(ESP, 0));
-    __ addl(ESP, Immediate(8));
+  // Do we have a constant area pointer?
+  if (locations->GetInputCount() == 3 && locations->InAt(2).IsValid()) {
+    DCHECK(locations->InAt(2).IsRegister());
+    Register constant_area = locations->InAt(2).AsRegister<Register>();
+    if (is_double) {
+      __ movsd(out, codegen->LiteralInt64Address(kDoubleNaN, constant_area));
+    } else {
+      __ movss(out, codegen->LiteralInt32Address(kFloatNaN, constant_area));
+    }
   } else {
-    __ pushl(Immediate(kFloatNaN));
-    __ movss(out, Address(ESP, 0));
-    __ addl(ESP, Immediate(4));
+    if (is_double) {
+      __ pushl(Immediate(kDoubleNaNHigh));
+      __ pushl(Immediate(kDoubleNaNLow));
+      __ movsd(out, Address(ESP, 0));
+      __ addl(ESP, Immediate(8));
+    } else {
+      __ pushl(Immediate(kFloatNaN));
+      __ movss(out, Address(ESP, 0));
+      __ addl(ESP, Immediate(4));
+    }
   }
   __ jmp(&done);
 
@@ -483,6 +509,12 @@
   // The following is sub-optimal, but all we can do for now. It would be fine to also accept
   // the second input to be the output (we can simply swap inputs).
   locations->SetOut(Location::SameAsFirstInput());
+  HInvokeStaticOrDirect* static_or_direct = invoke->AsInvokeStaticOrDirect();
+  DCHECK(static_or_direct != nullptr);
+  if (static_or_direct->HasSpecialInput() &&
+      invoke->InputAt(static_or_direct->GetSpecialInputIndex())->IsX86ComputeBaseMethodAddress()) {
+    locations->SetInAt(2, Location::RequiresRegister());
+  }
 }
 
 void IntrinsicLocationsBuilderX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
@@ -490,7 +522,11 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMathMinDoubleDouble(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ true, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(),
+              /* is_min */ true,
+              /* is_double */ true,
+              GetAssembler(),
+              codegen_);
 }
 
 void IntrinsicLocationsBuilderX86::VisitMathMinFloatFloat(HInvoke* invoke) {
@@ -498,7 +534,11 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMathMinFloatFloat(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ true, /* is_double */ false, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(),
+              /* is_min */ true,
+              /* is_double */ false,
+              GetAssembler(),
+              codegen_);
 }
 
 void IntrinsicLocationsBuilderX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
@@ -506,7 +546,11 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMathMaxDoubleDouble(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ true, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(),
+              /* is_min */ false,
+              /* is_double */ true,
+              GetAssembler(),
+              codegen_);
 }
 
 void IntrinsicLocationsBuilderX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
@@ -514,7 +558,11 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitMathMaxFloatFloat(HInvoke* invoke) {
-  GenMinMaxFP(invoke->GetLocations(), /* is_min */ false, /* is_double */ false, GetAssembler());
+  GenMinMaxFP(invoke->GetLocations(),
+              /* is_min */ false,
+              /* is_double */ false,
+              GetAssembler(),
+              codegen_);
 }
 
 static void GenMinMax(LocationSummary* locations, bool is_min, bool is_long,
@@ -2245,7 +2293,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitIntegerReverse(HInvoke* invoke) {
-  X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
+  X86Assembler* assembler = GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
 
   Register reg = locations->InAt(0).AsRegister<Register>();
@@ -2276,7 +2324,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitLongReverse(HInvoke* invoke) {
-  X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
+  X86Assembler* assembler = GetAssembler();
   LocationSummary* locations = invoke->GetLocations();
 
   Register reg_low = locations->InAt(0).AsRegisterPairLow<Register>();
@@ -2320,7 +2368,9 @@
   locations->SetOut(Location::RequiresRegister());
 }
 
-static void GenBitCount(X86Assembler* assembler, HInvoke* invoke, bool is_long) {
+static void GenBitCount(X86Assembler* assembler,
+                        CodeGeneratorX86* codegen,
+                        HInvoke* invoke, bool is_long) {
   LocationSummary* locations = invoke->GetLocations();
   Location src = locations->InAt(0);
   Register out = locations->Out().AsRegister<Register>();
@@ -2331,11 +2381,7 @@
     value = is_long
         ? POPCOUNT(static_cast<uint64_t>(value))
         : POPCOUNT(static_cast<uint32_t>(value));
-    if (value == 0) {
-      __ xorl(out, out);
-    } else {
-      __ movl(out, Immediate(value));
-    }
+    codegen->Load32BitValue(out, value);
     return;
   }
 
@@ -2367,7 +2413,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitIntegerBitCount(HInvoke* invoke) {
-  GenBitCount(GetAssembler(), invoke, /* is_long */ false);
+  GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ false);
 }
 
 void IntrinsicLocationsBuilderX86::VisitLongBitCount(HInvoke* invoke) {
@@ -2375,7 +2421,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitLongBitCount(HInvoke* invoke) {
-  GenBitCount(GetAssembler(), invoke, /* is_long */ true);
+  GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ true);
 }
 
 static void CreateLeadingZeroLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_long) {
@@ -2390,7 +2436,9 @@
   locations->SetOut(Location::RequiresRegister());
 }
 
-static void GenLeadingZeros(X86Assembler* assembler, HInvoke* invoke, bool is_long) {
+static void GenLeadingZeros(X86Assembler* assembler,
+                            CodeGeneratorX86* codegen,
+                            HInvoke* invoke, bool is_long) {
   LocationSummary* locations = invoke->GetLocations();
   Location src = locations->InAt(0);
   Register out = locations->Out().AsRegister<Register>();
@@ -2403,11 +2451,7 @@
     } else {
       value = is_long ? CLZ(static_cast<uint64_t>(value)) : CLZ(static_cast<uint32_t>(value));
     }
-    if (value == 0) {
-      __ xorl(out, out);
-    } else {
-      __ movl(out, Immediate(value));
-    }
+    codegen->Load32BitValue(out, value);
     return;
   }
 
@@ -2474,8 +2518,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitIntegerNumberOfLeadingZeros(HInvoke* invoke) {
-  X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
-  GenLeadingZeros(assembler, invoke, /* is_long */ false);
+  GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false);
 }
 
 void IntrinsicLocationsBuilderX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
@@ -2483,8 +2526,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitLongNumberOfLeadingZeros(HInvoke* invoke) {
-  X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
-  GenLeadingZeros(assembler, invoke, /* is_long */ true);
+  GenLeadingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
 }
 
 static void CreateTrailingZeroLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_long) {
@@ -2499,7 +2541,9 @@
   locations->SetOut(Location::RequiresRegister());
 }
 
-static void GenTrailingZeros(X86Assembler* assembler, HInvoke* invoke, bool is_long) {
+static void GenTrailingZeros(X86Assembler* assembler,
+                             CodeGeneratorX86* codegen,
+                             HInvoke* invoke, bool is_long) {
   LocationSummary* locations = invoke->GetLocations();
   Location src = locations->InAt(0);
   Register out = locations->Out().AsRegister<Register>();
@@ -2512,11 +2556,7 @@
     } else {
       value = is_long ? CTZ(static_cast<uint64_t>(value)) : CTZ(static_cast<uint32_t>(value));
     }
-    if (value == 0) {
-      __ xorl(out, out);
-    } else {
-      __ movl(out, Immediate(value));
-    }
+    codegen->Load32BitValue(out, value);
     return;
   }
 
@@ -2570,8 +2610,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitIntegerNumberOfTrailingZeros(HInvoke* invoke) {
-  X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
-  GenTrailingZeros(assembler, invoke, /* is_long */ false);
+  GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ false);
 }
 
 void IntrinsicLocationsBuilderX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
@@ -2579,8 +2618,7 @@
 }
 
 void IntrinsicCodeGeneratorX86::VisitLongNumberOfTrailingZeros(HInvoke* invoke) {
-  X86Assembler* assembler = down_cast<X86Assembler*>(codegen_->GetAssembler());
-  GenTrailingZeros(assembler, invoke, /* is_long */ true);
+  GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
 }
 
 // Unimplemented intrinsics.
@@ -2600,20 +2638,20 @@
 UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
 UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
 
-UNIMPLEMENTED_INTRINSIC(IntegerCompare)
-UNIMPLEMENTED_INTRINSIC(LongCompare)
 UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit)
 UNIMPLEMENTED_INTRINSIC(LongLowestOneBit)
-UNIMPLEMENTED_INTRINSIC(IntegerSignum)
-UNIMPLEMENTED_INTRINSIC(LongSignum)
 
-// Rotate operations are handled as HRor instructions.
+// Handled as HIR instructions.
 UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
+UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
 UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateRight)
-UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
 
 #undef UNIMPLEMENTED_INTRINSIC
 
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 51fa514..c9a4344 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2431,58 +2431,6 @@
   GenBitCount(GetAssembler(), codegen_, invoke, /* is_long */ true);
 }
 
-static void CreateCompareLocations(ArenaAllocator* arena, HInvoke* invoke) {
-  LocationSummary* locations = new (arena) LocationSummary(invoke,
-                                                           LocationSummary::kNoCall,
-                                                           kIntrinsified);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::RequiresRegister());
-  locations->SetOut(Location::RequiresRegister());
-}
-
-static void GenCompare(X86_64Assembler* assembler, HInvoke* invoke, bool is_long) {
-  LocationSummary* locations = invoke->GetLocations();
-  CpuRegister src1 = locations->InAt(0).AsRegister<CpuRegister>();
-  CpuRegister src2 = locations->InAt(1).AsRegister<CpuRegister>();
-  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
-
-  NearLabel is_lt, done;
-
-  __ xorl(out, out);
-
-  if (is_long) {
-    __ cmpq(src1, src2);
-  } else {
-    __ cmpl(src1, src2);
-  }
-  __ j(kEqual, &done);
-  __ j(kLess, &is_lt);
-
-  __ movl(out, Immediate(1));
-  __ jmp(&done);
-
-  __ Bind(&is_lt);
-  __ movl(out, Immediate(-1));
-
-  __ Bind(&done);
-}
-
-void IntrinsicLocationsBuilderX86_64::VisitIntegerCompare(HInvoke* invoke) {
-  CreateCompareLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86_64::VisitIntegerCompare(HInvoke* invoke) {
-  GenCompare(GetAssembler(), invoke, /* is_long */ false);
-}
-
-void IntrinsicLocationsBuilderX86_64::VisitLongCompare(HInvoke* invoke) {
-  CreateCompareLocations(arena_, invoke);
-}
-
-void IntrinsicCodeGeneratorX86_64::VisitLongCompare(HInvoke* invoke) {
-  GenCompare(GetAssembler(), invoke, /* is_long */ true);
-}
-
 static void CreateOneBitLocations(ArenaAllocator* arena, HInvoke* invoke, bool is_high) {
   LocationSummary* locations = new (arena) LocationSummary(invoke,
                                                            LocationSummary::kNoCall,
@@ -2757,74 +2705,6 @@
   GenTrailingZeros(GetAssembler(), codegen_, invoke, /* is_long */ true);
 }
 
-static void CreateSignLocations(ArenaAllocator* arena, HInvoke* invoke) {
-  LocationSummary* locations = new (arena) LocationSummary(invoke,
-                                                           LocationSummary::kNoCall,
-                                                           kIntrinsified);
-  locations->SetInAt(0, Location::Any());
-  locations->SetOut(Location::RequiresRegister());
-  locations->AddTemp(Location::RequiresRegister());  // Need a writeable register.
-}
-
-static void GenSign(X86_64Assembler* assembler,
-                    CodeGeneratorX86_64* codegen,
-                    HInvoke* invoke, bool is_long) {
-  LocationSummary* locations = invoke->GetLocations();
-  Location src = locations->InAt(0);
-  CpuRegister out = locations->Out().AsRegister<CpuRegister>();
-
-  if (invoke->InputAt(0)->IsConstant()) {
-    // Evaluate this at compile time.
-    int64_t value = Int64FromConstant(invoke->InputAt(0)->AsConstant());
-    codegen->Load32BitValue(out, value == 0 ? 0 : (value > 0 ? 1 : -1));
-    return;
-  }
-
-  // Copy input into temporary.
-  CpuRegister tmp = locations->GetTemp(0).AsRegister<CpuRegister>();
-  if (src.IsRegister()) {
-    if (is_long) {
-      __ movq(tmp, src.AsRegister<CpuRegister>());
-    } else {
-      __ movl(tmp, src.AsRegister<CpuRegister>());
-    }
-  } else if (is_long) {
-    DCHECK(src.IsDoubleStackSlot());
-    __ movq(tmp, Address(CpuRegister(RSP), src.GetStackIndex()));
-  } else {
-    DCHECK(src.IsStackSlot());
-    __ movl(tmp, Address(CpuRegister(RSP), src.GetStackIndex()));
-  }
-
-  // Do the bit twiddling: basically tmp >> 63/31 | -tmp >>> 63/31 for long/int.
-  if (is_long) {
-    __ movq(out, tmp);
-    __ sarq(out, Immediate(63));
-    __ negq(tmp);
-    __ shrq(tmp, Immediate(63));
-    __ orq(out, tmp);
-  } else {
-    __ movl(out, tmp);
-    __ sarl(out, Immediate(31));
-    __ negl(tmp);
-    __ shrl(tmp, Immediate(31));
-    __ orl(out, tmp);
-  }
-}
-
-void IntrinsicLocationsBuilderX86_64::VisitIntegerSignum(HInvoke* invoke) {
-  CreateSignLocations(arena_, invoke);
-}
-void IntrinsicCodeGeneratorX86_64::VisitIntegerSignum(HInvoke* invoke) {
-  GenSign(GetAssembler(), codegen_, invoke, /* is_long */ false);
-}
-void IntrinsicLocationsBuilderX86_64::VisitLongSignum(HInvoke* invoke) {
-  CreateSignLocations(arena_, invoke);
-}
-void IntrinsicCodeGeneratorX86_64::VisitLongSignum(HInvoke* invoke) {
-  GenSign(GetAssembler(), codegen_, invoke, /* is_long */ true);
-}
-
 // Unimplemented intrinsics.
 
 #define UNIMPLEMENTED_INTRINSIC(Name)                                                   \
@@ -2840,11 +2720,15 @@
 UNIMPLEMENTED_INTRINSIC(FloatIsNaN)
 UNIMPLEMENTED_INTRINSIC(DoubleIsNaN)
 
-// Rotate operations are handled as HRor instructions.
+// Handled as HIR instructions.
 UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft)
-UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateLeft)
+UNIMPLEMENTED_INTRINSIC(IntegerRotateRight)
 UNIMPLEMENTED_INTRINSIC(LongRotateRight)
+UNIMPLEMENTED_INTRINSIC(IntegerCompare)
+UNIMPLEMENTED_INTRINSIC(LongCompare)
+UNIMPLEMENTED_INTRINSIC(IntegerSignum)
+UNIMPLEMENTED_INTRINSIC(LongSignum)
 
 #undef UNIMPLEMENTED_INTRINSIC
 
diff --git a/compiler/optimizing/licm_test.cc b/compiler/optimizing/licm_test.cc
index 2b63ec8..9fb32f4 100644
--- a/compiler/optimizing/licm_test.cc
+++ b/compiler/optimizing/licm_test.cc
@@ -76,7 +76,7 @@
 
   // Performs LICM optimizations (after proper set up).
   void PerformLICM() {
-    TransformToSsa(graph_);
+    graph_->BuildDominatorTree();
     SideEffectsAnalysis side_effects(graph_);
     side_effects.Run();
     LICM(graph_, side_effects).Run();
diff --git a/compiler/optimizing/linearize_test.cc b/compiler/optimizing/linearize_test.cc
index ed275b1..13e14c5 100644
--- a/compiler/optimizing/linearize_test.cc
+++ b/compiler/optimizing/linearize_test.cc
@@ -39,14 +39,7 @@
 static void TestCode(const uint16_t* data, const uint32_t (&expected_order)[number_of_blocks]) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateGraph(&allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  bool graph_built = builder.BuildGraph(*item);
-  ASSERT_TRUE(graph_built);
-
-  TransformToSsa(graph);
-
+  HGraph* graph = CreateCFG(&allocator, data);
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
       X86InstructionSetFeatures::FromCppDefines());
   x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 991f8f7..3202493 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -32,14 +32,10 @@
 class LiveRangesTest : public CommonCompilerTest {};
 
 static HGraph* BuildGraph(const uint16_t* data, ArenaAllocator* allocator) {
-  HGraph* graph = CreateGraph(allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  builder.BuildGraph(*item);
+  HGraph* graph = CreateCFG(allocator, data);
   // Suspend checks implementation may change in the future, and this test relies
   // on how instructions are ordered.
   RemoveSuspendChecks(graph);
-  TransformToSsa(graph);
   // `Inline` conditions into ifs.
   PrepareForRegisterAllocation(graph).Run();
   return graph;
@@ -303,13 +299,12 @@
    *       12: equal
    *       14: if +++++
    *        |       \ +
-   *        |     18: suspend
-   *        |     20: add
-   *        |     22: goto
+   *        |     18: add
+   *        |     20: goto
    *        |
-   *       26: return
+   *       24: return
    *         |
-   *       30: exit
+   *       28: exit
    *
    * We want to make sure the phi at 10 has a lifetime hole after the add at 20.
    */
@@ -345,18 +340,18 @@
   interval = phi->GetLiveInterval();
   range = interval->GetFirstRange();
   ASSERT_EQ(10u, range->GetStart());
-  ASSERT_EQ(21u, range->GetEnd());
+  ASSERT_EQ(19u, range->GetEnd());
   range = range->GetNext();
   ASSERT_TRUE(range != nullptr);
-  ASSERT_EQ(24u, range->GetStart());
-  ASSERT_EQ(26u, range->GetEnd());
+  ASSERT_EQ(22u, range->GetStart());
+  ASSERT_EQ(24u, range->GetEnd());
 
   // Test for the add instruction.
   HAdd* add = liveness.GetInstructionFromSsaIndex(2)->AsAdd();
   interval = add->GetLiveInterval();
   range = interval->GetFirstRange();
-  ASSERT_EQ(20u, range->GetStart());
-  ASSERT_EQ(24u, range->GetEnd());
+  ASSERT_EQ(18u, range->GetStart());
+  ASSERT_EQ(22u, range->GetEnd());
   ASSERT_TRUE(range->GetNext() == nullptr);
 }
 
diff --git a/compiler/optimizing/liveness_test.cc b/compiler/optimizing/liveness_test.cc
index 7736eed..92a987c 100644
--- a/compiler/optimizing/liveness_test.cc
+++ b/compiler/optimizing/liveness_test.cc
@@ -46,12 +46,7 @@
 static void TestCode(const uint16_t* data, const char* expected) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateGraph(&allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  bool graph_built = builder.BuildGraph(*item);
-  ASSERT_TRUE(graph_built);
-  TransformToSsa(graph);
+  HGraph* graph = CreateCFG(&allocator, data);
   // `Inline` conditions into ifs.
   PrepareForRegisterAllocation(graph).Run();
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 9a97f54..8eaac0b 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -61,7 +61,7 @@
           (use->IsStaticFieldSet() && (reference_ == use->InputAt(1))) ||
           (use->IsUnresolvedStaticFieldSet() && (reference_ == use->InputAt(0))) ||
           (use->IsArraySet() && (reference_ == use->InputAt(2)))) {
-        // reference_ is merged to a phi/HSelect, passed to a callee, or stored to heap.
+        // reference_ is merged to HPhi/HSelect, passed to a callee, or stored to heap.
         // reference_ isn't the only name that can refer to its value anymore.
         is_singleton_ = false;
         is_singleton_and_not_returned_ = false;
@@ -458,6 +458,10 @@
     CreateReferenceInfoForReferenceType(instruction);
   }
 
+  void VisitSelect(HSelect* instruction) OVERRIDE {
+    CreateReferenceInfoForReferenceType(instruction);
+  }
+
   void VisitDeoptimize(HDeoptimize* instruction ATTRIBUTE_UNUSED) OVERRIDE {
     may_deoptimize_ = true;
   }
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index c057eca..27015c0 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -27,6 +27,15 @@
 
 namespace art {
 
+void HGraph::InitializeInexactObjectRTI(StackHandleScopeCollection* handles) {
+  ScopedObjectAccess soa(Thread::Current());
+  // Create the inexact Object reference type and store it in the HGraph.
+  ClassLinker* linker = Runtime::Current()->GetClassLinker();
+  inexact_object_rti_ = ReferenceTypeInfo::Create(
+      handles->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject)),
+      /* is_exact */ false);
+}
+
 void HGraph::AddBlock(HBasicBlock* block) {
   block->SetBlockId(blocks_.size());
   blocks_.push_back(block);
@@ -236,29 +245,6 @@
   }
 }
 
-GraphAnalysisResult HGraph::TryBuildingSsa(StackHandleScopeCollection* handles) {
-  GraphAnalysisResult result = BuildDominatorTree();
-  if (result != kAnalysisSuccess) {
-    return result;
-  }
-
-  // Create the inexact Object reference type and store it in the HGraph.
-  ScopedObjectAccess soa(Thread::Current());
-  ClassLinker* linker = Runtime::Current()->GetClassLinker();
-  inexact_object_rti_ = ReferenceTypeInfo::Create(
-      handles->NewHandle(linker->GetClassRoot(ClassLinker::kJavaLangObject)),
-      /* is_exact */ false);
-
-  // Tranforms graph to SSA form.
-  result = SsaBuilder(this, handles).BuildSsa();
-  if (result != kAnalysisSuccess) {
-    return result;
-  }
-
-  in_ssa_form_ = true;
-  return kAnalysisSuccess;
-}
-
 HBasicBlock* HGraph::SplitEdge(HBasicBlock* block, HBasicBlock* successor) {
   HBasicBlock* new_block = new (arena_) HBasicBlock(this, successor->GetDexPc());
   AddBlock(new_block);
@@ -647,6 +633,10 @@
       header_->GetGraph()->SetHasIrreducibleLoops(true);
       PopulateIrreducibleRecursive(back_edge);
     } else {
+      if (header_->GetGraph()->IsCompilingOsr()) {
+        irreducible_ = true;
+        header_->GetGraph()->SetHasIrreducibleLoops(true);
+      }
       PopulateRecursive(back_edge);
     }
   }
@@ -858,7 +848,6 @@
       // At the end of the loop pre-header, the corresponding value for instruction
       // is the first input of the phi.
       HInstruction* initial = instruction->AsPhi()->InputAt(0);
-      DCHECK(initial->GetBlock()->Dominates(loop_header));
       SetRawEnvAt(i, initial);
       initial->AddEnvUseAt(this, i);
     } else {
@@ -1589,7 +1578,7 @@
     loop_info->Remove(this);
     if (loop_info->IsBackEdge(*this)) {
       // If this was the last back edge of the loop, we deliberately leave the
-      // loop in an inconsistent state and will fail SSAChecker unless the
+      // loop in an inconsistent state and will fail GraphChecker unless the
       // entire loop is removed during the pass.
       loop_info->RemoveBackEdge(this);
     }
@@ -1628,7 +1617,7 @@
     } else if (num_pred_successors == 0u) {
       // The predecessor has no remaining successors and therefore must be dead.
       // We deliberately leave it without a control-flow instruction so that the
-      // SSAChecker fails unless it is not removed during the pass too.
+      // GraphChecker fails unless it is not removed during the pass too.
       predecessor->RemoveInstruction(last_instruction);
     } else {
       // There are multiple successors left. The removed block might be a successor
@@ -2041,13 +2030,6 @@
     }
   }
 
-  if (return_value != nullptr) {
-    invoke->ReplaceWith(return_value);
-  }
-
-  // Finally remove the invoke from the caller.
-  invoke->GetBlock()->RemoveInstruction(invoke);
-
   return return_value;
 }
 
@@ -2384,4 +2366,26 @@
   return os;
 }
 
+std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs) {
+  switch (rhs) {
+    case TypeCheckKind::kUnresolvedCheck:
+      return os << "unresolved_check";
+    case TypeCheckKind::kExactCheck:
+      return os << "exact_check";
+    case TypeCheckKind::kClassHierarchyCheck:
+      return os << "class_hierarchy_check";
+    case TypeCheckKind::kAbstractClassCheck:
+      return os << "abstract_class_check";
+    case TypeCheckKind::kInterfaceCheck:
+      return os << "interface_check";
+    case TypeCheckKind::kArrayObjectCheck:
+      return os << "array_object_check";
+    case TypeCheckKind::kArrayCheck:
+      return os << "array_check";
+    default:
+      LOG(FATAL) << "Unknown TypeCheckKind: " << static_cast<int>(rhs);
+      UNREACHABLE();
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index b808347..854854f 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -98,6 +98,7 @@
 };
 
 enum GraphAnalysisResult {
+  kAnalysisInvalidBytecode,
   kAnalysisFailThrowCatchLoop,
   kAnalysisFailAmbiguousArrayOp,
   kAnalysisSuccess,
@@ -274,6 +275,7 @@
          InstructionSet instruction_set,
          InvokeType invoke_type = kInvalidInvokeType,
          bool debuggable = false,
+         bool osr = false,
          int start_instruction_id = 0)
       : arena_(arena),
         blocks_(arena->Adapter(kArenaAllocBlockList)),
@@ -302,14 +304,19 @@
         cached_long_constants_(std::less<int64_t>(), arena->Adapter(kArenaAllocConstantsMap)),
         cached_double_constants_(std::less<int64_t>(), arena->Adapter(kArenaAllocConstantsMap)),
         cached_current_method_(nullptr),
-        inexact_object_rti_(ReferenceTypeInfo::CreateInvalid()) {
+        inexact_object_rti_(ReferenceTypeInfo::CreateInvalid()),
+        osr_(osr) {
     blocks_.reserve(kDefaultNumberOfBlocks);
   }
 
+  // Acquires and stores RTI of inexact Object to be used when creating HNullConstant.
+  void InitializeInexactObjectRTI(StackHandleScopeCollection* handles);
+
   ArenaAllocator* GetArena() const { return arena_; }
   const ArenaVector<HBasicBlock*>& GetBlocks() const { return blocks_; }
 
   bool IsInSsaForm() const { return in_ssa_form_; }
+  void SetInSsaForm() { in_ssa_form_ = true; }
 
   HBasicBlock* GetEntryBlock() const { return entry_block_; }
   HBasicBlock* GetExitBlock() const { return exit_block_; }
@@ -320,11 +327,6 @@
 
   void AddBlock(HBasicBlock* block);
 
-  // Try building the SSA form of this graph, with dominance computation and
-  // loop recognition. Returns a code specifying that it was successful or the
-  // reason for failure.
-  GraphAnalysisResult TryBuildingSsa(StackHandleScopeCollection* handles);
-
   void ComputeDominanceInformation();
   void ClearDominanceInformation();
   void ClearLoopInformation();
@@ -343,8 +345,9 @@
   void ComputeTryBlockInformation();
 
   // Inline this graph in `outer_graph`, replacing the given `invoke` instruction.
-  // Returns the instruction used to replace the invoke expression or null if the
-  // invoke is for a void method.
+  // Returns the instruction to replace the invoke expression or null if the
+  // invoke is for a void method. Note that the caller is responsible for replacing
+  // and removing the invoke instruction.
   HInstruction* InlineInto(HGraph* outer_graph, HInvoke* invoke);
 
   // Need to add a couple of blocks to test if the loop body is entered and
@@ -478,6 +481,8 @@
     return instruction_set_;
   }
 
+  bool IsCompilingOsr() const { return osr_; }
+
   bool HasTryCatch() const { return has_try_catch_; }
   void SetHasTryCatch(bool value) { has_try_catch_ = value; }
 
@@ -606,6 +611,11 @@
   // collection pointer to passes which may create NullConstant.
   ReferenceTypeInfo inexact_object_rti_;
 
+  // Whether we are compiling this graph for on stack replacement: this will
+  // make all loops seen as irreducible and emit special stack maps to mark
+  // compiled code entries which the interpreter can directly jump to.
+  const bool osr_;
+
   friend class SsaBuilder;           // For caching constants.
   friend class SsaLivenessAnalysis;  // For the linear order.
   ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1);
@@ -1226,7 +1236,6 @@
   M(StoreLocal, Instruction)                                            \
   M(Sub, BinaryOperation)                                               \
   M(SuspendCheck, Instruction)                                          \
-  M(Temporary, Instruction)                                             \
   M(Throw, Instruction)                                                 \
   M(TryBoundary, Instruction)                                           \
   M(TypeConversion, Instruction)                                        \
@@ -1259,6 +1268,7 @@
 #define FOR_EACH_CONCRETE_INSTRUCTION_X86(M)                            \
   M(X86ComputeBaseMethodAddress, Instruction)                           \
   M(X86LoadFromConstantTable, Instruction)                              \
+  M(X86FPNeg, Instruction)                                              \
   M(X86PackedSwitch, Instruction)
 #endif
 
@@ -3662,6 +3672,7 @@
   // method pointer; otherwise there may be one platform-specific special input,
   // such as PC-relative addressing base.
   uint32_t GetSpecialInputIndex() const { return GetNumberOfArguments(); }
+  bool HasSpecialInput() const { return GetNumberOfArguments() != InputCount(); }
 
   InvokeType GetOptimizedInvokeType() const { return optimized_invoke_type_; }
   void SetOptimizedInvokeType(InvokeType invoke_type) {
@@ -4931,33 +4942,6 @@
   DISALLOW_COPY_AND_ASSIGN(HBoundsCheck);
 };
 
-/**
- * Some DEX instructions are folded into multiple HInstructions that need
- * to stay live until the last HInstruction. This class
- * is used as a marker for the baseline compiler to ensure its preceding
- * HInstruction stays live. `index` represents the stack location index of the
- * instruction (the actual offset is computed as index * vreg_size).
- */
-class HTemporary : public HTemplateInstruction<0> {
- public:
-  explicit HTemporary(size_t index, uint32_t dex_pc = kNoDexPc)
-      : HTemplateInstruction(SideEffects::None(), dex_pc), index_(index) {}
-
-  size_t GetIndex() const { return index_; }
-
-  Primitive::Type GetType() const OVERRIDE {
-    // The previous instruction is the one that will be stored in the temporary location.
-    DCHECK(GetPrevious() != nullptr);
-    return GetPrevious()->GetType();
-  }
-
-  DECLARE_INSTRUCTION(Temporary);
-
- private:
-  const size_t index_;
-  DISALLOW_COPY_AND_ASSIGN(HTemporary);
-};
-
 class HSuspendCheck : public HTemplateInstruction<0> {
  public:
   explicit HSuspendCheck(uint32_t dex_pc)
@@ -5441,6 +5425,8 @@
   kArrayCheck             // No optimization yet when checking against a generic array.
 };
 
+std::ostream& operator<<(std::ostream& os, TypeCheckKind rhs);
+
 class HInstanceOf : public HExpression<2> {
  public:
   HInstanceOf(HInstruction* object,
@@ -6013,9 +5999,14 @@
 };
 
 inline int64_t Int64FromConstant(HConstant* constant) {
-  DCHECK(constant->IsIntConstant() || constant->IsLongConstant());
-  return constant->IsIntConstant() ? constant->AsIntConstant()->GetValue()
-                                   : constant->AsLongConstant()->GetValue();
+  if (constant->IsIntConstant()) {
+    return constant->AsIntConstant()->GetValue();
+  } else if (constant->IsLongConstant()) {
+    return constant->AsLongConstant()->GetValue();
+  } else {
+    DCHECK(constant->IsNullConstant());
+    return 0;
+  }
 }
 
 inline bool IsSameDexFile(const DexFile& lhs, const DexFile& rhs) {
@@ -6040,6 +6031,74 @@
   FOR_EACH_CONCRETE_INSTRUCTION(INSTRUCTION_TYPE_CHECK)
 #undef INSTRUCTION_TYPE_CHECK
 
+class SwitchTable : public ValueObject {
+ public:
+  SwitchTable(const Instruction& instruction, uint32_t dex_pc, bool sparse)
+      : instruction_(instruction), dex_pc_(dex_pc), sparse_(sparse) {
+    int32_t table_offset = instruction.VRegB_31t();
+    const uint16_t* table = reinterpret_cast<const uint16_t*>(&instruction) + table_offset;
+    if (sparse) {
+      CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kSparseSwitchSignature));
+    } else {
+      CHECK_EQ(table[0], static_cast<uint16_t>(Instruction::kPackedSwitchSignature));
+    }
+    num_entries_ = table[1];
+    values_ = reinterpret_cast<const int32_t*>(&table[2]);
+  }
+
+  uint16_t GetNumEntries() const {
+    return num_entries_;
+  }
+
+  void CheckIndex(size_t index) const {
+    if (sparse_) {
+      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
+      DCHECK_LT(index, 2 * static_cast<size_t>(num_entries_));
+    } else {
+      // In a packed table, we have the starting key and num_entries_ values.
+      DCHECK_LT(index, 1 + static_cast<size_t>(num_entries_));
+    }
+  }
+
+  int32_t GetEntryAt(size_t index) const {
+    CheckIndex(index);
+    return values_[index];
+  }
+
+  uint32_t GetDexPcForIndex(size_t index) const {
+    CheckIndex(index);
+    return dex_pc_ +
+        (reinterpret_cast<const int16_t*>(values_ + index) -
+         reinterpret_cast<const int16_t*>(&instruction_));
+  }
+
+  // Index of the first value in the table.
+  size_t GetFirstValueIndex() const {
+    if (sparse_) {
+      // In a sparse table, we have num_entries_ keys and num_entries_ values, in that order.
+      return num_entries_;
+    } else {
+      // In a packed table, we have the starting key and num_entries_ values.
+      return 1;
+    }
+  }
+
+ private:
+  const Instruction& instruction_;
+  const uint32_t dex_pc_;
+
+  // Whether this is a sparse-switch table (or a packed-switch one).
+  const bool sparse_;
+
+  // This can't be const as it needs to be computed off of the given instruction, and complicated
+  // expressions in the initializer list seemed very ugly.
+  uint16_t num_entries_;
+
+  const int32_t* values_;
+
+  DISALLOW_COPY_AND_ASSIGN(SwitchTable);
+};
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_NODES_H_
diff --git a/compiler/optimizing/nodes_x86.h b/compiler/optimizing/nodes_x86.h
index b1bf939..0b3a84d 100644
--- a/compiler/optimizing/nodes_x86.h
+++ b/compiler/optimizing/nodes_x86.h
@@ -56,6 +56,25 @@
   DISALLOW_COPY_AND_ASSIGN(HX86LoadFromConstantTable);
 };
 
+// Version of HNeg with access to the constant table for FP types.
+class HX86FPNeg : public HExpression<2> {
+ public:
+  HX86FPNeg(Primitive::Type result_type,
+            HInstruction* input,
+            HX86ComputeBaseMethodAddress* method_base,
+            uint32_t dex_pc)
+      : HExpression(result_type, SideEffects::None(), dex_pc) {
+    DCHECK(Primitive::IsFloatingPointType(result_type));
+    SetRawInputAt(0, input);
+    SetRawInputAt(1, method_base);
+  }
+
+  DECLARE_INSTRUCTION(X86FPNeg);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HX86FPNeg);
+};
+
 // X86 version of HPackedSwitch that holds a pointer to the base method address.
 class HX86PackedSwitch : public HTemplateInstruction<2> {
  public:
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index bdc664b..12b748b 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -45,15 +45,14 @@
 #include "compiler.h"
 #include "constant_folding.h"
 #include "dead_code_elimination.h"
+#include "debug/elf_debug_writer.h"
+#include "debug/method_debug_info.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
-#include "dex/verified_method.h"
 #include "dex/verification_results.h"
-#include "driver/compiler_driver.h"
+#include "dex/verified_method.h"
 #include "driver/compiler_driver-inl.h"
 #include "driver/compiler_options.h"
 #include "driver/dex_compilation_unit.h"
-#include "dwarf/method_debug_info.h"
-#include "elf_writer_debug.h"
 #include "elf_writer_quick.h"
 #include "graph_checker.h"
 #include "graph_visualizer.h"
@@ -64,20 +63,20 @@
 #include "intrinsics.h"
 #include "jit/debugger_interface.h"
 #include "jit/jit_code_cache.h"
-#include "licm.h"
 #include "jni/quick/jni_compiler.h"
+#include "licm.h"
 #include "load_store_elimination.h"
 #include "nodes.h"
+#include "oat_quick_method_header.h"
 #include "prepare_for_register_allocation.h"
 #include "reference_type_propagation.h"
 #include "register_allocator.h"
-#include "oat_quick_method_header.h"
 #include "select_generator.h"
 #include "sharpening.h"
 #include "side_effects_analysis.h"
 #include "ssa_builder.h"
-#include "ssa_phi_elimination.h"
 #include "ssa_liveness_analysis.h"
+#include "ssa_phi_elimination.h"
 #include "utils/assembler.h"
 #include "verifier/method_verifier.h"
 
@@ -187,18 +186,10 @@
     // Validate the HGraph if running in debug mode.
     if (kIsDebugBuild) {
       if (!graph_in_bad_state_) {
-        if (graph_->IsInSsaForm()) {
-          SSAChecker checker(graph_);
-          checker.Run();
-          if (!checker.IsValid()) {
-            LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<SSAChecker>(checker);
-          }
-        } else {
-          GraphChecker checker(graph_);
-          checker.Run();
-          if (!checker.IsValid()) {
-            LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<GraphChecker>(checker);
-          }
+        GraphChecker checker(graph_);
+        checker.Run();
+        if (!checker.IsValid()) {
+          LOG(FATAL) << "Error after " << pass_name << ": " << Dumpable<GraphChecker>(checker);
         }
       }
     }
@@ -300,7 +291,7 @@
     }
   }
 
-  bool JitCompile(Thread* self, jit::JitCodeCache* code_cache, ArtMethod* method)
+  bool JitCompile(Thread* self, jit::JitCodeCache* code_cache, ArtMethod* method, bool osr)
       OVERRIDE
       SHARED_REQUIRES(Locks::mutator_lock_);
 
@@ -309,7 +300,8 @@
   CompiledMethod* Emit(ArenaAllocator* arena,
                        CodeVectorAllocator* code_allocator,
                        CodeGenerator* codegen,
-                       CompilerDriver* driver) const;
+                       CompilerDriver* driver,
+                       const DexFile::CodeItem* item) const;
 
   // Try compiling a method and return the code generator used for
   // compiling it.
@@ -327,7 +319,8 @@
                             uint32_t method_idx,
                             jobject class_loader,
                             const DexFile& dex_file,
-                            Handle<mirror::DexCache> dex_cache) const;
+                            Handle<mirror::DexCache> dex_cache,
+                            bool osr) const;
 
   std::unique_ptr<OptimizingCompilerStats> compilation_stats_;
 
@@ -580,11 +573,12 @@
 CompiledMethod* OptimizingCompiler::Emit(ArenaAllocator* arena,
                                          CodeVectorAllocator* code_allocator,
                                          CodeGenerator* codegen,
-                                         CompilerDriver* compiler_driver) const {
+                                         CompilerDriver* compiler_driver,
+                                         const DexFile::CodeItem* code_item) const {
   ArenaVector<LinkerPatch> linker_patches = EmitAndSortLinkerPatches(codegen);
   ArenaVector<uint8_t> stack_map(arena->Adapter(kArenaAllocStackMaps));
   stack_map.resize(codegen->ComputeStackMapsSize());
-  codegen->BuildStackMaps(MemoryRegion(stack_map.data(), stack_map.size()));
+  codegen->BuildStackMaps(MemoryRegion(stack_map.data(), stack_map.size()), *code_item);
 
   CompiledMethod* compiled_method = CompiledMethod::SwapAllocCompiledMethod(
       compiler_driver,
@@ -615,7 +609,8 @@
                                               uint32_t method_idx,
                                               jobject class_loader,
                                               const DexFile& dex_file,
-                                              Handle<mirror::DexCache> dex_cache) const {
+                                              Handle<mirror::DexCache> dex_cache,
+                                              bool osr) const {
   MaybeRecordStat(MethodCompilationStat::kAttemptCompilation);
   CompilerDriver* compiler_driver = GetCompilerDriver();
   InstructionSet instruction_set = compiler_driver->GetInstructionSet();
@@ -662,9 +657,31 @@
       && compiler_driver->RequiresConstructorBarrier(Thread::Current(),
                                                      dex_compilation_unit.GetDexFile(),
                                                      dex_compilation_unit.GetClassDefIndex());
+
   HGraph* graph = new (arena) HGraph(
-      arena, dex_file, method_idx, requires_barrier, compiler_driver->GetInstructionSet(),
-      kInvalidInvokeType, compiler_driver->GetCompilerOptions().GetDebuggable());
+      arena,
+      dex_file,
+      method_idx,
+      requires_barrier,
+      compiler_driver->GetInstructionSet(),
+      kInvalidInvokeType,
+      compiler_driver->GetCompilerOptions().GetDebuggable(),
+      osr);
+
+  const uint8_t* interpreter_metadata = nullptr;
+  {
+    ScopedObjectAccess soa(Thread::Current());
+    StackHandleScope<1> hs(soa.Self());
+    Handle<mirror::ClassLoader> loader(hs.NewHandle(
+        soa.Decode<mirror::ClassLoader*>(class_loader)));
+    ArtMethod* art_method = compiler_driver->ResolveMethod(
+        soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type);
+    // We may not get a method, for example if its class is erroneous.
+    if (art_method != nullptr) {
+      graph->SetArtMethod(art_method);
+      interpreter_metadata = art_method->GetQuickenedInfo();
+    }
+  }
 
   std::unique_ptr<CodeGenerator> codegen(
       CodeGenerator::Create(graph,
@@ -683,73 +700,54 @@
                              visualizer_output_.get(),
                              compiler_driver);
 
-  const uint8_t* interpreter_metadata = nullptr;
-  {
-    ScopedObjectAccess soa(Thread::Current());
-    StackHandleScope<1> hs(soa.Self());
-    Handle<mirror::ClassLoader> loader(hs.NewHandle(
-        soa.Decode<mirror::ClassLoader*>(class_loader)));
-    ArtMethod* art_method = compiler_driver->ResolveMethod(
-        soa, dex_cache, loader, &dex_compilation_unit, method_idx, invoke_type);
-    // We may not get a method, for example if its class is erroneous.
-    if (art_method != nullptr) {
-      graph->SetArtMethod(art_method);
-      interpreter_metadata = art_method->GetQuickenedInfo();
-    }
-  }
-  HGraphBuilder builder(graph,
-                        &dex_compilation_unit,
-                        &dex_compilation_unit,
-                        &dex_file,
-                        compiler_driver,
-                        compilation_stats_.get(),
-                        interpreter_metadata,
-                        dex_cache);
-
   VLOG(compiler) << "Building " << pass_observer.GetMethodName();
 
   {
-    PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
-    if (!builder.BuildGraph(*code_item)) {
-      pass_observer.SetGraphInBadState();
-      return nullptr;
-    }
-  }
+    ScopedObjectAccess soa(Thread::Current());
+    StackHandleScopeCollection handles(soa.Self());
+    // Do not hold `mutator_lock_` between optimizations.
+    ScopedThreadSuspension sts(soa.Self(), kNative);
 
-  VLOG(compiler) << "Optimizing " << pass_observer.GetMethodName();
-
-  ScopedObjectAccess soa(Thread::Current());
-  StackHandleScopeCollection handles(soa.Self());
-  ScopedThreadSuspension sts(soa.Self(), kNative);
-
-  {
-    PassScope scope(SsaBuilder::kSsaBuilderPassName, &pass_observer);
-    GraphAnalysisResult result = graph->TryBuildingSsa(&handles);
-    if (result != kAnalysisSuccess) {
-      switch (result) {
-        case kAnalysisFailThrowCatchLoop:
-          MaybeRecordStat(MethodCompilationStat::kNotCompiledThrowCatchLoop);
-          break;
-        case kAnalysisFailAmbiguousArrayOp:
-          MaybeRecordStat(MethodCompilationStat::kNotCompiledAmbiguousArrayOp);
-          break;
-        case kAnalysisSuccess:
-          UNREACHABLE();
+    {
+      PassScope scope(HGraphBuilder::kBuilderPassName, &pass_observer);
+      HGraphBuilder builder(graph,
+                            &dex_compilation_unit,
+                            &dex_compilation_unit,
+                            &dex_file,
+                            compiler_driver,
+                            compilation_stats_.get(),
+                            interpreter_metadata,
+                            dex_cache);
+      GraphAnalysisResult result = builder.BuildGraph(*code_item, &handles);
+      if (result != kAnalysisSuccess) {
+        switch (result) {
+          case kAnalysisInvalidBytecode:
+            break;
+          case kAnalysisFailThrowCatchLoop:
+            MaybeRecordStat(MethodCompilationStat::kNotCompiledThrowCatchLoop);
+            break;
+          case kAnalysisFailAmbiguousArrayOp:
+            MaybeRecordStat(MethodCompilationStat::kNotCompiledAmbiguousArrayOp);
+            break;
+          case kAnalysisSuccess:
+            UNREACHABLE();
+        }
+        pass_observer.SetGraphInBadState();
+        return nullptr;
       }
-      pass_observer.SetGraphInBadState();
-      return nullptr;
     }
-  }
 
-  RunOptimizations(graph,
-                   codegen.get(),
-                   compiler_driver,
-                   compilation_stats_.get(),
-                   dex_compilation_unit,
-                   &pass_observer,
-                   &handles);
-  codegen->Compile(code_allocator);
-  pass_observer.DumpDisassembly();
+    RunOptimizations(graph,
+                     codegen.get(),
+                     compiler_driver,
+                     compilation_stats_.get(),
+                     dex_compilation_unit,
+                     &pass_observer,
+                     &handles);
+
+    codegen->Compile(code_allocator);
+    pass_observer.DumpDisassembly();
+  }
 
   if (kArenaAllocatorCountAllocations) {
     if (arena->BytesAllocated() > 4 * MB) {
@@ -797,10 +795,11 @@
                    method_idx,
                    jclass_loader,
                    dex_file,
-                   dex_cache));
+                   dex_cache,
+                   /* osr */ false));
     if (codegen.get() != nullptr) {
       MaybeRecordStat(MethodCompilationStat::kCompiled);
-      method = Emit(&arena, &code_allocator, codegen.get(), compiler_driver);
+      method = Emit(&arena, &code_allocator, codegen.get(), compiler_driver, code_item);
     }
   } else {
     if (compiler_driver->GetCompilerOptions().VerifyAtRuntime()) {
@@ -843,7 +842,8 @@
 
 bool OptimizingCompiler::JitCompile(Thread* self,
                                     jit::JitCodeCache* code_cache,
-                                    ArtMethod* method) {
+                                    ArtMethod* method,
+                                    bool osr) {
   StackHandleScope<2> hs(self);
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
       method->GetDeclaringClass()->GetClassLoader()));
@@ -873,7 +873,8 @@
                    method_idx,
                    jclass_loader,
                    *dex_file,
-                   dex_cache));
+                   dex_cache,
+                   osr));
     if (codegen.get() == nullptr) {
       return false;
     }
@@ -885,7 +886,7 @@
     return false;
   }
   MaybeRecordStat(MethodCompilationStat::kCompiled);
-  codegen->BuildStackMaps(MemoryRegion(stack_map_data, stack_map_size));
+  codegen->BuildStackMaps(MemoryRegion(stack_map_data, stack_map_size), *code_item);
   const void* code = code_cache->CommitCode(
       self,
       method,
@@ -896,7 +897,8 @@
       codegen->GetCoreSpillMask(),
       codegen->GetFpuSpillMask(),
       code_allocator.GetMemory().data(),
-      code_allocator.GetSize());
+      code_allocator.GetSize(),
+      osr);
 
   if (code == nullptr) {
     code_cache->ClearData(self, stack_map_data);
@@ -919,7 +921,7 @@
         ArrayRef<const uint8_t>(),  // native_gc_map.
         ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()),
         ArrayRef<const LinkerPatch>());
-    dwarf::MethodDebugInfo method_debug_info {
+    debug::MethodDebugInfo method_debug_info {
         dex_file,
         class_def_idx,
         method_idx,
@@ -930,7 +932,7 @@
         code_address + code_allocator.GetSize(),
         &compiled_method
     };
-    ArrayRef<const uint8_t> elf_file = dwarf::WriteDebugElfFileForMethod(method_debug_info);
+    ArrayRef<const uint8_t> elf_file = debug::WriteDebugElfFileForMethod(method_debug_info);
     CreateJITCodeEntryForAddress(code_address,
                                  std::unique_ptr<const uint8_t[]>(elf_file.data()),
                                  elf_file.size());
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 5a91043..0c7648e 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -64,10 +64,12 @@
 
 void RemoveSuspendChecks(HGraph* graph) {
   for (HBasicBlock* block : graph->GetBlocks()) {
-    for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
-      HInstruction* current = it.Current();
-      if (current->IsSuspendCheck()) {
-        current->GetBlock()->RemoveInstruction(current);
+    if (block != nullptr) {
+      for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
+        HInstruction* current = it.Current();
+        if (current->IsSuspendCheck()) {
+          current->GetBlock()->RemoveInstruction(current);
+        }
       }
     }
   }
@@ -83,12 +85,17 @@
 inline HGraph* CreateCFG(ArenaAllocator* allocator,
                          const uint16_t* data,
                          Primitive::Type return_type = Primitive::kPrimInt) {
-  HGraph* graph = CreateGraph(allocator);
-  HGraphBuilder builder(graph, return_type);
   const DexFile::CodeItem* item =
     reinterpret_cast<const DexFile::CodeItem*>(data);
-  bool graph_built = builder.BuildGraph(*item);
-  return graph_built ? graph : nullptr;
+  HGraph* graph = CreateGraph(allocator);
+
+  {
+    ScopedObjectAccess soa(Thread::Current());
+    StackHandleScopeCollection handles(soa.Self());
+    HGraphBuilder builder(graph, return_type);
+    bool graph_built = (builder.BuildGraph(*item, &handles) == kAnalysisSuccess);
+    return graph_built ? graph : nullptr;
+  }
 }
 
 // Naive string diff data type.
@@ -114,12 +121,6 @@
   return instruction->GetBlock() == nullptr;
 }
 
-inline void TransformToSsa(HGraph* graph) {
-  ScopedObjectAccess soa(Thread::Current());
-  StackHandleScopeCollection handles(soa.Self());
-  EXPECT_EQ(graph->TryBuildingSsa(&handles), kAnalysisSuccess);
-}
-
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc
index a2180bc..a6f1461 100644
--- a/compiler/optimizing/pc_relative_fixups_x86.cc
+++ b/compiler/optimizing/pc_relative_fixups_x86.cc
@@ -53,6 +53,10 @@
     BinaryFP(div);
   }
 
+  void VisitCompare(HCompare* compare) OVERRIDE {
+    BinaryFP(compare);
+  }
+
   void VisitReturn(HReturn* ret) OVERRIDE {
     HConstant* value = ret->InputAt(0)->AsConstant();
     if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
@@ -74,11 +78,50 @@
 
   void BinaryFP(HBinaryOperation* bin) {
     HConstant* rhs = bin->InputAt(1)->AsConstant();
-    if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) {
+    if (rhs != nullptr && Primitive::IsFloatingPointType(rhs->GetType())) {
       ReplaceInput(bin, rhs, 1, false);
     }
   }
 
+  void VisitEqual(HEqual* cond) OVERRIDE {
+    BinaryFP(cond);
+  }
+
+  void VisitNotEqual(HNotEqual* cond) OVERRIDE {
+    BinaryFP(cond);
+  }
+
+  void VisitLessThan(HLessThan* cond) OVERRIDE {
+    BinaryFP(cond);
+  }
+
+  void VisitLessThanOrEqual(HLessThanOrEqual* cond) OVERRIDE {
+    BinaryFP(cond);
+  }
+
+  void VisitGreaterThan(HGreaterThan* cond) OVERRIDE {
+    BinaryFP(cond);
+  }
+
+  void VisitGreaterThanOrEqual(HGreaterThanOrEqual* cond) OVERRIDE {
+    BinaryFP(cond);
+  }
+
+  void VisitNeg(HNeg* neg) OVERRIDE {
+    if (Primitive::IsFloatingPointType(neg->GetType())) {
+      // We need to replace the HNeg with a HX86FPNeg in order to address the constant area.
+      InitializePCRelativeBasePointer();
+      HGraph* graph = GetGraph();
+      HBasicBlock* block = neg->GetBlock();
+      HX86FPNeg* x86_fp_neg = new (graph->GetArena()) HX86FPNeg(
+          neg->GetType(),
+          neg->InputAt(0),
+          base_,
+          neg->GetDexPc());
+      block->ReplaceAndRemoveInstructionWith(neg, x86_fp_neg);
+    }
+  }
+
   void VisitPackedSwitch(HPackedSwitch* switch_insn) OVERRIDE {
     if (switch_insn->GetNumEntries() <=
         InstructionCodeGeneratorX86::kPackedSwitchJumpTableThreshold) {
@@ -127,12 +170,23 @@
     // If this is an invoke-static/-direct with PC-relative dex cache array
     // addressing, we need the PC-relative address base.
     HInvokeStaticOrDirect* invoke_static_or_direct = invoke->AsInvokeStaticOrDirect();
+    // We can't add a pointer to the constant area if we already have a current
+    // method pointer. This may arise when sharpening doesn't remove the current
+    // method pointer from the invoke.
+    if (invoke_static_or_direct != nullptr &&
+        invoke_static_or_direct->HasCurrentMethodInput()) {
+      DCHECK(!invoke_static_or_direct->HasPcRelativeDexCache());
+      return;
+    }
+
+    bool base_added = false;
     if (invoke_static_or_direct != nullptr && invoke_static_or_direct->HasPcRelativeDexCache()) {
       InitializePCRelativeBasePointer();
       // Add the extra parameter base_.
-      DCHECK(!invoke_static_or_direct->HasCurrentMethodInput());
       invoke_static_or_direct->AddSpecialInput(base_);
+      base_added = true;
     }
+
     // Ensure that we can load FP arguments from the constant area.
     for (size_t i = 0, e = invoke->InputCount(); i < e; i++) {
       HConstant* input = invoke->InputAt(i)->AsConstant();
@@ -140,6 +194,25 @@
         ReplaceInput(invoke, input, i, true);
       }
     }
+
+    // These intrinsics need the constant area.
+    switch (invoke->GetIntrinsic()) {
+      case Intrinsics::kMathAbsDouble:
+      case Intrinsics::kMathAbsFloat:
+      case Intrinsics::kMathMaxDoubleDouble:
+      case Intrinsics::kMathMaxFloatFloat:
+      case Intrinsics::kMathMinDoubleDouble:
+      case Intrinsics::kMathMinFloatFloat:
+        if (!base_added) {
+          DCHECK(invoke_static_or_direct != nullptr);
+          DCHECK(!invoke_static_or_direct->HasCurrentMethodInput());
+          InitializePCRelativeBasePointer();
+          invoke_static_or_direct->AddSpecialInput(base_);
+        }
+        break;
+      default:
+        break;
+    }
   }
 
   // The generated HX86ComputeBaseMethodAddress in the entry block needed as an
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index c56100d..2de0c1b 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -30,17 +30,15 @@
 static void TestCode(const uint16_t* data, const char* expected) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateGraph(&allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  bool graph_built = builder.BuildGraph(*item);
-  ASSERT_TRUE(graph_built);
+  HGraph* graph = CreateCFG(&allocator, data);
   StringPrettyPrinter printer(graph);
   printer.VisitInsertionOrder();
   ASSERT_STREQ(expected, printer.str().c_str());
 }
 
-TEST(PrettyPrinterTest, ReturnVoid) {
+class PrettyPrinterTest : public CommonCompilerTest {};
+
+TEST_F(PrettyPrinterTest, ReturnVoid) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
       Instruction::RETURN_VOID);
 
@@ -56,7 +54,7 @@
   TestCode(data, expected);
 }
 
-TEST(PrettyPrinterTest, CFG1) {
+TEST_F(PrettyPrinterTest, CFG1) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
     "  3: SuspendCheck\n"
@@ -76,7 +74,7 @@
   TestCode(data, expected);
 }
 
-TEST(PrettyPrinterTest, CFG2) {
+TEST_F(PrettyPrinterTest, CFG2) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
     "  4: SuspendCheck\n"
@@ -98,7 +96,7 @@
   TestCode(data, expected);
 }
 
-TEST(PrettyPrinterTest, CFG3) {
+TEST_F(PrettyPrinterTest, CFG3) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
     "  4: SuspendCheck\n"
@@ -134,16 +132,16 @@
   TestCode(data3, expected);
 }
 
-TEST(PrettyPrinterTest, CFG4) {
+TEST_F(PrettyPrinterTest, CFG4) {
   const char* expected =
-    "BasicBlock 0, succ: 1\n"
+    "BasicBlock 0, succ: 3\n"
     "  3: SuspendCheck\n"
-    "  4: Goto 1\n"
-    "BasicBlock 1, pred: 0, 1, succ: 1\n"
+    "  4: Goto 3\n"
+    "BasicBlock 1, pred: 3, 1, succ: 1\n"
     "  0: SuspendCheck\n"
     "  1: Goto 1\n"
-    "BasicBlock 2\n"
-    "  2: Exit\n";
+    "BasicBlock 3, pred: 0, succ: 1\n"
+    "  5: Goto 1\n";
 
   const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::NOP,
@@ -157,15 +155,13 @@
   TestCode(data2, expected);
 }
 
-TEST(PrettyPrinterTest, CFG5) {
+TEST_F(PrettyPrinterTest, CFG5) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
     "  3: SuspendCheck\n"
     "  4: Goto 1\n"
-    "BasicBlock 1, pred: 0, 2, succ: 3\n"
+    "BasicBlock 1, pred: 0, succ: 3\n"
     "  0: ReturnVoid\n"
-    "BasicBlock 2, succ: 1\n"
-    "  1: Goto 1\n"
     "BasicBlock 3, pred: 1\n"
     "  2: Exit\n";
 
@@ -177,25 +173,23 @@
   TestCode(data, expected);
 }
 
-TEST(PrettyPrinterTest, CFG6) {
+TEST_F(PrettyPrinterTest, CFG6) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  0: Local [4, 3, 2]\n"
-    "  1: IntConstant [2]\n"
+    "  1: IntConstant [5, 5]\n"
     "  10: SuspendCheck\n"
     "  11: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 3, 2\n"
-    "  2: StoreLocal(0, 1)\n"
-    "  3: LoadLocal(0) [5]\n"
-    "  4: LoadLocal(0) [5]\n"
-    "  5: Equal(3, 4) [6]\n"
+    "BasicBlock 1, pred: 0, succ: 5, 2\n"
+    "  5: Equal(1, 1) [6]\n"
     "  6: If(5)\n"
     "BasicBlock 2, pred: 1, succ: 3\n"
     "  7: Goto 3\n"
-    "BasicBlock 3, pred: 1, 2, succ: 4\n"
+    "BasicBlock 3, pred: 5, 2, succ: 4\n"
     "  8: ReturnVoid\n"
     "BasicBlock 4, pred: 3\n"
-    "  9: Exit\n";
+    "  9: Exit\n"
+    "BasicBlock 5, pred: 1, succ: 3\n"
+    "  12: Goto 3\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -206,26 +200,24 @@
   TestCode(data, expected);
 }
 
-TEST(PrettyPrinterTest, CFG7) {
+TEST_F(PrettyPrinterTest, CFG7) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  0: Local [4, 3, 2]\n"
-    "  1: IntConstant [2]\n"
+    "  1: IntConstant [5, 5]\n"
     "  11: SuspendCheck\n"
     "  12: Goto 1\n"
-    "BasicBlock 1, pred: 0, succ: 3, 2\n"
-    "  2: StoreLocal(0, 1)\n"
-    "  3: LoadLocal(0) [5]\n"
-    "  4: LoadLocal(0) [5]\n"
-    "  5: Equal(3, 4) [6]\n"
+    "BasicBlock 1, pred: 0, succ: 5, 6\n"
+    "  5: Equal(1, 1) [6]\n"
     "  6: If(5)\n"
-    "BasicBlock 2, pred: 1, 3, succ: 3\n"
+    "BasicBlock 2, pred: 6, 3, succ: 3\n"
     "  7: Goto 3\n"
-    "BasicBlock 3, pred: 1, 2, succ: 2\n"
+    "BasicBlock 3, pred: 5, 2, succ: 2\n"
     "  8: SuspendCheck\n"
     "  9: Goto 2\n"
-    "BasicBlock 4\n"
-    "  10: Exit\n";
+    "BasicBlock 5, pred: 1, succ: 3\n"
+    "  13: Goto 3\n"
+    "BasicBlock 6, pred: 1, succ: 2\n"
+    "  14: Goto 2\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -236,15 +228,13 @@
   TestCode(data, expected);
 }
 
-TEST(PrettyPrinterTest, IntConstant) {
+TEST_F(PrettyPrinterTest, IntConstant) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  0: Local [2]\n"
-    "  1: IntConstant [2]\n"
+    "  1: IntConstant\n"
     "  5: SuspendCheck\n"
     "  6: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 2\n"
-    "  2: StoreLocal(0, 1)\n"
     "  3: ReturnVoid\n"
     "BasicBlock 2, pred: 1\n"
     "  4: Exit\n";
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 1224a48..deaa415 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -55,10 +55,12 @@
  public:
   RTPVisitor(HGraph* graph,
              HandleCache* handle_cache,
-             ArenaVector<HInstruction*>* worklist)
+             ArenaVector<HInstruction*>* worklist,
+             bool is_first_run)
     : HGraphDelegateVisitor(graph),
       handle_cache_(handle_cache),
-      worklist_(worklist) {}
+      worklist_(worklist),
+      is_first_run_(is_first_run) {}
 
   void VisitNewInstance(HNewInstance* new_instance) OVERRIDE;
   void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
@@ -86,14 +88,17 @@
  private:
   HandleCache* handle_cache_;
   ArenaVector<HInstruction*>* worklist_;
+  const bool is_first_run_;
 };
 
 ReferenceTypePropagation::ReferenceTypePropagation(HGraph* graph,
                                                    StackHandleScopeCollection* handles,
+                                                   bool is_first_run,
                                                    const char* name)
     : HOptimization(graph, name),
       handle_cache_(handles),
-      worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)) {
+      worklist_(graph->GetArena()->Adapter(kArenaAllocReferenceTypePropagation)),
+      is_first_run_(is_first_run) {
 }
 
 void ReferenceTypePropagation::ValidateTypes() {
@@ -125,7 +130,7 @@
 }
 
 void ReferenceTypePropagation::Visit(HInstruction* instruction) {
-  RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
+  RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
   instruction->Accept(&visitor);
 }
 
@@ -144,7 +149,7 @@
 }
 
 void ReferenceTypePropagation::VisitBasicBlock(HBasicBlock* block) {
-  RTPVisitor visitor(graph_, &handle_cache_, &worklist_);
+  RTPVisitor visitor(graph_, &handle_cache_, &worklist_, is_first_run_);
   // Handle Phis first as there might be instructions in the same block who depend on them.
   for (HInstructionIterator it(block->GetPhis()); !it.Done(); it.Advance()) {
     VisitPhi(it.Current()->AsPhi());
@@ -620,6 +625,7 @@
   DCHECK_EQ(bound_type->InputAt(0), check_cast->InputAt(0));
 
   if (class_rti.IsValid()) {
+    DCHECK(is_first_run_);
     // This is the first run of RTP and class is resolved.
     bound_type->SetUpperBound(class_rti, /* CheckCast succeeds for nulls. */ true);
   } else {
@@ -636,6 +642,12 @@
   }
 
   if (phi->GetBlock()->IsLoopHeader()) {
+    if (!is_first_run_ && graph_->IsCompilingOsr()) {
+      // Don't update the type of a loop phi when compiling OSR: we may have done
+      // speculative optimizations dominating that phi, that do not hold at the
+      // point the interpreter jumps to that loop header.
+      return;
+    }
     ScopedObjectAccess soa(Thread::Current());
     // Set the initial type for the phi. Use the non back edge input for reaching
     // a fixed point faster.
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index a7f10a6..028a6fc 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -33,6 +33,7 @@
  public:
   ReferenceTypePropagation(HGraph* graph,
                            StackHandleScopeCollection* handles,
+                           bool is_first_run,
                            const char* name = kReferenceTypePropagationPassName);
 
   // Visit a single instruction.
@@ -93,6 +94,8 @@
 
   ArenaVector<HInstruction*> worklist_;
 
+  // Whether this reference type propagation is the first run we are doing.
+  const bool is_first_run_;
 
   static constexpr size_t kDefaultWorklistSize = 8;
 
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index 5cd30ad..b8d76b9 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -994,10 +994,6 @@
     return false;
   }
 
-  // We use the first use to compare with other intervals. If this interval
-  // is used after any active intervals, we will spill this interval.
-  size_t first_use = current->FirstUseAfter(current->GetStart());
-
   // First set all registers as not being used.
   size_t* next_use = registers_array_;
   for (size_t i = 0; i < number_of_registers_; ++i) {
@@ -1011,7 +1007,7 @@
     if (active->IsFixed()) {
       next_use[active->GetRegister()] = current->GetStart();
     } else {
-      size_t use = active->FirstUseAfter(current->GetStart());
+      size_t use = active->FirstRegisterUseAfter(current->GetStart());
       if (use != kNoLifetime) {
         next_use[active->GetRegister()] = use;
       }
@@ -1052,16 +1048,16 @@
     DCHECK(current->IsHighInterval());
     reg = current->GetRegister();
     // When allocating the low part, we made sure the high register was available.
-    DCHECK_LT(first_use, next_use[reg]);
+    DCHECK_LT(first_register_use, next_use[reg]);
   } else if (current->IsLowInterval()) {
-    reg = FindAvailableRegisterPair(next_use, first_use);
+    reg = FindAvailableRegisterPair(next_use, first_register_use);
     // We should spill if both registers are not available.
-    should_spill = (first_use >= next_use[reg])
-      || (first_use >= next_use[GetHighForLowRegister(reg)]);
+    should_spill = (first_register_use >= next_use[reg])
+      || (first_register_use >= next_use[GetHighForLowRegister(reg)]);
   } else {
     DCHECK(!current->IsHighInterval());
     reg = FindAvailableRegister(next_use, current);
-    should_spill = (first_use >= next_use[reg]);
+    should_spill = (first_register_use >= next_use[reg]);
   }
 
   DCHECK_NE(reg, kNoRegister);
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index 572faa8..a9de7c3 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -38,11 +38,7 @@
 static bool Check(const uint16_t* data) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateGraph(&allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  builder.BuildGraph(*item);
-  TransformToSsa(graph);
+  HGraph* graph = CreateCFG(&allocator, data);
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
       X86InstructionSetFeatures::FromCppDefines());
   x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
@@ -254,15 +250,6 @@
   ASSERT_TRUE(Check(data));
 }
 
-static HGraph* BuildSSAGraph(const uint16_t* data, ArenaAllocator* allocator) {
-  HGraph* graph = CreateGraph(allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  builder.BuildGraph(*item);
-  TransformToSsa(graph);
-  return graph;
-}
-
 TEST_F(RegisterAllocatorTest, Loop3) {
   /*
    * Test the following snippet:
@@ -302,7 +289,7 @@
 
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = BuildSSAGraph(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
       X86InstructionSetFeatures::FromCppDefines());
   x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
@@ -336,7 +323,7 @@
 
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = BuildSSAGraph(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
       X86InstructionSetFeatures::FromCppDefines());
   x86::CodeGeneratorX86 codegen(graph, *features_x86.get(), CompilerOptions());
@@ -390,7 +377,7 @@
 
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = BuildSSAGraph(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   SsaDeadPhiElimination(graph).Run();
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
       X86InstructionSetFeatures::FromCppDefines());
@@ -414,7 +401,7 @@
 
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = BuildSSAGraph(data, &allocator);
+  HGraph* graph = CreateCFG(&allocator, data);
   SsaDeadPhiElimination(graph).Run();
   std::unique_ptr<const X86InstructionSetFeatures> features_x86(
       X86InstructionSetFeatures::FromCppDefines());
diff --git a/compiler/optimizing/ssa_builder.cc b/compiler/optimizing/ssa_builder.cc
index 165d09d..43f2499 100644
--- a/compiler/optimizing/ssa_builder.cc
+++ b/compiler/optimizing/ssa_builder.cc
@@ -430,8 +430,6 @@
   }
 
   for (HNewInstance* new_instance : uninitialized_strings_) {
-    DCHECK(new_instance->IsStringAlloc());
-
     // Replace NewInstance of String with NullConstant if not used prior to
     // calling StringFactory. In case of deoptimization, the interpreter is
     // expected to skip null check on the `this` argument of the StringFactory call.
@@ -440,10 +438,26 @@
       new_instance->GetBlock()->RemoveInstruction(new_instance);
 
       // Remove LoadClass if not needed any more.
-      HLoadClass* load_class = new_instance->InputAt(0)->AsLoadClass();
+      HInstruction* input = new_instance->InputAt(0);
+      HLoadClass* load_class = nullptr;
+
+      // If the class was not present in the dex cache at the point of building
+      // the graph, the builder inserted a HClinitCheck in between. Since the String
+      // class is always initialized at the point of running Java code, we can remove
+      // that check.
+      if (input->IsClinitCheck()) {
+        load_class = input->InputAt(0)->AsLoadClass();
+        input->ReplaceWith(load_class);
+        input->GetBlock()->RemoveInstruction(input);
+      } else {
+        load_class = input->AsLoadClass();
+        DCHECK(new_instance->IsStringAlloc());
+        DCHECK(!load_class->NeedsAccessCheck()) << "String class is always accessible";
+      }
       DCHECK(load_class != nullptr);
-      DCHECK(!load_class->NeedsAccessCheck()) << "String class is always accessible";
       if (!load_class->HasUses()) {
+        // Even if the HLoadClass needs access check, we can remove it, as we know the
+        // String class does not need it.
         load_class->GetBlock()->RemoveInstruction(load_class);
       }
     }
@@ -451,6 +465,8 @@
 }
 
 GraphAnalysisResult SsaBuilder::BuildSsa() {
+  DCHECK(!GetGraph()->IsInSsaForm());
+
   // 1) Visit in reverse post order. We need to have all predecessors of a block
   // visited (with the exception of loops) in order to create the right environment
   // for that block. For loops, we create phis whose inputs will be set in 2).
@@ -483,7 +499,7 @@
 
   // 6) Compute type of reference type instructions. The pass assumes that
   // NullConstant has been fixed up.
-  ReferenceTypePropagation(GetGraph(), handles_).Run();
+  ReferenceTypePropagation(GetGraph(), handles_, /* is_first_run */ true).Run();
 
   // 7) Step 1) duplicated ArrayGet instructions with ambiguous type (int/float
   // or long/double) and marked ArraySets with ambiguous input type. Now that RTP
@@ -533,6 +549,7 @@
     }
   }
 
+  GetGraph()->SetInSsaForm();
   return kAnalysisSuccess;
 }
 
@@ -899,11 +916,6 @@
   }
 }
 
-void SsaBuilder::VisitTemporary(HTemporary* temp) {
-  // Temporaries are only used by the baseline register allocator.
-  temp->GetBlock()->RemoveInstruction(temp);
-}
-
 void SsaBuilder::VisitArrayGet(HArrayGet* aget) {
   Primitive::Type type = aget->GetType();
   DCHECK(!Primitive::IsFloatingPointType(type));
diff --git a/compiler/optimizing/ssa_builder.h b/compiler/optimizing/ssa_builder.h
index ccef8ea..2dae9c2 100644
--- a/compiler/optimizing/ssa_builder.h
+++ b/compiler/optimizing/ssa_builder.h
@@ -75,13 +75,10 @@
   void VisitLoadLocal(HLoadLocal* load) OVERRIDE;
   void VisitStoreLocal(HStoreLocal* store) OVERRIDE;
   void VisitInstruction(HInstruction* instruction) OVERRIDE;
-  void VisitTemporary(HTemporary* instruction) OVERRIDE;
   void VisitArrayGet(HArrayGet* aget) OVERRIDE;
   void VisitArraySet(HArraySet* aset) OVERRIDE;
   void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE;
 
-  static constexpr const char* kSsaBuilderPassName = "ssa_builder";
-
  private:
   void SetLoopHeaderPhiInputs();
   void FixEnvironmentPhis();
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index 1dd3508..83e9dac 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -226,7 +226,7 @@
         // The only instructions which may not be recorded in the environments
         // are constants created by the SSA builder as typed equivalents of
         // untyped constants from the bytecode, or phis with only such constants
-        // as inputs (verified by SSAChecker). Their raw binary value must
+        // as inputs (verified by GraphChecker). Their raw binary value must
         // therefore be the same and we only need to keep alive one.
       } else {
         size_t phi_input_index = successor->GetPredecessorIndexOf(block);
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index d2885a8..a688092 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -79,13 +79,7 @@
 static void TestCode(const uint16_t* data, const char* expected) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateGraph(&allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  bool graph_built = builder.BuildGraph(*item);
-  ASSERT_TRUE(graph_built);
-
-  TransformToSsa(graph);
+  HGraph* graph = CreateCFG(&allocator, data);
   // Suspend checks implementation may change in the future, and this test relies
   // on how instructions are ordered.
   RemoveSuspendChecks(graph);
diff --git a/compiler/optimizing/suspend_check_test.cc b/compiler/optimizing/suspend_check_test.cc
index b6c704c..15cd4e8 100644
--- a/compiler/optimizing/suspend_check_test.cc
+++ b/compiler/optimizing/suspend_check_test.cc
@@ -18,6 +18,7 @@
 #include "dex_instruction.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
+#include "pretty_printer.h"
 
 #include "gtest/gtest.h"
 
@@ -30,20 +31,17 @@
 static void TestCode(const uint16_t* data) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
-  HGraph* graph = CreateGraph(&allocator);
-  HGraphBuilder builder(graph);
-  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
-  bool graph_built = builder.BuildGraph(*item);
-  ASSERT_TRUE(graph_built);
-
-  HBasicBlock* first_block = graph->GetEntryBlock()->GetSuccessors()[0];
-  HInstruction* first_instruction = first_block->GetFirstInstruction();
-  // Account for some tests having a store local as first instruction.
-  ASSERT_TRUE(first_instruction->IsSuspendCheck()
-              || first_instruction->GetNext()->IsSuspendCheck());
+  HGraph* graph = CreateCFG(&allocator, data);
+  HBasicBlock* first_block = graph->GetEntryBlock()->GetSingleSuccessor();
+  HBasicBlock* loop_header = first_block->GetSingleSuccessor();
+  ASSERT_TRUE(loop_header->IsLoopHeader());
+  ASSERT_EQ(loop_header->GetLoopInformation()->GetPreHeader(), first_block);
+  ASSERT_TRUE(loop_header->GetFirstInstruction()->IsSuspendCheck());
 }
 
-TEST(CodegenTest, CFG1) {
+class SuspendCheckTest : public CommonCompilerTest {};
+
+TEST_F(SuspendCheckTest, CFG1) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::NOP,
     Instruction::GOTO | 0xFF00);
@@ -51,14 +49,14 @@
   TestCode(data);
 }
 
-TEST(CodegenTest, CFG2) {
+TEST_F(SuspendCheckTest, CFG2) {
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO_32, 0, 0);
 
   TestCode(data);
 }
 
-TEST(CodegenTest, CFG3) {
+TEST_F(SuspendCheckTest, CFG3) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQ, 0xFFFF,
@@ -67,7 +65,7 @@
   TestCode(data);
 }
 
-TEST(CodegenTest, CFG4) {
+TEST_F(SuspendCheckTest, CFG4) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_NE, 0xFFFF,
@@ -76,7 +74,7 @@
   TestCode(data);
 }
 
-TEST(CodegenTest, CFG5) {
+TEST_F(SuspendCheckTest, CFG5) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_EQZ, 0xFFFF,
@@ -85,7 +83,7 @@
   TestCode(data);
 }
 
-TEST(CodegenTest, CFG6) {
+TEST_F(SuspendCheckTest, CFG6) {
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
     Instruction::IF_NEZ, 0xFFFF,
diff --git a/compiler/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h
index 5fde9e8..5b84058 100644
--- a/compiler/utils/arm/managed_register_arm.h
+++ b/compiler/utils/arm/managed_register_arm.h
@@ -19,7 +19,7 @@
 
 #include "base/logging.h"
 #include "constants_arm.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
 #include "utils/managed_register.h"
 
 namespace art {
diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h
index dbcd8c5..46be1c5 100644
--- a/compiler/utils/arm64/managed_register_arm64.h
+++ b/compiler/utils/arm64/managed_register_arm64.h
@@ -19,7 +19,7 @@
 
 #include "base/logging.h"
 #include "constants_arm64.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
 #include "utils/managed_register.h"
 
 namespace art {
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index 1dbc142..414ea7e 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -21,9 +21,10 @@
 
 #include "arch/instruction_set.h"
 #include "arch/instruction_set_features.h"
+#include "arm/constants_arm.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "arm/constants_arm.h"
+#include "debug/dwarf/debug_frame_opcode_writer.h"
 #include "label.h"
 #include "managed_register.h"
 #include "memory_region.h"
@@ -31,7 +32,6 @@
 #include "offsets.h"
 #include "x86/constants_x86.h"
 #include "x86_64/constants_x86_64.h"
-#include "dwarf/debug_frame_opcode_writer.h"
 
 namespace art {
 
diff --git a/compiler/utils/mips/managed_register_mips.h b/compiler/utils/mips/managed_register_mips.h
index 40d39e3..5e7ed11 100644
--- a/compiler/utils/mips/managed_register_mips.h
+++ b/compiler/utils/mips/managed_register_mips.h
@@ -18,7 +18,7 @@
 #define ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_
 
 #include "constants_mips.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
 #include "utils/managed_register.h"
 
 namespace art {
diff --git a/compiler/utils/mips64/managed_register_mips64.h b/compiler/utils/mips64/managed_register_mips64.h
index 4c4705b..1d36128 100644
--- a/compiler/utils/mips64/managed_register_mips64.h
+++ b/compiler/utils/mips64/managed_register_mips64.h
@@ -18,7 +18,7 @@
 #define ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_
 
 #include "constants_mips64.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
 #include "utils/managed_register.h"
 
 namespace art {
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index 7138a46..3efef70 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -326,6 +326,14 @@
 }
 
 
+void X86Assembler::cmovl(Condition condition, Register dst, const Address& src) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0x0F);
+  EmitUint8(0x40 + condition);
+  EmitOperand(dst, src);
+}
+
+
 void X86Assembler::setb(Condition condition, Register dst) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x0F);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 759a41e..00ff7bd 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -363,6 +363,7 @@
   void leal(Register dst, const Address& src);
 
   void cmovl(Condition condition, Register dst, Register src);
+  void cmovl(Condition condition, Register dst, const Address& src);
 
   void setb(Condition condition, Register dst);
 
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 0fd0982..d0d5147 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -332,6 +332,21 @@
 }
 
 
+TEST_F(AssemblerX86Test, CmovlAddress) {
+  GetAssembler()->cmovl(x86::kEqual, x86::Register(x86::EAX), x86::Address(
+      x86::Register(x86::EDI), x86::Register(x86::EBX), x86::TIMES_4, 12));
+  GetAssembler()->cmovl(x86::kNotEqual, x86::Register(x86::EDI), x86::Address(
+      x86::Register(x86::ESI), x86::Register(x86::EBX), x86::TIMES_4, 12));
+  GetAssembler()->cmovl(x86::kEqual, x86::Register(x86::EDI), x86::Address(
+      x86::Register(x86::EDI), x86::Register(x86::EAX), x86::TIMES_4, 12));
+  const char* expected =
+    "cmovzl 0xc(%EDI,%EBX,4), %eax\n"
+    "cmovnzl 0xc(%ESI,%EBX,4), %edi\n"
+    "cmovzl 0xc(%EDI,%EAX,4), %edi\n";
+
+  DriverStr(expected, "cmovl_address");
+}
+
 /////////////////
 // Near labels //
 /////////////////
diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h
index 4e8c41e..fc20d7e 100644
--- a/compiler/utils/x86/managed_register_x86.h
+++ b/compiler/utils/x86/managed_register_x86.h
@@ -18,7 +18,7 @@
 #define ART_COMPILER_UTILS_X86_MANAGED_REGISTER_X86_H_
 
 #include "constants_x86.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
 #include "utils/managed_register.h"
 
 namespace art {
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 10f5a00..d86ad1b 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -223,6 +223,19 @@
 }
 
 
+void X86_64Assembler::cmov(Condition c, CpuRegister dst, const Address& src, bool is64bit) {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  if (is64bit) {
+    EmitRex64(dst, src);
+  } else {
+    EmitOptionalRex32(dst, src);
+  }
+  EmitUint8(0x0F);
+  EmitUint8(0x40 + c);
+  EmitOperand(dst.LowBits(), src);
+}
+
+
 void X86_64Assembler::movzxb(CpuRegister dst, CpuRegister src) {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitOptionalByteRegNormalizingRex32(dst, src);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 6f0847e..f00cb12 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -366,6 +366,7 @@
 
   void cmov(Condition c, CpuRegister dst, CpuRegister src);  // This is the 64b version.
   void cmov(Condition c, CpuRegister dst, CpuRegister src, bool is64bit);
+  void cmov(Condition c, CpuRegister dst, const Address& src, bool is64bit);
 
   void movzxb(CpuRegister dst, CpuRegister src);
   void movzxb(CpuRegister dst, const Address& src);
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 8a87fca..4f65709 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -1371,6 +1371,37 @@
   DriverStr(expected, "popcntq_address");
 }
 
+TEST_F(AssemblerX86_64Test, CmovlAddress) {
+  GetAssembler()->cmov(x86_64::kEqual, x86_64::CpuRegister(x86_64::R10), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), false);
+  GetAssembler()->cmov(x86_64::kNotEqual, x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), false);
+  GetAssembler()->cmov(x86_64::kEqual, x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), false);
+  const char* expected =
+    "cmovzl 0xc(%RDI,%RBX,4), %R10d\n"
+    "cmovnzl 0xc(%R10,%RBX,4), %edi\n"
+    "cmovzl 0xc(%RDI,%R9,4), %edi\n";
+
+  DriverStr(expected, "cmovl_address");
+}
+
+TEST_F(AssemblerX86_64Test, CmovqAddress) {
+  GetAssembler()->cmov(x86_64::kEqual, x86_64::CpuRegister(x86_64::R10), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), true);
+  GetAssembler()->cmov(x86_64::kNotEqual, x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R10), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12), true);
+  GetAssembler()->cmov(x86_64::kEqual, x86_64::CpuRegister(x86_64::RDI), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12), true);
+  const char* expected =
+    "cmovzq 0xc(%RDI,%RBX,4), %R10\n"
+    "cmovnzq 0xc(%R10,%RBX,4), %rdi\n"
+    "cmovzq 0xc(%RDI,%R9,4), %rdi\n";
+
+  DriverStr(expected, "cmovq_address");
+}
+
+
 /////////////////
 // Near labels //
 /////////////////
diff --git a/compiler/utils/x86_64/managed_register_x86_64.h b/compiler/utils/x86_64/managed_register_x86_64.h
index 47bbb44..c4228c1 100644
--- a/compiler/utils/x86_64/managed_register_x86_64.h
+++ b/compiler/utils/x86_64/managed_register_x86_64.h
@@ -18,7 +18,7 @@
 #define ART_COMPILER_UTILS_X86_64_MANAGED_REGISTER_X86_64_H_
 
 #include "constants_x86_64.h"
-#include "dwarf/register.h"
+#include "debug/dwarf/register.h"
 #include "utils/managed_register.h"
 
 namespace art {
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index b3e3ba6..541fb5a 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -35,9 +35,9 @@
 #define ATRACE_TAG ATRACE_TAG_DALVIK
 #include <cutils/trace.h>
 
-#include "art_method-inl.h"
 #include "arch/instruction_set_features.h"
 #include "arch/mips/instruction_set_features_mips.h"
+#include "art_method-inl.h"
 #include "base/dumpable.h"
 #include "base/macros.h"
 #include "base/stl_util.h"
@@ -48,14 +48,14 @@
 #include "class_linker.h"
 #include "compiler.h"
 #include "compiler_callbacks.h"
-#include "dex_file-inl.h"
+#include "debug/method_debug_info.h"
 #include "dex/pass_manager.h"
-#include "dex/verification_results.h"
-#include "dex/quick_compiler_callbacks.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
+#include "dex/quick_compiler_callbacks.h"
+#include "dex/verification_results.h"
+#include "dex_file-inl.h"
 #include "driver/compiler_driver.h"
 #include "driver/compiler_options.h"
-#include "dwarf/method_debug_info.h"
 #include "elf_file.h"
 #include "elf_writer.h"
 #include "elf_writer_quick.h"
@@ -126,6 +126,11 @@
       continue;
     }
 
+    // The image format is dropped.
+    if (StartsWith(original_argv[i], "--image-format=")) {
+      continue;
+    }
+
     // This should leave any dex-file and oat-file options, describing what we compiled.
 
     // However, we prefer to drop this when we saw --zip-fd.
@@ -1682,6 +1687,12 @@
         std::vector<const DexFile*>& dex_files = dex_files_per_oat_file_[i];
         oat_writer->PrepareLayout(driver_.get(), image_writer_.get(), dex_files);
 
+        // We need to mirror the layout of the ELF file in the compressed debug-info.
+        // Therefore we need to propagate the sizes of at least those sections.
+        size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
+        size_t text_size = oat_writer->GetSize() - rodata_size;
+        elf_writer->PrepareDebugInfo(rodata_size, text_size, oat_writer->GetMethodDebugInfo());
+
         OutputStream*& rodata = rodata_[i];
         DCHECK(rodata != nullptr);
         if (!oat_writer->WriteRodata(rodata)) {
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 5e2cf6b..0e709eb 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -1152,8 +1152,10 @@
             args << Rd << ", #" << imm16;
             break;
           }
-          case 0x16: {
+          case 0x16: case 0x14: case 0x1C: {
             // BFI Rd, Rn, #lsb, #width - 111 10 0 11 011 0 nnnn 0 iii dddd ii 0 iiiii
+            // SBFX Rd, Rn, #lsb, #width - 111 10 0 11 010 0 nnnn 0 iii dddd ii 0 iiiii
+            // UBFX Rd, Rn, #lsb, #width - 111 10 0 11 110 0 nnnn 0 iii dddd ii 0 iiiii
             ArmRegister Rd(instr, 8);
             ArmRegister Rn(instr, 16);
             uint32_t msb = instr & 0x1F;
@@ -1161,12 +1163,21 @@
             uint32_t imm3 = (instr >> 12) & 0x7;
             uint32_t lsb = (imm3 << 2) | imm2;
             uint32_t width = msb - lsb + 1;
-            if (Rn.r != 0xF) {
-              opcode << "bfi";
-              args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
+            if (op3 == 0x16) {
+              if (Rn.r != 0xF) {
+                opcode << "bfi";
+                args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
+              } else {
+                opcode << "bfc";
+                args << Rd << ", #" << lsb << ", #" << width;
+              }
             } else {
-              opcode << "bfc";
-              args << Rd << ", #" << lsb << ", #" << width;
+              opcode << ((op3 & 0x8) != 0u ? "ubfx" : "sbfx");
+              args << Rd << ", " << Rn << ", #" << lsb << ", #" << width;
+              if (Rd.r == 13 || Rd.r == 15 || Rn.r == 13 || Rn.r == 15 ||
+                  (instr & 0x04000020) != 0u) {
+                args << " (UNPREDICTABLE)";
+              }
             }
             break;
           }
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 1668dc5..1d80bda 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -150,30 +150,17 @@
   }
 }
 
-bool PatchOat::Patch(File* input_oat, const std::string& image_location, off_t delta,
-                     File* output_oat, File* output_image, InstructionSet isa,
-                     TimingLogger* timings,
-                     bool output_oat_opened_from_fd ATTRIBUTE_UNUSED,
-                     bool new_oat_out) {
+bool PatchOat::Patch(const std::string& image_location,
+                     off_t delta,
+                     const std::string& output_directory,
+                     InstructionSet isa,
+                     TimingLogger* timings) {
   CHECK(Runtime::Current() == nullptr);
-  CHECK(output_image != nullptr);
-  CHECK_GE(output_image->Fd(), 0);
-  CHECK(input_oat != nullptr);
-  CHECK(output_oat != nullptr);
-  CHECK_GE(input_oat->Fd(), 0);
-  CHECK_GE(output_oat->Fd(), 0);
   CHECK(!image_location.empty()) << "image file must have a filename.";
 
   TimingLogger::ScopedTiming t("Runtime Setup", timings);
 
-  if (isa == kNone) {
-    Elf32_Ehdr elf_hdr;
-    if (sizeof(elf_hdr) != input_oat->Read(reinterpret_cast<char*>(&elf_hdr), sizeof(elf_hdr), 0)) {
-      LOG(ERROR) << "unable to read elf header";
-      return false;
-    }
-    isa = GetInstructionSetFromELF(elf_hdr.e_machine, elf_hdr.e_flags);
-  }
+  CHECK_NE(isa, kNone);
   const char* isa_name = GetInstructionSetString(isa);
 
   // Set up the runtime
@@ -193,8 +180,6 @@
   Thread::Current()->TransitionFromRunnableToSuspended(kNative);
   ScopedObjectAccess soa(Thread::Current());
 
-  std::string output_directory =
-      output_image->GetPath().substr(0, output_image->GetPath().find_last_of("/"));
   t.NewTiming("Image and oat Patching setup");
   std::vector<gc::space::ImageSpace*> spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
   std::map<gc::space::ImageSpace*, std::unique_ptr<File>> space_to_file_map;
@@ -325,6 +310,7 @@
     std::string output_image_filename = output_directory +
                                         (StartsWith(converted_image_filename, "/") ? "" : "/") +
                                         converted_image_filename;
+    bool new_oat_out;
     std::unique_ptr<File>
         output_image_file(CreateOrOpen(output_image_filename.c_str(), &new_oat_out));
     if (output_image_file.get() == nullptr) {
@@ -932,21 +918,9 @@
   UsageError("  --output-image-file=<file.art>: Specifies the exact file to write the patched");
   UsageError("      image file to.");
   UsageError("");
-  UsageError("  --output-image-fd=<file-descriptor>: Specifies the file-descriptor to write the");
-  UsageError("      the patched image file to.");
-  UsageError("");
-  UsageError("  --orig-base-offset=<original-base-offset>: Specify the base offset the input file");
-  UsageError("      was compiled with. This is needed if one is specifying a --base-offset");
-  UsageError("");
-  UsageError("  --base-offset=<new-base-offset>: Specify the base offset we will repatch the");
-  UsageError("      given files to use. This requires that --orig-base-offset is also given.");
-  UsageError("");
   UsageError("  --base-offset-delta=<delta>: Specify the amount to change the old base-offset by.");
   UsageError("      This value may be negative.");
   UsageError("");
-  UsageError("  --patched-image-file=<file.art>: Relocate the oat file to be the same as the");
-  UsageError("      given image file.");
-  UsageError("");
   UsageError("  --patched-image-location=<file.art>: Relocate the oat file to be the same as the");
   UsageError("      image at the given location. If used one must also specify the");
   UsageError("      --instruction-set flag. It will search for this image in the same way that");
@@ -992,6 +966,244 @@
   return true;
 }
 
+static int patchoat_image(TimingLogger& timings,
+                          InstructionSet isa,
+                          const std::string& input_image_location,
+                          const std::string& output_image_filename,
+                          off_t base_delta,
+                          bool base_delta_set,
+                          bool debug) {
+  CHECK(!input_image_location.empty());
+  if (output_image_filename.empty()) {
+    Usage("Image patching requires --output-image-file");
+  }
+
+  if (!base_delta_set) {
+    Usage("Must supply a desired new offset or delta.");
+  }
+
+  if (!IsAligned<kPageSize>(base_delta)) {
+    Usage("Base offset/delta must be aligned to a pagesize (0x%08x) boundary.", kPageSize);
+  }
+
+  if (debug) {
+    LOG(INFO) << "moving offset by " << base_delta
+        << " (0x" << std::hex << base_delta << ") bytes or "
+        << std::dec << (base_delta/kPageSize) << " pages.";
+  }
+
+  TimingLogger::ScopedTiming pt("patch image and oat", &timings);
+
+  std::string output_directory =
+      output_image_filename.substr(0, output_image_filename.find_last_of("/"));
+  bool ret = PatchOat::Patch(input_image_location, base_delta, output_directory, isa, &timings);
+
+  if (kIsDebugBuild) {
+    LOG(INFO) << "Exiting with return ... " << ret;
+  }
+  return ret ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static int patchoat_oat(TimingLogger& timings,
+                        InstructionSet isa,
+                        const std::string& patched_image_location,
+                        off_t base_delta,
+                        bool base_delta_set,
+                        int input_oat_fd,
+                        const std::string& input_oat_location,
+                        std::string input_oat_filename,
+                        bool have_input_oat,
+                        int output_oat_fd,
+                        std::string output_oat_filename,
+                        bool have_output_oat,
+                        bool lock_output,
+                        bool debug) {
+  {
+    // Only 1 of these may be set.
+    uint32_t cnt = 0;
+    cnt += (base_delta_set) ? 1 : 0;
+    cnt += (!patched_image_location.empty()) ? 1 : 0;
+    if (cnt > 1) {
+      Usage("Only one of --base-offset-delta or --patched-image-location may be used.");
+    } else if (cnt == 0) {
+      Usage("Must specify --base-offset-delta or --patched-image-location.");
+    }
+  }
+
+  if (!have_input_oat || !have_output_oat) {
+    Usage("Both input and output oat must be supplied to patch an app odex.");
+  }
+
+  if (!input_oat_location.empty()) {
+    if (!LocationToFilename(input_oat_location, isa, &input_oat_filename)) {
+      Usage("Unable to find filename for input oat location %s", input_oat_location.c_str());
+    }
+    if (debug) {
+      LOG(INFO) << "Using input-oat-file " << input_oat_filename;
+    }
+  }
+
+  bool match_delta = false;
+  if (!patched_image_location.empty()) {
+    std::string system_filename;
+    bool has_system = false;
+    std::string cache_filename;
+    bool has_cache = false;
+    bool has_android_data_unused = false;
+    bool is_global_cache = false;
+    if (!gc::space::ImageSpace::FindImageFilename(patched_image_location.c_str(), isa,
+                                                  &system_filename, &has_system, &cache_filename,
+                                                  &has_android_data_unused, &has_cache,
+                                                  &is_global_cache)) {
+      Usage("Unable to determine image file for location %s", patched_image_location.c_str());
+    }
+    std::string patched_image_filename;
+    if (has_cache) {
+      patched_image_filename = cache_filename;
+    } else if (has_system) {
+      LOG(WARNING) << "Only image file found was in /system for image location "
+          << patched_image_location;
+      patched_image_filename = system_filename;
+    } else {
+      Usage("Unable to determine image file for location %s", patched_image_location.c_str());
+    }
+    if (debug) {
+      LOG(INFO) << "Using patched-image-file " << patched_image_filename;
+    }
+
+    base_delta_set = true;
+    match_delta = true;
+    std::string error_msg;
+    if (!ReadBaseDelta(patched_image_filename.c_str(), &base_delta, &error_msg)) {
+      Usage(error_msg.c_str(), patched_image_filename.c_str());
+    }
+  }
+
+  if (!IsAligned<kPageSize>(base_delta)) {
+    Usage("Base offset/delta must be alligned to a pagesize (0x%08x) boundary.", kPageSize);
+  }
+
+  // Do we need to cleanup output files if we fail?
+  bool new_oat_out = false;
+
+  std::unique_ptr<File> input_oat;
+  std::unique_ptr<File> output_oat;
+
+  if (input_oat_fd != -1) {
+    if (input_oat_filename.empty()) {
+      input_oat_filename = "input-oat-file";
+    }
+    input_oat.reset(new File(input_oat_fd, input_oat_filename, false));
+    if (input_oat_fd == output_oat_fd) {
+      input_oat.get()->DisableAutoClose();
+    }
+    if (input_oat == nullptr) {
+      // Unlikely, but ensure exhaustive logging in non-0 exit code case
+      LOG(ERROR) << "Failed to open input oat file by its FD" << input_oat_fd;
+    }
+  } else {
+    CHECK(!input_oat_filename.empty());
+    input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str()));
+    if (input_oat == nullptr) {
+      int err = errno;
+      LOG(ERROR) << "Failed to open input oat file " << input_oat_filename
+          << ": " << strerror(err) << "(" << err << ")";
+    }
+  }
+
+  if (output_oat_fd != -1) {
+    if (output_oat_filename.empty()) {
+      output_oat_filename = "output-oat-file";
+    }
+    output_oat.reset(new File(output_oat_fd, output_oat_filename, true));
+    if (output_oat == nullptr) {
+      // Unlikely, but ensure exhaustive logging in non-0 exit code case
+      LOG(ERROR) << "Failed to open output oat file by its FD" << output_oat_fd;
+    }
+  } else {
+    CHECK(!output_oat_filename.empty());
+    output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
+    if (output_oat == nullptr) {
+      int err = errno;
+      LOG(ERROR) << "Failed to open output oat file " << output_oat_filename
+          << ": " << strerror(err) << "(" << err << ")";
+    }
+  }
+
+  // TODO: get rid of this.
+  auto cleanup = [&output_oat_filename, &new_oat_out](bool success) {
+    if (!success) {
+      if (new_oat_out) {
+        CHECK(!output_oat_filename.empty());
+        TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str()));
+      }
+    }
+
+    if (kIsDebugBuild) {
+      LOG(INFO) << "Cleaning up.. success? " << success;
+    }
+  };
+
+  if (input_oat.get() == nullptr || output_oat.get() == nullptr) {
+    LOG(ERROR) << "Failed to open input/output oat files";
+    cleanup(false);
+    return EXIT_FAILURE;
+  }
+
+  if (match_delta) {
+    std::string error_msg;
+    // Figure out what the current delta is so we can match it to the desired delta.
+    std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat.get(), PROT_READ, MAP_PRIVATE,
+                                               &error_msg));
+    off_t current_delta = 0;
+    if (elf.get() == nullptr) {
+      LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg;
+      cleanup(false);
+      return EXIT_FAILURE;
+    } else if (!ReadOatPatchDelta(elf.get(), &current_delta, &error_msg)) {
+      LOG(ERROR) << "Unable to get current delta: " << error_msg;
+      cleanup(false);
+      return EXIT_FAILURE;
+    }
+    // Before this line base_delta is the desired final delta. We need it to be the actual amount to
+    // change everything by. We subtract the current delta from it to make it this.
+    base_delta -= current_delta;
+    if (!IsAligned<kPageSize>(base_delta)) {
+      LOG(ERROR) << "Given image file was relocated by an illegal delta";
+      cleanup(false);
+      return false;
+    }
+  }
+
+  if (debug) {
+    LOG(INFO) << "moving offset by " << base_delta
+        << " (0x" << std::hex << base_delta << ") bytes or "
+        << std::dec << (base_delta/kPageSize) << " pages.";
+  }
+
+  ScopedFlock output_oat_lock;
+  if (lock_output) {
+    std::string error_msg;
+    if (!output_oat_lock.Init(output_oat.get(), &error_msg)) {
+      LOG(ERROR) << "Unable to lock output oat " << output_oat->GetPath() << ": " << error_msg;
+      cleanup(false);
+      return EXIT_FAILURE;
+    }
+  }
+
+  TimingLogger::ScopedTiming pt("patch oat", &timings);
+  bool ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings,
+                             output_oat_fd >= 0,  // was it opened from FD?
+                             new_oat_out);
+  ret = FinishFile(output_oat.get(), ret);
+
+  if (kIsDebugBuild) {
+    LOG(INFO) << "Exiting with return ... " << ret;
+  }
+  cleanup(ret);
+  return ret ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
 static int patchoat(int argc, char **argv) {
   InitLogging(argv);
   MemMap::Init();
@@ -1024,15 +1236,8 @@
   int output_oat_fd = -1;
   bool have_output_oat = false;
   std::string output_image_filename;
-  int output_image_fd = -1;
-  bool have_output_image = false;
-  uintptr_t base_offset = 0;
-  bool base_offset_set = false;
-  uintptr_t orig_base_offset = 0;
-  bool orig_base_offset_set = false;
   off_t base_delta = 0;
   bool base_delta_set = false;
-  bool match_delta = false;
   std::string patched_image_filename;
   std::string patched_image_location;
   bool dump_timings = kIsDebugBuild;
@@ -1096,36 +1301,7 @@
         Usage("--output-oat-fd pass a negative value %d", output_oat_fd);
       }
     } else if (option.starts_with("--output-image-file=")) {
-      if (have_output_image) {
-        Usage("Only one of --output-image-file, and --output-image-fd may be used.");
-      }
-      have_output_image = true;
       output_image_filename = option.substr(strlen("--output-image-file=")).data();
-    } else if (option.starts_with("--output-image-fd=")) {
-      if (have_output_image) {
-        Usage("Only one of --output-image-file, and --output-image-fd may be used.");
-      }
-      have_output_image = true;
-      const char* image_fd_str = option.substr(strlen("--output-image-fd=")).data();
-      if (!ParseInt(image_fd_str, &output_image_fd)) {
-        Usage("Failed to parse --output-image-fd argument '%s' as an integer", image_fd_str);
-      }
-      if (output_image_fd < 0) {
-        Usage("--output-image-fd pass a negative value %d", output_image_fd);
-      }
-    } else if (option.starts_with("--orig-base-offset=")) {
-      const char* orig_base_offset_str = option.substr(strlen("--orig-base-offset=")).data();
-      orig_base_offset_set = true;
-      if (!ParseUint(orig_base_offset_str, &orig_base_offset)) {
-        Usage("Failed to parse --orig-base-offset argument '%s' as an uintptr_t",
-              orig_base_offset_str);
-      }
-    } else if (option.starts_with("--base-offset=")) {
-      const char* base_offset_str = option.substr(strlen("--base-offset=")).data();
-      base_offset_set = true;
-      if (!ParseUint(base_offset_str, &base_offset)) {
-        Usage("Failed to parse --base-offset argument '%s' as an uintptr_t", base_offset_str);
-      }
     } else if (option.starts_with("--base-offset-delta=")) {
       const char* base_delta_str = option.substr(strlen("--base-offset-delta=")).data();
       base_delta_set = true;
@@ -1134,8 +1310,6 @@
       }
     } else if (option.starts_with("--patched-image-location=")) {
       patched_image_location = option.substr(strlen("--patched-image-location=")).data();
-    } else if (option.starts_with("--patched-image-file=")) {
-      patched_image_filename = option.substr(strlen("--patched-image-file=")).data();
     } else if (option == "--lock-output") {
       lock_output = true;
     } else if (option == "--no-lock-output") {
@@ -1149,284 +1323,43 @@
     }
   }
 
-  {
-    // Only 1 of these may be set.
-    uint32_t cnt = 0;
-    cnt += (base_delta_set) ? 1 : 0;
-    cnt += (base_offset_set && orig_base_offset_set) ? 1 : 0;
-    cnt += (!patched_image_filename.empty()) ? 1 : 0;
-    cnt += (!patched_image_location.empty()) ? 1 : 0;
-    if (cnt > 1) {
-      Usage("Only one of --base-offset/--orig-base-offset, --base-offset-delta, "
-            "--patched-image-filename or --patched-image-location may be used.");
-    } else if (cnt == 0) {
-      Usage("Must specify --base-offset-delta, --base-offset and --orig-base-offset, "
-            "--patched-image-location or --patched-image-file");
-    }
+  // The instruction set is mandatory. This simplifies things...
+  if (!isa_set) {
+    Usage("Instruction set must be set.");
   }
 
-  if (have_input_oat != have_output_oat) {
-    Usage("Either both input and output oat must be supplied or niether must be.");
-  }
-
-  if ((!input_image_location.empty()) != have_output_image) {
-    Usage("Either both input and output image must be supplied or niether must be.");
-  }
-
-  // We know we have both the input and output so rename for clarity.
-  bool have_image_files = have_output_image;
-  bool have_oat_files = have_output_oat;
-
-  if (!have_oat_files) {
-    if (have_image_files) {
-      Usage("Cannot patch an image file without an oat file");
-    } else {
-      Usage("Must be patching either an oat file or an image file with an oat file.");
-    }
-  }
-
-  if (!have_oat_files && !isa_set) {
-    Usage("Must include ISA if patching an image file without an oat file.");
-  }
-
-  if (!input_oat_location.empty()) {
-    if (!isa_set) {
-      Usage("specifying a location requires specifying an instruction set");
-    }
-    if (!LocationToFilename(input_oat_location, isa, &input_oat_filename)) {
-      Usage("Unable to find filename for input oat location %s", input_oat_location.c_str());
-    }
-    if (debug) {
-      LOG(INFO) << "Using input-oat-file " << input_oat_filename;
-    }
-  }
-  if (!patched_image_location.empty()) {
-    if (!isa_set) {
-      Usage("specifying a location requires specifying an instruction set");
-    }
-    std::string system_filename;
-    bool has_system = false;
-    std::string cache_filename;
-    bool has_cache = false;
-    bool has_android_data_unused = false;
-    bool is_global_cache = false;
-    if (!gc::space::ImageSpace::FindImageFilename(patched_image_location.c_str(), isa,
-                                                  &system_filename, &has_system, &cache_filename,
-                                                  &has_android_data_unused, &has_cache,
-                                                  &is_global_cache)) {
-      Usage("Unable to determine image file for location %s", patched_image_location.c_str());
-    }
-    if (has_cache) {
-      patched_image_filename = cache_filename;
-    } else if (has_system) {
-      LOG(WARNING) << "Only image file found was in /system for image location "
-                   << patched_image_location;
-      patched_image_filename = system_filename;
-    } else {
-      Usage("Unable to determine image file for location %s", patched_image_location.c_str());
-    }
-    if (debug) {
-      LOG(INFO) << "Using patched-image-file " << patched_image_filename;
-    }
-  }
-
-  if (!base_delta_set) {
-    if (orig_base_offset_set && base_offset_set) {
-      base_delta_set = true;
-      base_delta = base_offset - orig_base_offset;
-    } else if (!patched_image_filename.empty()) {
-      if (have_image_files) {
-        Usage("--patched-image-location should not be used when patching other images");
-      }
-      base_delta_set = true;
-      match_delta = true;
-      std::string error_msg;
-      if (!ReadBaseDelta(patched_image_filename.c_str(), &base_delta, &error_msg)) {
-        Usage(error_msg.c_str(), patched_image_filename.c_str());
-      }
-    } else {
-      if (base_offset_set) {
-        Usage("Unable to determine original base offset.");
-      } else {
-        Usage("Must supply a desired new offset or delta.");
-      }
-    }
-  }
-
-  if (!IsAligned<kPageSize>(base_delta)) {
-    Usage("Base offset/delta must be alligned to a pagesize (0x%08x) boundary.", kPageSize);
-  }
-
-  // Do we need to cleanup output files if we fail?
-  bool new_image_out = false;
-  bool new_oat_out = false;
-
-  std::unique_ptr<File> input_oat;
-  std::unique_ptr<File> output_oat;
-  std::unique_ptr<File> output_image;
-
-  if (have_image_files) {
-    CHECK(!input_image_location.empty());
-
-    if (output_image_fd != -1) {
-      if (output_image_filename.empty()) {
-        output_image_filename = "output-image-file";
-      }
-      output_image.reset(new File(output_image_fd, output_image_filename, true));
-    } else {
-      CHECK(!output_image_filename.empty());
-      output_image.reset(CreateOrOpen(output_image_filename.c_str(), &new_image_out));
-    }
+  int ret;
+  if (!input_image_location.empty()) {
+    ret = patchoat_image(timings,
+                         isa,
+                         input_image_location,
+                         output_image_filename,
+                         base_delta,
+                         base_delta_set,
+                         debug);
   } else {
-    CHECK(output_image_filename.empty() && output_image_fd == -1 && input_image_location.empty());
+    ret = patchoat_oat(timings,
+                       isa,
+                       patched_image_location,
+                       base_delta,
+                       base_delta_set,
+                       input_oat_fd,
+                       input_oat_location,
+                       input_oat_filename,
+                       have_input_oat,
+                       output_oat_fd,
+                       output_oat_filename,
+                       have_output_oat,
+                       lock_output,
+                       debug);
   }
 
-  if (have_oat_files) {
-    if (input_oat_fd != -1) {
-      if (input_oat_filename.empty()) {
-        input_oat_filename = "input-oat-file";
-      }
-      input_oat.reset(new File(input_oat_fd, input_oat_filename, false));
-      if (input_oat_fd == output_oat_fd) {
-        input_oat.get()->DisableAutoClose();
-      }
-      if (input_oat == nullptr) {
-        // Unlikely, but ensure exhaustive logging in non-0 exit code case
-        LOG(ERROR) << "Failed to open input oat file by its FD" << input_oat_fd;
-      }
-    } else {
-      CHECK(!input_oat_filename.empty());
-      input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str()));
-      if (input_oat == nullptr) {
-        int err = errno;
-        LOG(ERROR) << "Failed to open input oat file " << input_oat_filename
-                   << ": " << strerror(err) << "(" << err << ")";
-      }
-    }
-
-    if (output_oat_fd != -1) {
-      if (output_oat_filename.empty()) {
-        output_oat_filename = "output-oat-file";
-      }
-      output_oat.reset(new File(output_oat_fd, output_oat_filename, true));
-      if (output_oat == nullptr) {
-        // Unlikely, but ensure exhaustive logging in non-0 exit code case
-        LOG(ERROR) << "Failed to open output oat file by its FD" << output_oat_fd;
-      }
-    } else {
-      CHECK(!output_oat_filename.empty());
-      output_oat.reset(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
-      if (output_oat == nullptr) {
-        int err = errno;
-        LOG(ERROR) << "Failed to open output oat file " << output_oat_filename
-                   << ": " << strerror(err) << "(" << err << ")";
-      }
-    }
+  timings.EndTiming();
+  if (dump_timings) {
+    LOG(INFO) << Dumpable<TimingLogger>(timings);
   }
 
-  // TODO: get rid of this.
-  auto cleanup = [&output_image_filename, &output_oat_filename,
-                  &new_oat_out, &new_image_out, &timings, &dump_timings](bool success) {
-    timings.EndTiming();
-    if (!success) {
-      if (new_oat_out) {
-        CHECK(!output_oat_filename.empty());
-        TEMP_FAILURE_RETRY(unlink(output_oat_filename.c_str()));
-      }
-      if (new_image_out) {
-        CHECK(!output_image_filename.empty());
-        TEMP_FAILURE_RETRY(unlink(output_image_filename.c_str()));
-      }
-    }
-    if (dump_timings) {
-      LOG(INFO) << Dumpable<TimingLogger>(timings);
-    }
-
-    if (kIsDebugBuild) {
-      LOG(INFO) << "Cleaning up.. success? " << success;
-    }
-  };
-
-  if (have_oat_files && (input_oat.get() == nullptr || output_oat.get() == nullptr)) {
-    LOG(ERROR) << "Failed to open input/output oat files";
-    cleanup(false);
-    return EXIT_FAILURE;
-  } else if (have_image_files && output_image.get() == nullptr) {
-    LOG(ERROR) << "Failed to open output image file";
-    cleanup(false);
-    return EXIT_FAILURE;
-  }
-
-  if (match_delta) {
-    CHECK(!have_image_files);  // We will not do this with images.
-    std::string error_msg;
-    // Figure out what the current delta is so we can match it to the desired delta.
-    std::unique_ptr<ElfFile> elf(ElfFile::Open(input_oat.get(), PROT_READ, MAP_PRIVATE,
-                                               &error_msg));
-    off_t current_delta = 0;
-    if (elf.get() == nullptr) {
-      LOG(ERROR) << "unable to open oat file " << input_oat->GetPath() << " : " << error_msg;
-      cleanup(false);
-      return EXIT_FAILURE;
-    } else if (!ReadOatPatchDelta(elf.get(), &current_delta, &error_msg)) {
-      LOG(ERROR) << "Unable to get current delta: " << error_msg;
-      cleanup(false);
-      return EXIT_FAILURE;
-    }
-    // Before this line base_delta is the desired final delta. We need it to be the actual amount to
-    // change everything by. We subtract the current delta from it to make it this.
-    base_delta -= current_delta;
-    if (!IsAligned<kPageSize>(base_delta)) {
-      LOG(ERROR) << "Given image file was relocated by an illegal delta";
-      cleanup(false);
-      return false;
-    }
-  }
-
-  if (debug) {
-    LOG(INFO) << "moving offset by " << base_delta
-              << " (0x" << std::hex << base_delta << ") bytes or "
-              << std::dec << (base_delta/kPageSize) << " pages.";
-  }
-
-  // TODO: is it going to be promatic to unlink a file that was flock-ed?
-  ScopedFlock output_oat_lock;
-  if (lock_output) {
-    std::string error_msg;
-    if (have_oat_files && !output_oat_lock.Init(output_oat.get(), &error_msg)) {
-      LOG(ERROR) << "Unable to lock output oat " << output_image->GetPath() << ": " << error_msg;
-      cleanup(false);
-      return EXIT_FAILURE;
-    }
-  }
-
-  bool ret;
-  if (have_image_files && have_oat_files) {
-    TimingLogger::ScopedTiming pt("patch image and oat", &timings);
-    ret = PatchOat::Patch(input_oat.get(), input_image_location, base_delta,
-                          output_oat.get(), output_image.get(), isa, &timings,
-                          output_oat_fd >= 0,  // was it opened from FD?
-                          new_oat_out);
-    // The order here doesn't matter. If the first one is successfully saved and the second one
-    // erased, ImageSpace will still detect a problem and not use the files.
-    ret = FinishFile(output_image.get(), ret);
-    ret = FinishFile(output_oat.get(), ret);
-  } else if (have_oat_files) {
-    TimingLogger::ScopedTiming pt("patch oat", &timings);
-    ret = PatchOat::Patch(input_oat.get(), base_delta, output_oat.get(), &timings,
-                          output_oat_fd >= 0,  // was it opened from FD?
-                          new_oat_out);
-    ret = FinishFile(output_oat.get(), ret);
-  } else {
-    CHECK(false);
-    ret = true;
-  }
-
-  if (kIsDebugBuild) {
-    LOG(INFO) << "Exiting with return ... " << ret;
-  }
-  cleanup(ret);
-  return (ret) ? EXIT_SUCCESS : EXIT_FAILURE;
+  return ret;
 }
 
 }  // namespace art
diff --git a/patchoat/patchoat.h b/patchoat/patchoat.h
index ceddc34..a6a8fee 100644
--- a/patchoat/patchoat.h
+++ b/patchoat/patchoat.h
@@ -53,11 +53,11 @@
                     TimingLogger* timings);
 
   // Patch both the image and the oat file
-  static bool Patch(File* oat_in, const std::string& art_location,
-                    off_t delta, File* oat_out, File* art_out, InstructionSet isa,
-                    TimingLogger* timings,
-                    bool output_oat_opened_from_fd,  // Was this using --oatput-oat-fd ?
-                    bool new_oat_out);               // Output oat was a new file created by us?
+  static bool Patch(const std::string& art_location,
+                    off_t delta,
+                    const std::string& output_directory,
+                    InstructionSet isa,
+                    TimingLogger* timings);
 
   ~PatchOat() {}
   PatchOat(PatchOat&&) = default;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 288f95e..e9f7add 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -275,6 +275,8 @@
   arch/arm64/fault_handler_arm64.cc
 
 LIBART_SRC_FILES_x86 := \
+  interpreter/mterp/mterp.cc \
+  interpreter/mterp/out/mterp_x86.S \
   arch/x86/context_x86.cc \
   arch/x86/entrypoints_init_x86.cc \
   arch/x86/jni_entrypoints_x86.S \
@@ -286,20 +288,6 @@
 LIBART_TARGET_SRC_FILES_x86 := \
   $(LIBART_SRC_FILES_x86)
 
-# Darwin uses non-standard x86 assembly syntax.  Don't build x86 Darwin host mterp there.
-ifeq ($(HOST_OS),darwin)
-  LIBART_SRC_FILES_x86 += \
-    interpreter/mterp/mterp_stub.cc
-else
-  LIBART_SRC_FILES_x86 += \
-    interpreter/mterp/mterp.cc \
-    interpreter/mterp/out/mterp_x86.S
-endif
-# But do support x86 mterp for target build regardless of host platform.
-LIBART_TARGET_SRC_FILES_x86 += \
-  interpreter/mterp/mterp.cc \
-  interpreter/mterp/out/mterp_x86.S
-
 # Note that the fault_handler_x86.cc is not a mistake.  This file is
 # shared between the x86 and x86_64 architectures.
 LIBART_SRC_FILES_x86_64 := \
diff --git a/runtime/arch/arm/entrypoints_init_arm.cc b/runtime/arch/arm/entrypoints_init_arm.cc
index 7141181..e358ff8 100644
--- a/runtime/arch/arm/entrypoints_init_arm.cc
+++ b/runtime/arch/arm/entrypoints_init_arm.cc
@@ -130,6 +130,25 @@
     qpoints->pL2f = art_quick_l2f;
   }
 
+  // More math.
+  qpoints->pCos = cos;
+  qpoints->pSin = sin;
+  qpoints->pAcos = acos;
+  qpoints->pAsin = asin;
+  qpoints->pAtan = atan;
+  qpoints->pAtan2 = atan2;
+  qpoints->pCbrt = cbrt;
+  qpoints->pCosh = cosh;
+  qpoints->pExp = exp;
+  qpoints->pExpm1 = expm1;
+  qpoints->pHypot = hypot;
+  qpoints->pLog = log;
+  qpoints->pLog10 = log10;
+  qpoints->pNextAfter = nextafter;
+  qpoints->pSinh = sinh;
+  qpoints->pTan = tan;
+  qpoints->pTanh = tanh;
+
   // Intrinsics
   qpoints->pIndexOf = art_quick_indexof;
   qpoints->pStringCompareTo = art_quick_string_compareto;
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 631b784..c4e314b 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -429,6 +429,56 @@
 END art_quick_invoke_stub_internal
 
     /*
+     * On stack replacement stub.
+     * On entry:
+     *   r0 = stack to copy
+     *   r1 = size of stack
+     *   r2 = pc to call
+     *   r3 = JValue* result
+     *   [sp] = shorty
+     *   [sp + 4] = thread
+     */
+ENTRY art_quick_osr_stub
+    SPILL_ALL_CALLEE_SAVE_GPRS             @ Spill regs (9)
+    mov    r11, sp                         @ Save the stack pointer
+    mov    r10, r1                         @ Save size of stack
+    ldr    r9, [r11, #40]                  @ Move managed thread pointer into r9
+    mov    r8, r2                          @ Save the pc to call
+    sub    r7, sp, #12                     @ Reserve space for stack pointer,
+                                           @    JValue* result, and ArtMethod* slot.
+    and    r7, #0xFFFFFFF0                 @ Align stack pointer
+    mov    sp, r7                          @ Update stack pointer
+    str    r11, [sp, #4]                   @ Save old stack pointer
+    str    r3, [sp, #8]                    @ Save JValue* result
+    mov    ip, #0
+    str    ip, [sp]                        @ Store null for ArtMethod* at bottom of frame
+    sub    sp, sp, r1                      @ Reserve space for callee stack
+    mov    r2, r1
+    mov    r1, r0
+    mov    r0, sp
+    bl     memcpy                          @ memcpy (dest r0, src r1, bytes r2)
+    bl     .Losr_entry                     @ Call the method
+    ldr    r10, [sp, #8]                   @ Restore JValue* result
+    ldr    sp, [sp, #4]                    @ Restore saved stack pointer
+    ldr    r4, [sp, #36]                   @ load shorty
+    ldrb   r4, [r4, #0]                    @ load return type
+    cmp    r4, #68                         @ Test if result type char == 'D'.
+    beq    .Losr_fp_result
+    cmp    r4, #70                         @ Test if result type char == 'F'.
+    beq    .Losr_fp_result
+    strd r0, [r10]                         @ Store r0/r1 into result pointer
+    b    .Losr_exit
+.Losr_fp_result:
+    vstr d0, [r10]                         @ Store s0-s1/d0 into result pointer
+.Losr_exit:
+    pop    {r4, r5, r6, r7, r8, r9, r10, r11, pc}
+.Losr_entry:
+    sub r10, r10, #4
+    str lr, [sp, r10]                     @ Store link register per the compiler ABI
+    bx r8
+END art_quick_osr_stub
+
+    /*
      * On entry r0 is uint32_t* gprs_ and r1 is uint32_t* fprs_
      */
 ARM_ENTRY art_quick_do_long_jump
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 9ccabad..e848008 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -915,6 +915,105 @@
 
 
 
+/*  extern"C" void art_quick_osr_stub(void** stack,                x0
+ *                                    size_t stack_size_in_bytes,  x1
+ *                                    const uin8_t* native_pc,     x2
+ *                                    JValue *result,              x3
+ *                                    char   *shorty,              x4
+ *                                    Thread *self)                x5
+ */
+ENTRY art_quick_osr_stub
+SAVE_SIZE=15*8   // x3, x4, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, SP, LR, FP saved.
+    mov x9, sp                             // Save stack pointer.
+    .cfi_register sp,x9
+
+    sub x10, sp, # SAVE_SIZE
+    and x10, x10, # ~0xf                   // Enforce 16 byte stack alignment.
+    mov sp, x10                            // Set new SP.
+
+    str x28, [sp, #112]
+    stp x26, x27, [sp, #96]
+    stp x24, x25, [sp, #80]
+    stp x22, x23, [sp, #64]
+    stp x20, x21, [sp, #48]
+    stp x9, x19, [sp, #32]                // Save old stack pointer and x19.
+    stp x3, x4, [sp, #16]                 // Save result and shorty addresses.
+    stp xFP, xLR, [sp]                    // Store LR & FP.
+    mov xSELF, x5                         // Move thread pointer into SELF register.
+
+    sub sp, sp, #16
+    str xzr, [sp]                         // Store null for ArtMethod* slot
+    // Branch to stub.
+    bl .Losr_entry
+    add sp, sp, #16
+
+    // Restore return value address and shorty address.
+    ldp x3,x4, [sp, #16]
+    ldr x28, [sp, #112]
+    ldp x26, x27, [sp, #96]
+    ldp x24, x25, [sp, #80]
+    ldp x22, x23, [sp, #64]
+    ldp x20, x21, [sp, #48]
+
+    // Store result (w0/x0/s0/d0) appropriately, depending on resultType.
+    ldrb w10, [x4]
+
+    // Check the return type and store the correct register into the jvalue in memory.
+
+    // Don't set anything for a void type.
+    cmp w10, #'V'
+    beq .Losr_exit
+
+    // Is it a double?
+    cmp w10, #'D'
+    bne .Lno_double
+    str d0, [x3]
+    b .Losr_exit
+
+.Lno_double:  // Is it a float?
+    cmp w10, #'F'
+    bne .Lno_float
+    str s0, [x3]
+    b .Losr_exit
+
+.Lno_float:  // Just store x0. Doesn't matter if it is 64 or 32 bits.
+    str x0, [x3]
+
+.Losr_exit:  // Finish up.
+    ldp x2, x19, [sp, #32]   // Restore stack pointer and x19.
+    ldp xFP, xLR, [sp]    // Restore old frame pointer and link register.
+    mov sp, x2
+    ret
+
+.Losr_entry:
+    // Update stack pointer for the callee
+    sub sp, sp, x1
+
+    // Update link register slot expected by the callee.
+    sub w1, w1, #8
+    str lr, [sp, x1]
+
+    // Copy arguments into stack frame.
+    // Use simple copy routine for now.
+    // 4 bytes per slot.
+    // X0 - source address
+    // W1 - args length
+    // SP - destination address.
+    // W10 - temporary
+.Losr_loop_entry:
+    cmp w1, #0
+    beq .Losr_loop_exit
+    sub w1, w1, #4
+    ldr w10, [x0, x1]
+    str w10, [sp, x1]
+    b .Losr_loop_entry
+
+.Losr_loop_exit:
+    // Branch to the OSR entry point.
+    br x2
+
+END art_quick_osr_stub
+
     /*
      * On entry x0 is uintptr_t* gprs_ and x1 is uint64_t* fprs_
      */
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index da30331..fbee5d7 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1712,5 +1712,65 @@
     ret
 END_FUNCTION art_quick_read_barrier_for_root_slow
 
+  /*
+     * On stack replacement stub.
+     * On entry:
+     *   [sp] = return address
+     *   [sp + 4] = stack to copy
+     *   [sp + 8] = size of stack
+     *   [sp + 12] = pc to call
+     *   [sp + 16] = JValue* result
+     *   [sp + 20] = shorty
+     *   [sp + 24] = thread
+     */
+DEFINE_FUNCTION art_quick_osr_stub
+    // Save native callee saves.
+    PUSH ebp
+    PUSH ebx
+    PUSH esi
+    PUSH edi
+    mov 4+16(%esp), %esi           // ESI = argument array
+    mov 8+16(%esp), %ecx           // ECX = size of args
+    mov 12+16(%esp), %ebx          // EBX = pc to call
+    mov %esp, %ebp                 // Save stack pointer
+    andl LITERAL(0xFFFFFFF0), %esp // Align stack
+    PUSH ebp                       // Save old stack pointer
+    subl LITERAL(12), %esp         // Align stack
+    movl LITERAL(0), (%esp)        // Store null for ArtMethod* slot
+    call .Losr_entry
+
+    // Restore stack pointer.
+    addl LITERAL(12), %esp
+    POP ebp
+    mov %ebp, %esp
+
+    // Restore callee saves.
+    POP edi
+    POP esi
+    POP ebx
+    POP ebp
+    mov 16(%esp), %ecx            // Get JValue result
+    mov %eax, (%ecx)              // Store the result assuming it is a long, int or Object*
+    mov %edx, 4(%ecx)             // Store the other half of the result
+    mov 20(%esp), %edx            // Get the shorty
+    cmpb LITERAL(68), (%edx)      // Test if result type char == 'D'
+    je .Losr_return_double_quick
+    cmpb LITERAL(70), (%edx)      // Test if result type char == 'F'
+    je .Losr_return_float_quick
+    ret
+.Losr_return_double_quick:
+    movsd %xmm0, (%ecx)           // Store the floating point result
+    ret
+.Losr_return_float_quick:
+    movss %xmm0, (%ecx)           // Store the floating point result
+    ret
+.Losr_entry:
+    subl LITERAL(4), %ecx         // Given stack size contains pushed frame pointer, substract it.
+    subl %ecx, %esp
+    mov %esp, %edi                // EDI = beginning of stack
+    rep movsb                     // while (ecx--) { *edi++ = *esi++ }
+    jmp *%ebx
+END_FUNCTION art_quick_osr_stub
+
     // TODO: implement these!
 UNIMPLEMENTED art_quick_memcmp16
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 883da96..69caec8 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1744,3 +1744,64 @@
     RESTORE_FP_CALLEE_SAVE_FRAME
     ret
 END_FUNCTION art_quick_read_barrier_for_root_slow
+
+    /*
+     * On stack replacement stub.
+     * On entry:
+     *   [sp] = return address
+     *   rdi = stack to copy
+     *   rsi = size of stack
+     *   rdx = pc to call
+     *   rcx = JValue* result
+     *   r8 = shorty
+     *   r9 = thread
+     *
+     * Note that the native C ABI already aligned the stack to 16-byte.
+     */
+DEFINE_FUNCTION art_quick_osr_stub
+    // Save the non-volatiles.
+    PUSH rbp                      // Save rbp.
+    PUSH rcx                      // Save rcx/result*.
+    PUSH r8                       // Save r8/shorty*.
+
+    // Save callee saves.
+    PUSH rbx
+    PUSH r12
+    PUSH r13
+    PUSH r14
+    PUSH r15
+
+    pushq LITERAL(0)              // Push null for ArtMethod*.
+    movl %esi, %ecx               // rcx := size of stack
+    movq %rdi, %rsi               // rsi := stack to copy
+    call .Losr_entry
+
+    // Restore stack and callee-saves.
+    addq LITERAL(8), %rsp
+    POP r15
+    POP r14
+    POP r13
+    POP r12
+    POP rbx
+    POP r8
+    POP rcx
+    POP rbp
+    cmpb LITERAL(68), (%r8)        // Test if result type char == 'D'.
+    je .Losr_return_double_quick
+    cmpb LITERAL(70), (%r8)        // Test if result type char == 'F'.
+    je .Losr_return_float_quick
+    movq %rax, (%rcx)              // Store the result assuming its a long, int or Object*
+    ret
+.Losr_return_double_quick:
+    movsd %xmm0, (%rcx)            // Store the double floating point result.
+    ret
+.Losr_return_float_quick:
+    movss %xmm0, (%rcx)            // Store the floating point result.
+    ret
+.Losr_entry:
+    subl LITERAL(8), %ecx         // Given stack size contains pushed frame pointer, substract it.
+    subq %rcx, %rsp
+    movq %rsp, %rdi               // rdi := beginning of stack
+    rep movsb                     // while (rcx--) { *rdi++ = *rsi++ }
+    jmp *%rdx
+END_FUNCTION art_quick_osr_stub
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 28540c8..ebe89bb 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -449,23 +449,26 @@
 void ArtMethod::VisitRoots(RootVisitorType& visitor, size_t pointer_size) {
   ArtMethod* interface_method = nullptr;
   mirror::Class* klass = declaring_class_.Read();
-  if (UNLIKELY(klass != nullptr && klass->IsProxyClass())) {
-    // For normal methods, dex cache shortcuts will be visited through the declaring class.
-    // However, for proxies we need to keep the interface method alive, so we visit its roots.
-    interface_method = mirror::DexCache::GetElementPtrSize(
-        GetDexCacheResolvedMethods(pointer_size),
-        GetDexMethodIndex(),
-        pointer_size);
-    DCHECK(interface_method != nullptr);
-    DCHECK_EQ(interface_method,
-              Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
-    interface_method->VisitRoots(visitor, pointer_size);
-  }
-
-  visitor.VisitRootIfNonNull(declaring_class_.AddressWithoutBarrier());
-  ProfilingInfo* profiling_info = GetProfilingInfo(pointer_size);
-  if (hotness_count_ != 0 && !IsNative() && profiling_info != nullptr) {
-    profiling_info->VisitRoots(visitor);
+  if (LIKELY(klass != nullptr)) {
+    if (UNLIKELY(klass->IsProxyClass())) {
+      // For normal methods, dex cache shortcuts will be visited through the declaring class.
+      // However, for proxies we need to keep the interface method alive, so we visit its roots.
+      interface_method = mirror::DexCache::GetElementPtrSize(
+          GetDexCacheResolvedMethods(pointer_size),
+          GetDexMethodIndex(),
+          pointer_size);
+      DCHECK(interface_method != nullptr);
+      DCHECK_EQ(interface_method,
+                Runtime::Current()->GetClassLinker()->FindMethodForProxy(klass, this));
+      interface_method->VisitRoots(visitor, pointer_size);
+    }
+    visitor.VisitRoot(declaring_class_.AddressWithoutBarrier());
+    if (!IsNative()) {
+      ProfilingInfo* profiling_info = GetProfilingInfo(pointer_size);
+      if (profiling_info != nullptr) {
+        profiling_info->VisitRoots(visitor);
+      }
+    }
   }
 }
 
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 6f36016..cd38e16 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -292,22 +292,7 @@
         // Unusual case where we were running generated code and an
         // exception was thrown to force the activations to be removed from the
         // stack. Continue execution in the interpreter.
-        self->ClearException();
-        ShadowFrame* shadow_frame =
-            self->PopStackedShadowFrame(StackedShadowFrameType::kDeoptimizationShadowFrame);
-        mirror::Throwable* pending_exception = nullptr;
-        bool from_code = false;
-        self->PopDeoptimizationContext(result, &pending_exception, &from_code);
-        CHECK(!from_code);
-        self->SetTopOfStack(nullptr);
-        self->SetTopOfShadowStack(shadow_frame);
-
-        // Restore the exception that was pending before deoptimization then interpret the
-        // deoptimized frames.
-        if (pending_exception != nullptr) {
-          self->SetException(pending_exception);
-        }
-        interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, from_code, result);
+        self->DeoptimizeWithDeoptimizationException(result);
       }
       if (kLogInvocationStartAndReturn) {
         LOG(INFO) << StringPrintf("Returned '%s' quick code=%p", PrettyMethod(this).c_str(),
diff --git a/runtime/art_method.h b/runtime/art_method.h
index ce23c2a..078a978 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -174,13 +174,13 @@
 
   bool IsProxyMethod() SHARED_REQUIRES(Locks::mutator_lock_);
 
-  bool IsPreverified() {
-    return (GetAccessFlags() & kAccPreverified) != 0;
+  bool SkipAccessChecks() {
+    return (GetAccessFlags() & kAccSkipAccessChecks) != 0;
   }
 
-  void SetPreverified() {
-    DCHECK(!IsPreverified());
-    SetAccessFlags(GetAccessFlags() | kAccPreverified);
+  void SetSkipAccessChecks() {
+    DCHECK(!SkipAccessChecks());
+    SetAccessFlags(GetAccessFlags() | kAccSkipAccessChecks);
   }
 
   // Returns true if this method could be overridden by a default method.
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 31610a3..eb3b7f3 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -150,11 +150,11 @@
 ADD_TEST_EQ(THREAD_ROSALLOC_RUNS_OFFSET,
             art::Thread::RosAllocRunsOffset<__SIZEOF_POINTER__>().Int32Value())
 // Offset of field Thread::tlsPtr_.thread_local_alloc_stack_top.
-#define THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 34 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 16 * __SIZEOF_POINTER__)
 ADD_TEST_EQ(THREAD_LOCAL_ALLOC_STACK_TOP_OFFSET,
             art::Thread::ThreadLocalAllocStackTopOffset<__SIZEOF_POINTER__>().Int32Value())
 // Offset of field Thread::tlsPtr_.thread_local_alloc_stack_end.
-#define THREAD_LOCAL_ALLOC_STACK_END_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 35 * __SIZEOF_POINTER__)
+#define THREAD_LOCAL_ALLOC_STACK_END_OFFSET (THREAD_ROSALLOC_RUNS_OFFSET + 17 * __SIZEOF_POINTER__)
 ADD_TEST_EQ(THREAD_LOCAL_ALLOC_STACK_END_OFFSET,
             art::Thread::ThreadLocalAllocStackEndOffset<__SIZEOF_POINTER__>().Int32Value())
 
@@ -331,21 +331,23 @@
 ADD_TEST_EQ(ROSALLOC_MAX_THREAD_LOCAL_BRACKET_SIZE,
             static_cast<int32_t>(art::gc::allocator::RosAlloc::kMaxThreadLocalBracketSize))
 
-#define ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT 4
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT 3
 ADD_TEST_EQ(ROSALLOC_BRACKET_QUANTUM_SIZE_SHIFT,
-            static_cast<int32_t>(art::gc::allocator::RosAlloc::kBracketQuantumSizeShift))
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSizeShift))
 
-#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK 15
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK 7
 ADD_TEST_EQ(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK,
-            static_cast<int32_t>(art::gc::allocator::RosAlloc::kBracketQuantumSize - 1))
+            static_cast<int32_t>(art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
 
-#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED32 0xfffffff0
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED32 0xfffffff8
 ADD_TEST_EQ(static_cast<uint32_t>(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED32),
-            ~static_cast<uint32_t>(art::gc::allocator::RosAlloc::kBracketQuantumSize - 1))
+            ~static_cast<uint32_t>(
+                art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
 
-#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED64 0xfffffffffffffff0
+#define ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED64 0xfffffffffffffff8
 ADD_TEST_EQ(static_cast<uint64_t>(ROSALLOC_BRACKET_QUANTUM_SIZE_MASK_TOGGLED64),
-            ~static_cast<uint64_t>(art::gc::allocator::RosAlloc::kBracketQuantumSize - 1))
+            ~static_cast<uint64_t>(
+                art::gc::allocator::RosAlloc::kThreadLocalBracketQuantumSize - 1))
 
 #define ROSALLOC_RUN_FREE_LIST_OFFSET 8
 ADD_TEST_EQ(ROSALLOC_RUN_FREE_LIST_OFFSET,
diff --git a/runtime/base/scoped_arena_allocator.cc b/runtime/base/scoped_arena_allocator.cc
index 90c6ee3..7d04fa0 100644
--- a/runtime/base/scoped_arena_allocator.cc
+++ b/runtime/base/scoped_arena_allocator.cc
@@ -99,7 +99,7 @@
   if (UNLIKELY(static_cast<size_t>(top_end_ - ptr) < rounded_bytes)) {
     ptr = AllocateFromNextArena(rounded_bytes);
     CHECK(ptr != nullptr) << "Failed to allocate memory";
-    MEMORY_TOOL_MAKE_NOACCESS(ptr, top_end_);
+    MEMORY_TOOL_MAKE_NOACCESS(ptr, top_end_ - ptr);
   }
   CurrentStats()->RecordAlloc(bytes, kind);
   top_ptr_ = ptr + rounded_bytes;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c80f91a..5278d1b 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -326,6 +326,24 @@
   std::fill_n(find_array_class_cache_, kFindArrayCacheSize, GcRoot<mirror::Class>(nullptr));
 }
 
+void ClassLinker::CheckSystemClass(Thread* self, Handle<mirror::Class> c1, const char* descriptor) {
+  mirror::Class* c2 = FindSystemClass(self, descriptor);
+  if (c2 == nullptr) {
+    LOG(FATAL) << "Could not find class " << descriptor;
+    UNREACHABLE();
+  }
+  if (c1.Get() != c2) {
+    std::ostringstream os1, os2;
+    c1->DumpClass(os1, mirror::Class::kDumpClassFullDetail);
+    c2->DumpClass(os2, mirror::Class::kDumpClassFullDetail);
+    LOG(FATAL) << "InitWithoutImage: Class mismatch for " << descriptor
+               << ". This is most likely the result of a broken build. Make sure that "
+               << "libcore and art projects match.\n\n"
+               << os1.str() << "\n\n" << os2.str();
+    UNREACHABLE();
+  }
+}
+
 bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> boot_class_path,
                                    std::string* error_msg) {
   VLOG(startup) << "ClassLinker::Init";
@@ -517,18 +535,12 @@
 
   // Object, String and DexCache need to be rerun through FindSystemClass to finish init
   mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self);
-  CHECK_EQ(java_lang_Object.Get(), FindSystemClass(self, "Ljava/lang/Object;"));
+  CheckSystemClass(self, java_lang_Object, "Ljava/lang/Object;");
   CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize());
   mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self);
-  mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;");
-  if (java_lang_String.Get() != String_class) {
-    std::ostringstream os1, os2;
-    java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail);
-    String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail);
-    LOG(FATAL) << os1.str() << "\n\n" << os2.str();
-  }
+  CheckSystemClass(self, java_lang_String, "Ljava/lang/String;");
   mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self);
-  CHECK_EQ(java_lang_DexCache.Get(), FindSystemClass(self, "Ljava/lang/DexCache;"));
+  CheckSystemClass(self, java_lang_DexCache, "Ljava/lang/DexCache;");
   CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize());
 
   // Setup the primitive array type classes - can't be done until Object has a vtable.
@@ -538,14 +550,13 @@
   SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B"));
   mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
 
-  CHECK_EQ(char_array_class.Get(), FindSystemClass(self, "[C"));
+  CheckSystemClass(self, char_array_class, "[C");
 
   SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S"));
   mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
 
-  CHECK_EQ(int_array_class.Get(), FindSystemClass(self, "[I"));
-
-  CHECK_EQ(long_array_class.Get(), FindSystemClass(self, "[J"));
+  CheckSystemClass(self, int_array_class, "[I");
+  CheckSystemClass(self, long_array_class, "[J");
 
   SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F"));
   mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
@@ -553,9 +564,12 @@
   SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D"));
   mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
 
-  CHECK_EQ(class_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Class;"));
+  // Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it
+  // in class_table_.
+  CheckSystemClass(self, java_lang_Class, "Ljava/lang/Class;");
 
-  CHECK_EQ(object_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Object;"));
+  CheckSystemClass(self, class_array_class, "[Ljava/lang/Class;");
+  CheckSystemClass(self, object_array_class, "[Ljava/lang/Object;");
 
   // Setup the single, global copy of "iftable".
   auto java_lang_Cloneable = hs.NewHandle(FindSystemClass(self, "Ljava/lang/Cloneable;"));
@@ -577,14 +591,11 @@
            mirror::Class::GetDirectInterface(self, object_array_class, 0));
   CHECK_EQ(java_io_Serializable.Get(),
            mirror::Class::GetDirectInterface(self, object_array_class, 1));
-  // Run Class, ArtField, and ArtMethod through FindSystemClass. This initializes their
-  // dex_cache_ fields and register them in class_table_.
-  CHECK_EQ(java_lang_Class.Get(), FindSystemClass(self, "Ljava/lang/Class;"));
 
   CHECK_EQ(object_array_string.Get(),
            FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass)));
 
-  // End of special init trickery, subsequent classes may be loaded via FindSystemClass.
+  // End of special init trickery, all subsequent classes may be loaded via FindSystemClass.
 
   // Create java.lang.reflect.Proxy root.
   SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;"));
@@ -624,7 +635,7 @@
   // java.lang.ref classes need to be specially flagged, but otherwise are normal classes
   // finish initializing Reference class
   mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self);
-  CHECK_EQ(java_lang_ref_Reference.Get(), FindSystemClass(self, "Ljava/lang/ref/Reference;"));
+  CheckSystemClass(self, java_lang_ref_Reference, "Ljava/lang/ref/Reference;");
   CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize());
   CHECK_EQ(java_lang_ref_Reference->GetClassSize(),
            mirror::Reference::ClassSize(image_pointer_size_));
@@ -1669,6 +1680,22 @@
                                                          forward_dex_cache_arrays);
       class_table->Visit(visitor);
     }
+    // forward_dex_cache_arrays is true iff we copied all of the dex cache arrays into the .bss.
+    // In this case, madvise away the dex cache arrays section of the image to reduce RAM usage and
+    // mark as PROT_NONE to catch any invalid accesses.
+    if (forward_dex_cache_arrays) {
+      const ImageSection& dex_cache_section = header.GetImageSection(
+          ImageHeader::kSectionDexCacheArrays);
+      uint8_t* section_begin = AlignUp(space->Begin() + dex_cache_section.Offset(), kPageSize);
+      uint8_t* section_end = AlignDown(space->Begin() + dex_cache_section.End(), kPageSize);
+      if (section_begin < section_end) {
+        madvise(section_begin, section_end - section_begin, MADV_DONTNEED);
+        mprotect(section_begin, section_end - section_begin, PROT_NONE);
+        VLOG(image) << "Released and protected dex cache array image section from "
+                    << reinterpret_cast<const void*>(section_begin) << "-"
+                    << reinterpret_cast<const void*>(section_end);
+      }
+    }
   }
   VLOG(class_linker) << "Adding image space took " << PrettyDuration(NanoTime() - start_time);
   return true;
@@ -2593,19 +2620,37 @@
   return oat_class.GetOatMethod(oat_method_idx).GetQuickCode();
 }
 
-// Returns true if the method must run with interpreter, false otherwise.
-static bool NeedsInterpreter(ArtMethod* method, const void* quick_code)
-    SHARED_REQUIRES(Locks::mutator_lock_) {
+bool ClassLinker::ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* quick_code) {
+  if (UNLIKELY(method->IsNative() || method->IsProxyMethod())) {
+    return false;
+  }
+
   if (quick_code == nullptr) {
-    // No code: need interpreter.
-    // May return true for native code, in the case of generic JNI
-    // DCHECK(!method->IsNative());
     return true;
   }
-  // If interpreter mode is enabled, every method (except native and proxy) must
-  // be run with interpreter.
-  return Runtime::Current()->GetInstrumentation()->InterpretOnly() &&
-         !method->IsNative() && !method->IsProxyMethod();
+
+  Runtime* runtime = Runtime::Current();
+  instrumentation::Instrumentation* instr = runtime->GetInstrumentation();
+  if (instr->InterpretOnly()) {
+    return true;
+  }
+
+  if (runtime->GetClassLinker()->IsQuickToInterpreterBridge(quick_code)) {
+    // Doing this check avoids doing compiled/interpreter transitions.
+    return true;
+  }
+
+  if (Dbg::IsForcedInterpreterNeededForCalling(Thread::Current(), method)) {
+    // Force the use of interpreter when it is required by the debugger.
+    return true;
+  }
+
+  if (runtime->UseJit() && runtime->GetJit()->JitAtFirstUse()) {
+    // The force JIT uses the interpreter entry point to execute the JIT.
+    return true;
+  }
+
+  return false;
 }
 
 void ClassLinker::FixupStaticTrampolines(mirror::Class* klass) {
@@ -2650,15 +2695,12 @@
       OatFile::OatMethod oat_method = oat_class.GetOatMethod(method_index);
       quick_code = oat_method.GetQuickCode();
     }
-    const bool enter_interpreter = NeedsInterpreter(method, quick_code);
-    if (enter_interpreter) {
+    // Check whether the method is native, in which case it's generic JNI.
+    if (quick_code == nullptr && method->IsNative()) {
+      quick_code = GetQuickGenericJniStub();
+    } else if (ShouldUseInterpreterEntrypoint(method, quick_code)) {
       // Use interpreter entry point.
-      // Check whether the method is native, in which case it's generic JNI.
-      if (quick_code == nullptr && method->IsNative()) {
-        quick_code = GetQuickGenericJniStub();
-      } else {
-        quick_code = GetQuickToInterpreterBridge();
-      }
+      quick_code = GetQuickToInterpreterBridge();
     }
     runtime->GetInstrumentation()->UpdateMethodsCode(method, quick_code);
   }
@@ -2689,7 +2731,8 @@
   }
 
   // Install entry point from interpreter.
-  bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode());
+  const void* quick_code = method->GetEntryPointFromQuickCompiledCode();
+  bool enter_interpreter = ShouldUseInterpreterEntrypoint(method, quick_code);
 
   if (!method->IsInvokable()) {
     EnsureThrowsInvocationError(method);
@@ -2701,20 +2744,18 @@
     // It will be replaced by the proper entry point by ClassLinker::FixupStaticTrampolines
     // after initializing class (see ClassLinker::InitializeClass method).
     method->SetEntryPointFromQuickCompiledCode(GetQuickResolutionStub());
+  } else if (quick_code == nullptr && method->IsNative()) {
+    method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
   } else if (enter_interpreter) {
-    if (!method->IsNative()) {
-      // Set entry point from compiled code if there's no code or in interpreter only mode.
-      method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
-    } else {
-      method->SetEntryPointFromQuickCompiledCode(GetQuickGenericJniStub());
-    }
+    // Set entry point from compiled code if there's no code or in interpreter only mode.
+    method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
   }
 
   if (method->IsNative()) {
     // Unregistering restores the dlsym lookup stub.
     method->UnregisterNative();
 
-    if (enter_interpreter) {
+    if (enter_interpreter || quick_code == nullptr) {
       // We have a native method here without code. Then it should have either the generic JNI
       // trampoline as entrypoint (non-static), or the resolution trampoline (static).
       // TODO: this doesn't handle all the cases where trampolines may be installed.
@@ -3625,7 +3666,7 @@
 
   // Don't attempt to re-verify if already sufficiently verified.
   if (klass->IsVerified()) {
-    EnsurePreverifiedMethods(klass);
+    EnsureSkipAccessChecksMethods(klass);
     return;
   }
   if (klass->IsCompileTimeVerified() && Runtime::Current()->IsAotCompiler()) {
@@ -3648,22 +3689,10 @@
     mirror::Class::SetStatus(klass, mirror::Class::kStatusVerifyingAtRuntime, self);
   }
 
-  // Skip verification if we are forcing a soft fail.
-  // This has to be before the normal verification enabled check,
-  // since technically verification is disabled in this mode.
-  if (UNLIKELY(Runtime::Current()->IsVerificationSoftFail())) {
-    // Force verification to be a 'soft failure'.
-    mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
-    // As this is a fake verified status, make sure the methods are _not_ marked preverified
-    // later.
-    klass->SetPreverified();
-    return;
-  }
-
   // Skip verification if disabled.
   if (!Runtime::Current()->IsVerificationEnabled()) {
     mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
-    EnsurePreverifiedMethods(klass);
+    EnsureSkipAccessChecksMethods(klass);
     return;
   }
 
@@ -3766,9 +3795,9 @@
         mirror::Class::SetStatus(klass, mirror::Class::kStatusRetryVerificationAtRuntime, self);
       } else {
         mirror::Class::SetStatus(klass, mirror::Class::kStatusVerified, self);
-        // As this is a fake verified status, make sure the methods are _not_ marked preverified
-        // later.
-        klass->SetPreverified();
+        // As this is a fake verified status, make sure the methods are _not_ marked
+        // kAccSkipAccessChecks later.
+        klass->SetVerificationAttempted();
       }
     }
   } else {
@@ -3781,19 +3810,26 @@
   }
   if (preverified || verifier_failure == verifier::MethodVerifier::kNoFailure) {
     // Class is verified so we don't need to do any access check on its methods.
-    // Let the interpreter know it by setting the kAccPreverified flag onto each
+    // Let the interpreter know it by setting the kAccSkipAccessChecks flag onto each
     // method.
     // Note: we're going here during compilation and at runtime. When we set the
-    // kAccPreverified flag when compiling image classes, the flag is recorded
+    // kAccSkipAccessChecks flag when compiling image classes, the flag is recorded
     // in the image and is set when loading the image.
-    EnsurePreverifiedMethods(klass);
+
+    if (UNLIKELY(Runtime::Current()->IsVerificationSoftFail())) {
+      // Never skip access checks if the verification soft fail is forced.
+      // Mark the class as having a verification attempt to avoid re-running the verifier.
+      klass->SetVerificationAttempted();
+    } else {
+      EnsureSkipAccessChecksMethods(klass);
+    }
   }
 }
 
-void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) {
-  if (!klass->IsPreverified()) {
-    klass->SetPreverifiedFlagOnAllMethods(image_pointer_size_);
-    klass->SetPreverified();
+void ClassLinker::EnsureSkipAccessChecksMethods(Handle<mirror::Class> klass) {
+  if (!klass->WasVerificationAttempted()) {
+    klass->SetSkipAccessChecksFlagOnAllMethods(image_pointer_size_);
+    klass->SetVerificationAttempted();
   }
 }
 
@@ -3824,7 +3860,7 @@
   }
 
   // We may be running with a preopted oat file but without image. In this case,
-  // we don't skip verification of preverified classes to ensure we initialize
+  // we don't skip verification of skip_access_checks classes to ensure we initialize
   // dex caches with all types resolved during verification.
   // We need to trust image classes, as these might be coming out of a pre-opted, quickened boot
   // image (that we just failed loading), and the verifier can't be run on quickened opcodes when
@@ -3932,8 +3968,9 @@
   }
   DCHECK(klass->GetClass() != nullptr);
   klass->SetObjectSize(sizeof(mirror::Proxy));
-  // Set the class access flags incl. preverified, so we do not try to set the flag on the methods.
-  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccPreverified);
+  // Set the class access flags incl. VerificationAttempted, so we do not try to set the flag on
+  // the methods.
+  klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
   klass->SetClassLoader(soa.Decode<mirror::ClassLoader*>(loader));
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
   klass->SetName(soa.Decode<mirror::String*>(name));
@@ -4104,9 +4141,10 @@
 
 void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) {
   // Create constructor for Proxy that must initialize the method.
-  CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 19u);
+  CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 18u);
   ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->GetDirectMethodUnchecked(
       2, image_pointer_size_);
+  DCHECK_EQ(std::string(proxy_constructor->GetName()), "<init>");
   // Ensure constructor is in dex cache so that we can use the dex cache to look up the overridden
   // constructor method.
   GetClassRoot(kJavaLangReflectProxy)->GetDexCache()->SetResolvedMethod(
@@ -4741,7 +4779,7 @@
                                     bool can_init_parents) {
   DCHECK(c.Get() != nullptr);
   if (c->IsInitialized()) {
-    EnsurePreverifiedMethods(c);
+    EnsureSkipAccessChecksMethods(c);
     return true;
   }
   const bool success = InitializeClass(self, c, can_init_fields, can_init_parents);
@@ -6436,11 +6474,11 @@
     for (ArtMethod* def_method : default_methods) {
       ArtMethod& new_method = *out;
       new_method.CopyFrom(def_method, image_pointer_size_);
-      // Clear the preverified flag if it is present. Since this class hasn't been verified yet it
-      // shouldn't have methods that are preverified.
+      // Clear the kAccSkipAccessChecks flag if it is present. Since this class hasn't been verified
+      // yet it shouldn't have methods that are skipping access checks.
       // TODO This is rather arbitrary. We should maybe support classes where only some of its
-      // methods are preverified.
-      new_method.SetAccessFlags((new_method.GetAccessFlags() | kAccDefault) & ~kAccPreverified);
+      // methods are skip_access_checks.
+      new_method.SetAccessFlags((new_method.GetAccessFlags() | kAccDefault) & ~kAccSkipAccessChecks);
       move_table.emplace(def_method, &new_method);
       ++out;
     }
@@ -6448,11 +6486,11 @@
       ArtMethod& new_method = *out;
       new_method.CopyFrom(conf_method, image_pointer_size_);
       // This is a type of default method (there are default method impls, just a conflict) so mark
-      // this as a default, non-abstract method, since thats what it is. Also clear the preverified
-      // bit since this class hasn't been verified yet it shouldn't have methods that are
-      // preverified.
+      // this as a default, non-abstract method, since thats what it is. Also clear the
+      // kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have
+      // methods that are skipping access checks.
       constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict;
-      constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccPreverified);
+      constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks);
       new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags);
       DCHECK(new_method.IsDefaultConflicting());
       // The actual method might or might not be marked abstract since we just copied it from a
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 9217c32..a9448f7 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -592,6 +592,9 @@
       REQUIRES(!Locks::classlinker_classes_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  static bool ShouldUseInterpreterEntrypoint(ArtMethod* method, const void* quick_code)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   struct DexCacheData {
     // Weak root to the DexCache. Note: Do not decode this unnecessarily or else class unloading may
     // not work properly.
@@ -964,9 +967,10 @@
   void CreateProxyMethod(Handle<mirror::Class> klass, ArtMethod* prototype, ArtMethod* out)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  // Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the
-  // class access flags to determine whether this has been done before.
-  void EnsurePreverifiedMethods(Handle<mirror::Class> c)
+  // Ensures that methods have the kAccSkipAccessChecks bit set. We use the
+  // kAccVerificationAttempted bit on the class access flags to determine whether this has been done
+  // before.
+  void EnsureSkipAccessChecksMethods(Handle<mirror::Class> c)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   mirror::Class* LookupClassFromBootImage(const char* descriptor)
@@ -1024,6 +1028,11 @@
       REQUIRES(!dex_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  // Check that c1 == FindSystemClass(self, descriptor). Abort with class dumps otherwise.
+  void CheckSystemClass(Thread* self, Handle<mirror::Class> c1, const char* descriptor)
+      REQUIRES(!dex_lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   std::vector<const DexFile*> boot_class_path_;
   std::vector<std::unique_ptr<const DexFile>> boot_dex_files_;
 
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 40dfda9..3a0f3e5 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -210,11 +210,10 @@
                                                klass->GetDescriptor(&temp2)));
     if (klass->IsInterface()) {
       EXPECT_TRUE(klass->IsAbstract());
-      if (klass->NumDirectMethods() == 1) {
-        EXPECT_TRUE(klass->GetDirectMethod(0, sizeof(void*))->IsClassInitializer());
-        EXPECT_TRUE(klass->GetDirectMethod(0, sizeof(void*))->IsDirect());
-      } else {
-        EXPECT_EQ(0U, klass->NumDirectMethods());
+      // Check that all direct methods are static (either <clinit> or a regular static method).
+      for (ArtMethod& m : klass->GetDirectMethods(sizeof(void*))) {
+        EXPECT_TRUE(m.IsStatic());
+        EXPECT_TRUE(m.IsDirect());
       }
     } else {
       if (!klass->IsSynthetic()) {
@@ -1126,14 +1125,14 @@
 static void CheckMethod(ArtMethod* method, bool verified)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   if (!method->IsNative() && !method->IsAbstract()) {
-    EXPECT_EQ((method->GetAccessFlags() & kAccPreverified) != 0U, verified)
+    EXPECT_EQ((method->GetAccessFlags() & kAccSkipAccessChecks) != 0U, verified)
         << PrettyMethod(method, true);
   }
 }
 
-static void CheckPreverified(mirror::Class* c, bool preverified)
+static void CheckVerificationAttempted(mirror::Class* c, bool preverified)
     SHARED_REQUIRES(Locks::mutator_lock_) {
-  EXPECT_EQ((c->GetAccessFlags() & kAccPreverified) != 0U, preverified)
+  EXPECT_EQ((c->GetAccessFlags() & kAccVerificationAttempted) != 0U, preverified)
       << "Class " << PrettyClass(c) << " not as expected";
   for (auto& m : c->GetMethods(sizeof(void*))) {
     CheckMethod(&m, preverified);
@@ -1147,7 +1146,7 @@
   ASSERT_TRUE(JavaLangObject != nullptr);
   EXPECT_TRUE(JavaLangObject->IsInitialized()) << "Not testing already initialized class from the "
                                                   "core";
-  CheckPreverified(JavaLangObject, true);
+  CheckVerificationAttempted(JavaLangObject, true);
 }
 
 TEST_F(ClassLinkerTest, Preverified_UninitializedBoot) {
@@ -1160,10 +1159,10 @@
   EXPECT_FALSE(security_manager->IsInitialized()) << "Not testing uninitialized class from the "
                                                      "core";
 
-  CheckPreverified(security_manager.Get(), false);
+  CheckVerificationAttempted(security_manager.Get(), false);
 
   class_linker_->EnsureInitialized(soa.Self(), security_manager, true, true);
-  CheckPreverified(security_manager.Get(), true);
+  CheckVerificationAttempted(security_manager.Get(), true);
 }
 
 TEST_F(ClassLinkerTest, Preverified_App) {
@@ -1175,10 +1174,10 @@
   Handle<mirror::Class> statics(
       hs.NewHandle(class_linker_->FindClass(soa.Self(), "LStatics;", class_loader)));
 
-  CheckPreverified(statics.Get(), false);
+  CheckVerificationAttempted(statics.Get(), false);
 
   class_linker_->EnsureInitialized(soa.Self(), statics, true, true);
-  CheckPreverified(statics.Get(), true);
+  CheckVerificationAttempted(statics.Get(), true);
 }
 
 TEST_F(ClassLinkerTest, IsBootStrapClassLoaded) {
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 7a852e2..ddf2749 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -478,7 +478,7 @@
 
   // Check field access flags.
   std::string error_msg;
-  if (!CheckFieldAccessFlags(access_flags, class_access_flags, &error_msg)) {
+  if (!CheckFieldAccessFlags(idx, access_flags, class_access_flags, &error_msg)) {
     ErrorStringPrintf("%s", error_msg.c_str());
     return false;
   }
@@ -2312,12 +2312,88 @@
   return count <= 1;
 }
 
-bool DexFileVerifier::CheckFieldAccessFlags(uint32_t field_access_flags,
+// Helper functions to retrieve names from the dex file. We do not want to rely on DexFile
+// functionality, as we're still verifying the dex file. begin and header correspond to the
+// underscored variants in the DexFileVerifier.
+
+static std::string GetStringOrError(const uint8_t* const begin,
+                                    const DexFile::Header* const header,
+                                    uint32_t string_idx) {
+  if (header->string_ids_size_ < string_idx) {
+    return "(error)";
+  }
+
+  const DexFile::StringId* string_id =
+      reinterpret_cast<const DexFile::StringId*>(begin + header->string_ids_off_) + string_idx;
+
+  // Assume that the data is OK at this point. String data has been checked at this point.
+
+  const uint8_t* ptr = begin + string_id->string_data_off_;
+  DecodeUnsignedLeb128(&ptr);
+  return reinterpret_cast<const char*>(ptr);
+}
+
+static std::string GetClassOrError(const uint8_t* const begin,
+                                   const DexFile::Header* const header,
+                                   uint32_t class_idx) {
+  if (header->type_ids_size_ < class_idx) {
+    return "(error)";
+  }
+
+  const DexFile::TypeId* type_id =
+      reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx;
+
+  // Assume that the data is OK at this point. Type id offsets have been checked at this point.
+
+  return GetStringOrError(begin, header, type_id->descriptor_idx_);
+}
+
+static std::string GetFieldDescriptionOrError(const uint8_t* const begin,
+                                              const DexFile::Header* const header,
+                                              uint32_t idx) {
+  if (header->field_ids_size_ < idx) {
+    return "(error)";
+  }
+
+  const DexFile::FieldId* field_id =
+      reinterpret_cast<const DexFile::FieldId*>(begin + header->field_ids_off_) + idx;
+
+  // Assume that the data is OK at this point. Field id offsets have been checked at this point.
+
+  std::string class_name = GetClassOrError(begin, header, field_id->class_idx_);
+  std::string field_name = GetStringOrError(begin, header, field_id->name_idx_);
+
+  return class_name + "." + field_name;
+}
+
+static std::string GetMethodDescriptionOrError(const uint8_t* const begin,
+                                               const DexFile::Header* const header,
+                                               uint32_t idx) {
+  if (header->method_ids_size_ < idx) {
+    return "(error)";
+  }
+
+  const DexFile::MethodId* method_id =
+      reinterpret_cast<const DexFile::MethodId*>(begin + header->method_ids_off_) + idx;
+
+  // Assume that the data is OK at this point. Method id offsets have been checked at this point.
+
+  std::string class_name = GetClassOrError(begin, header, method_id->class_idx_);
+  std::string method_name = GetStringOrError(begin, header, method_id->name_idx_);
+
+  return class_name + "." + method_name;
+}
+
+bool DexFileVerifier::CheckFieldAccessFlags(uint32_t idx,
+                                            uint32_t field_access_flags,
                                             uint32_t class_access_flags,
                                             std::string* error_msg) {
   // Generally sort out >16-bit flags.
   if ((field_access_flags & ~kAccJavaFlagsMask) != 0) {
-    *error_msg = StringPrintf("Bad class_data_item field access_flags %x", field_access_flags);
+    *error_msg = StringPrintf("Bad field access_flags for %s: %x(%s)",
+                              GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+                              field_access_flags,
+                              PrettyJavaAccessFlags(field_access_flags).c_str());
     return false;
   }
 
@@ -2334,8 +2410,10 @@
 
   // Fields may have only one of public/protected/final.
   if (!CheckAtMostOneOfPublicProtectedPrivate(field_access_flags)) {
-    *error_msg = StringPrintf("Field may have only one of public/protected/private, %x",
-                              field_access_flags);
+    *error_msg = StringPrintf("Field may have only one of public/protected/private, %s: %x(%s)",
+                              GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+                              field_access_flags,
+                              PrettyJavaAccessFlags(field_access_flags).c_str());
     return false;
   }
 
@@ -2344,14 +2422,19 @@
     // Interface fields must be public final static.
     constexpr uint32_t kPublicFinalStatic = kAccPublic | kAccFinal | kAccStatic;
     if ((field_access_flags & kPublicFinalStatic) != kPublicFinalStatic) {
-      *error_msg = StringPrintf("Interface field is not public final static: %x",
-                                field_access_flags);
+      *error_msg = StringPrintf("Interface field is not public final static, %s: %x(%s)",
+                                GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+                                field_access_flags,
+                                PrettyJavaAccessFlags(field_access_flags).c_str());
       return false;
     }
     // Interface fields may be synthetic, but may not have other flags.
     constexpr uint32_t kDisallowed = ~(kPublicFinalStatic | kAccSynthetic);
     if ((field_access_flags & kFieldAccessFlags & kDisallowed) != 0) {
-      *error_msg = StringPrintf("Interface field has disallowed flag: %x", field_access_flags);
+      *error_msg = StringPrintf("Interface field has disallowed flag, %s: %x(%s)",
+                                GetFieldDescriptionOrError(begin_, header_, idx).c_str(),
+                                field_access_flags,
+                                PrettyJavaAccessFlags(field_access_flags).c_str());
       return false;
     }
     return true;
@@ -2360,7 +2443,8 @@
   // Volatile fields may not be final.
   constexpr uint32_t kVolatileFinal = kAccVolatile | kAccFinal;
   if ((field_access_flags & kVolatileFinal) == kVolatileFinal) {
-    *error_msg = "Fields may not be volatile and final";
+    *error_msg = StringPrintf("Fields may not be volatile and final: %s",
+                              GetFieldDescriptionOrError(begin_, header_, idx).c_str());
     return false;
   }
 
@@ -2410,7 +2494,9 @@
   constexpr uint32_t kAllMethodFlags =
       kAccJavaFlagsMask | kAccConstructor | kAccDeclaredSynchronized;
   if ((method_access_flags & ~kAllMethodFlags) != 0) {
-    *error_msg = StringPrintf("Bad class_data_item method access_flags %x", method_access_flags);
+    *error_msg = StringPrintf("Bad method access_flags for %s: %x",
+                              GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
+                              method_access_flags);
     return false;
   }
 
@@ -2430,7 +2516,8 @@
 
   // Methods may have only one of public/protected/final.
   if (!CheckAtMostOneOfPublicProtectedPrivate(method_access_flags)) {
-    *error_msg = StringPrintf("Method may have only one of public/protected/private, %x",
+    *error_msg = StringPrintf("Method may have only one of public/protected/private, %s: %x",
+                              GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
                               method_access_flags);
     return false;
   }
@@ -2456,8 +2543,10 @@
   // Only methods named "<clinit>" or "<init>" may be marked constructor. Note: we cannot enforce
   // the reverse for backwards compatibility reasons.
   if (((method_access_flags & kAccConstructor) != 0) && !is_constructor) {
-    *error_msg = StringPrintf("Method %" PRIu32 " is marked constructor, but doesn't match name",
-                              method_index);
+    *error_msg =
+        StringPrintf("Method %" PRIu32 "(%s) is marked constructor, but doesn't match name",
+                     method_index,
+                     GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
     return false;
   }
   // Check that the static constructor (= static initializer) is named "<clinit>" and that the
@@ -2465,8 +2554,9 @@
   if (is_constructor) {
     bool is_static = (method_access_flags & kAccStatic) != 0;
     if (is_static ^ is_clinit_by_name) {
-      *error_msg = StringPrintf("Constructor %" PRIu32 " is not flagged correctly wrt/ static.",
-                                method_index);
+      *error_msg = StringPrintf("Constructor %" PRIu32 "(%s) is not flagged correctly wrt/ static.",
+                                method_index,
+                                GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
       return false;
     }
   }
@@ -2474,8 +2564,9 @@
   // and other methods in the virtual methods list.
   bool is_direct = (method_access_flags & (kAccStatic | kAccPrivate)) != 0 || is_constructor;
   if (is_direct != expect_direct) {
-    *error_msg = StringPrintf("Direct/virtual method %" PRIu32 " not in expected list %d",
+    *error_msg = StringPrintf("Direct/virtual method %" PRIu32 "(%s) not in expected list %d",
                               method_index,
+                              GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
                               expect_direct);
     return false;
   }
@@ -2488,14 +2579,17 @@
   if (!has_code) {
     // Only native or abstract methods may not have code.
     if ((method_access_flags & (kAccNative | kAccAbstract)) == 0) {
-      *error_msg = StringPrintf("Method %" PRIu32 " has no code, but is not marked native or "
+      *error_msg = StringPrintf("Method %" PRIu32 "(%s) has no code, but is not marked native or "
                                 "abstract",
-                                method_index);
+                                method_index,
+                                GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
       return false;
     }
     // Constructors must always have code.
     if (is_constructor) {
-      *error_msg = StringPrintf("Constructor %u must not be abstract or native", method_index);
+      *error_msg = StringPrintf("Constructor %u(%s) must not be abstract or native",
+                                method_index,
+                                GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
       return false;
     }
     if ((method_access_flags & kAccAbstract) != 0) {
@@ -2503,14 +2597,15 @@
       constexpr uint32_t kForbidden =
           kAccPrivate | kAccStatic | kAccFinal | kAccNative | kAccStrict | kAccSynchronized;
       if ((method_access_flags & kForbidden) != 0) {
-        *error_msg = StringPrintf("Abstract method %" PRIu32 " has disallowed access flags %x",
-                                  method_index,
-                                  method_access_flags);
+        *error_msg = StringPrintf("Abstract method %" PRIu32 "(%s) has disallowed access flags %x",
+            method_index,
+            GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
+            method_access_flags);
         return false;
       }
       // Abstract methods should be in an abstract class or interface.
       if ((class_access_flags & (kAccInterface | kAccAbstract)) == 0) {
-        LOG(WARNING) << "Method " << PrettyMethod(method_index, *dex_file_)
+        LOG(WARNING) << "Method " << GetMethodDescriptionOrError(begin_, header_, method_index)
                      << " is abstract, but the declaring class is neither abstract nor an "
                      << "interface in dex file "
                      << dex_file_->GetLocation();
@@ -2520,8 +2615,9 @@
     if ((class_access_flags & kAccInterface) != 0) {
       // Interface methods must be public and abstract.
       if ((method_access_flags & (kAccPublic | kAccAbstract)) != (kAccPublic | kAccAbstract)) {
-        *error_msg = StringPrintf("Interface method %" PRIu32 " is not public and abstract",
-                                  method_index);
+        *error_msg = StringPrintf("Interface method %" PRIu32 "(%s) is not public and abstract",
+            method_index,
+            GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
         return false;
       }
       // At this point, we know the method is public and abstract. This means that all the checks
@@ -2533,8 +2629,9 @@
 
   // When there's code, the method must not be native or abstract.
   if ((method_access_flags & (kAccNative | kAccAbstract)) != 0) {
-    *error_msg = StringPrintf("Method %" PRIu32 " has code, but is marked native or abstract",
-                              method_index);
+    *error_msg = StringPrintf("Method %" PRIu32 "(%s) has code, but is marked native or abstract",
+                              method_index,
+                              GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
     return false;
   }
 
@@ -2543,8 +2640,9 @@
     static constexpr uint32_t kInitAllowed =
         kAccPrivate | kAccProtected | kAccPublic | kAccStrict | kAccVarargs | kAccSynthetic;
     if ((method_access_flags & ~kInitAllowed) != 0) {
-      *error_msg = StringPrintf("Constructor %" PRIu32 " flagged inappropriately %x",
+      *error_msg = StringPrintf("Constructor %" PRIu32 "(%s) flagged inappropriately %x",
                                 method_index,
+                                GetMethodDescriptionOrError(begin_, header_, method_index).c_str(),
                                 method_access_flags);
       return false;
     }
diff --git a/runtime/dex_file_verifier.h b/runtime/dex_file_verifier.h
index 6c63749..ddfeea2 100644
--- a/runtime/dex_file_verifier.h
+++ b/runtime/dex_file_verifier.h
@@ -157,9 +157,10 @@
 
   // Check validity of the given access flags, interpreted for a field in the context of a class
   // with the given second access flags.
-  static bool CheckFieldAccessFlags(uint32_t field_access_flags,
-                                    uint32_t class_access_flags,
-                                    std::string* error_msg);
+  bool CheckFieldAccessFlags(uint32_t idx,
+                             uint32_t field_access_flags,
+                             uint32_t class_access_flags,
+                             std::string* error_msg);
   // Check validity of the given method and access flags, in the context of a class with the given
   // second access flags.
   bool CheckMethodAccessFlags(uint32_t method_index,
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index b67af53..558a6ed 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -527,7 +527,7 @@
         ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
         OrMaskToMethodFlags(dex_file, "<init>", kAccStatic);
       },
-      "Constructor 1 is not flagged correctly wrt/ static");
+      "Constructor 1(LMethodFlags;.<init>) is not flagged correctly wrt/ static");
   static constexpr uint32_t kInitNotAllowed[] = {
       kAccFinal,
       kAccSynchronized,
@@ -544,7 +544,7 @@
           ApplyMaskToMethodFlags(dex_file, "<init>", ~kAccPublic);
           OrMaskToMethodFlags(dex_file, "<init>", kInitNotAllowed[i]);
         },
-        "Constructor 1 flagged inappropriately");
+        "Constructor 1(LMethodFlags;.<init>) flagged inappropriately");
   }
 }
 
@@ -742,7 +742,7 @@
 
         ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
       },
-      "Interface method 1 is not public and abstract");
+      "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract");
   VerifyModification(
       kMethodFlagsInterface,
       "method_flags_interface_non_abstract",
@@ -751,7 +751,7 @@
 
         ApplyMaskToMethodFlags(dex_file, "foo", ~kAccAbstract);
       },
-      "Method 1 has no code, but is not marked native or abstract");
+      "Method 1(LInterfaceMethodFlags;.foo) has no code, but is not marked native or abstract");
 
   VerifyModification(
       kMethodFlagsInterface,
@@ -761,7 +761,7 @@
 
         OrMaskToMethodFlags(dex_file, "foo", kAccStatic);
       },
-      "Direct/virtual method 1 not in expected list 0");
+      "Direct/virtual method 1(LInterfaceMethodFlags;.foo) not in expected list 0");
   VerifyModification(
       kMethodFlagsInterface,
       "method_flags_interface_private",
@@ -771,7 +771,7 @@
         ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
         OrMaskToMethodFlags(dex_file, "foo", kAccPrivate);
       },
-      "Direct/virtual method 1 not in expected list 0");
+      "Direct/virtual method 1(LInterfaceMethodFlags;.foo) not in expected list 0");
 
   VerifyModification(
       kMethodFlagsInterface,
@@ -781,7 +781,7 @@
 
         ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
       },
-      "Interface method 1 is not public and abstract");
+      "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract");
   VerifyModification(
       kMethodFlagsInterface,
       "method_flags_interface_protected",
@@ -791,7 +791,7 @@
         ApplyMaskToMethodFlags(dex_file, "foo", ~kAccPublic);
         OrMaskToMethodFlags(dex_file, "foo", kAccProtected);
       },
-      "Interface method 1 is not public and abstract");
+      "Interface method 1(LInterfaceMethodFlags;.foo) is not public and abstract");
 
   constexpr uint32_t kAllMethodFlags =
       kAccPublic |
@@ -831,7 +831,7 @@
           }
           OrMaskToMethodFlags(dex_file, "foo", mask);
         },
-        "Abstract method 1 has disallowed access flags");
+        "Abstract method 1(LInterfaceMethodFlags;.foo) has disallowed access flags");
   }
 }
 
diff --git a/runtime/dex_instruction_utils.h b/runtime/dex_instruction_utils.h
index 1ae2b1b..2849cd8 100644
--- a/runtime/dex_instruction_utils.h
+++ b/runtime/dex_instruction_utils.h
@@ -49,6 +49,16 @@
 
 // NOTE: The following functions disregard quickened instructions.
 
+// By "direct" const we mean to exclude const-string and const-class
+// which load data from somewhere else, i.e. indirectly.
+constexpr bool IsInstructionDirectConst(Instruction::Code opcode) {
+  return Instruction::CONST_4 <= opcode && opcode <= Instruction::CONST_WIDE_HIGH16;
+}
+
+constexpr bool IsInstructionConstWide(Instruction::Code opcode) {
+  return Instruction::CONST_WIDE_16 <= opcode && opcode <= Instruction::CONST_WIDE_HIGH16;
+}
+
 constexpr bool IsInstructionReturn(Instruction::Code opcode) {
   return Instruction::RETURN_VOID <= opcode && opcode <= Instruction::RETURN_OBJECT;
 }
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 0663b7e..7e7d904 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -299,8 +299,10 @@
 }
 
 template<FindFieldType type, bool access_check>
-inline ArtField* FindFieldFromCode(uint32_t field_idx, ArtMethod* referrer,
-                                           Thread* self, size_t expected_size) {
+inline ArtField* FindFieldFromCode(uint32_t field_idx,
+                                   ArtMethod* referrer,
+                                   Thread* self,
+                                   size_t expected_size) REQUIRES(!Roles::uninterruptible_) {
   bool is_primitive;
   bool is_set;
   bool is_static;
@@ -316,7 +318,31 @@
     default:                     is_primitive = true;  is_set = true;  is_static = true;  break;
   }
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  ArtField* resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
+
+  ArtField* resolved_field;
+  if (access_check) {
+    // Slow path: According to JLS 13.4.8, a linkage error may occur if a compile-time
+    // qualifying type of a field and the resolved run-time qualifying type of a field differed
+    // in their static-ness.
+    //
+    // In particular, don't assume the dex instruction already correctly knows if the
+    // real field is static or not. The resolution must not be aware of this.
+    ArtMethod* method = referrer->GetInterfaceMethodIfProxy(sizeof(void*));
+
+    StackHandleScope<2> hs(self);
+    Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(method->GetDexCache()));
+    Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(method->GetClassLoader()));
+
+    resolved_field = class_linker->ResolveFieldJLS(*method->GetDexFile(),
+                                                   field_idx,
+                                                   h_dex_cache,
+                                                   h_class_loader);
+  } else {
+    // Fast path: Verifier already would've called ResolveFieldJLS and we wouldn't
+    // be executing here if there was a static/non-static mismatch.
+    resolved_field = class_linker->ResolveField(field_idx, referrer, is_static);
+  }
+
   if (UNLIKELY(resolved_field == nullptr)) {
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
     return nullptr;  // Failure.
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index b5a55bf..3dfad76 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -273,15 +273,15 @@
     if (outer_method != nullptr) {
       const OatQuickMethodHeader* current_code = outer_method->GetOatQuickMethodHeader(caller_pc);
       if (current_code->IsOptimized()) {
-          uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc);
-          CodeInfo code_info = current_code->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);
-          }
+        uintptr_t native_pc_offset = current_code->NativeQuickPcOffset(caller_pc);
+        CodeInfo code_info = current_code->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) {
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index 1850254..a245f18 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -27,7 +27,36 @@
 
 namespace art {
 
-extern "C" int8_t artGetByteStaticFromCode(uint32_t field_idx, ArtMethod* referrer,
+inline constexpr bool FindFieldTypeIsRead(FindFieldType type) {
+  return type == InstanceObjectRead ||
+         type == InstancePrimitiveRead ||
+         type == StaticObjectRead ||
+         type == StaticPrimitiveRead;
+}
+
+// Helper function to do a null check after trying to resolve the field. Not for statics since obj
+// does not exist there. There is a suspend check, object is a double pointer to update the value
+// in the caller in case it moves.
+template<FindFieldType type, bool kAccessCheck>
+ALWAYS_INLINE static inline ArtField* FindInstanceField(uint32_t field_idx,
+                                                        ArtMethod* referrer,
+                                                        Thread* self,
+                                                        size_t size,
+                                                        mirror::Object** obj)
+    REQUIRES(!Roles::uninterruptible_)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  StackHandleScope<1> hs(self);
+  HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj));
+  ArtField* field = FindFieldFromCode<type, kAccessCheck>(field_idx, referrer, self, size);
+  if (LIKELY(field != nullptr) && UNLIKELY(h.Get() == nullptr)) {
+    ThrowNullPointerExceptionForFieldAccess(field, /*is_read*/FindFieldTypeIsRead(type));
+    return nullptr;
+  }
+  return field;
+}
+
+extern "C" int8_t artGetByteStaticFromCode(uint32_t field_idx,
+                                           ArtMethod* referrer,
                                            Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
@@ -42,7 +71,8 @@
   return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" uint8_t artGetBooleanStaticFromCode(uint32_t field_idx, ArtMethod* referrer,
+extern "C" uint8_t artGetBooleanStaticFromCode(uint32_t field_idx,
+                                               ArtMethod* referrer,
                                                Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
@@ -57,7 +87,8 @@
   return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" int16_t artGetShortStaticFromCode(uint32_t field_idx, ArtMethod* referrer,
+extern "C" int16_t artGetShortStaticFromCode(uint32_t field_idx,
+                                             ArtMethod* referrer,
                                              Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
@@ -125,12 +156,16 @@
                                                    Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
-  ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectRead,
+  ArtField* field = FindFieldFast(field_idx,
+                                  referrer,
+                                  StaticObjectRead,
                                   sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr)) {
     return field->GetObj(field->GetDeclaringClass());
   }
-  field = FindFieldFromCode<StaticObjectRead, true>(field_idx, referrer, self,
+  field = FindFieldFromCode<StaticObjectRead, true>(field_idx,
+                                                    referrer,
+                                                    self,
                                                     sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr)) {
     return field->GetObj(field->GetDeclaringClass());
@@ -138,149 +173,159 @@
   return nullptr;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" int8_t artGetByteInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                             ArtMethod* referrer, Thread* self)
+extern "C" int8_t artGetByteInstanceFromCode(uint32_t field_idx,
+                                             mirror::Object* obj,
+                                             ArtMethod* referrer,
+                                             Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int8_t));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetByte(obj);
   }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
-                                                         sizeof(int8_t));
+  field = FindInstanceField<InstancePrimitiveRead, true>(field_idx,
+                                                         referrer,
+                                                         self,
+                                                         sizeof(int8_t),
+                                                         &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, true);
-    } else {
-      return field->GetByte(obj);
-    }
+    return field->GetByte(obj);
   }
   return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" uint8_t artGetBooleanInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                                 ArtMethod* referrer, Thread* self)
+extern "C" uint8_t artGetBooleanInstanceFromCode(uint32_t field_idx,
+                                                 mirror::Object* obj,
+                                                 ArtMethod* referrer,
+                                                 Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int8_t));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetBoolean(obj);
   }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
-                                                         sizeof(int8_t));
+  field = FindInstanceField<InstancePrimitiveRead, true>(field_idx,
+                                                         referrer,
+                                                         self,
+                                                         sizeof(int8_t),
+                                                         &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, true);
-    } else {
-      return field->GetBoolean(obj);
-    }
+    return field->GetBoolean(obj);
   }
   return 0;  // Will throw exception by checking with Thread::Current.
 }
-extern "C" int16_t artGetShortInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                               ArtMethod* referrer, Thread* self)
+extern "C" int16_t artGetShortInstanceFromCode(uint32_t field_idx,
+                                               mirror::Object* obj,
+                                               ArtMethod* referrer,
+                                               Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int16_t));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetShort(obj);
   }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
-                                                         sizeof(int16_t));
+  field = FindInstanceField<InstancePrimitiveRead, true>(field_idx,
+                                                         referrer,
+                                                         self,
+                                                         sizeof(int16_t),
+                                                         &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, true);
-    } else {
-      return field->GetShort(obj);
-    }
+    return field->GetShort(obj);
   }
   return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" uint16_t artGetCharInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                               ArtMethod* referrer, Thread* self)
+extern "C" uint16_t artGetCharInstanceFromCode(uint32_t field_idx,
+                                               mirror::Object* obj,
+                                               ArtMethod* referrer,
+                                               Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int16_t));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetChar(obj);
   }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
-                                                         sizeof(int16_t));
+  field = FindInstanceField<InstancePrimitiveRead, true>(field_idx,
+                                                         referrer,
+                                                         self,
+                                                         sizeof(int16_t),
+                                                         &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, true);
-    } else {
-      return field->GetChar(obj);
-    }
+    return field->GetChar(obj);
   }
   return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                             ArtMethod* referrer, Thread* self)
+extern "C" uint32_t artGet32InstanceFromCode(uint32_t field_idx,
+                                             mirror::Object* obj,
+                                             ArtMethod* referrer,
+                                             Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int32_t));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->Get32(obj);
   }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
-                                                         sizeof(int32_t));
+  field = FindInstanceField<InstancePrimitiveRead, true>(field_idx,
+                                                         referrer,
+                                                         self,
+                                                         sizeof(int32_t),
+                                                         &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, true);
-    } else {
-      return field->Get32(obj);
-    }
+    return field->Get32(obj);
   }
   return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj,
-                                             ArtMethod* referrer, Thread* self)
+extern "C" uint64_t artGet64InstanceFromCode(uint32_t field_idx,
+                                             mirror::Object* obj,
+                                             ArtMethod* referrer,
+                                             Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveRead, sizeof(int64_t));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->Get64(obj);
   }
-  field = FindFieldFromCode<InstancePrimitiveRead, true>(field_idx, referrer, self,
-                                                         sizeof(int64_t));
+  field = FindInstanceField<InstancePrimitiveRead, true>(field_idx,
+                                                         referrer,
+                                                         self,
+                                                         sizeof(int64_t),
+                                                         &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, true);
-    } else {
-      return field->Get64(obj);
-    }
+    return field->Get64(obj);
   }
   return 0;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" mirror::Object* artGetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
+extern "C" mirror::Object* artGetObjInstanceFromCode(uint32_t field_idx,
+                                                     mirror::Object* obj,
                                                      ArtMethod* referrer,
                                                      Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
-  ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectRead,
+  ArtField* field = FindFieldFast(field_idx,
+                                  referrer,
+                                  InstanceObjectRead,
                                   sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     return field->GetObj(obj);
   }
-  field = FindFieldFromCode<InstanceObjectRead, true>(
-      field_idx, referrer, self, sizeof(mirror::HeapReference<mirror::Object>));
+  field = FindInstanceField<InstanceObjectRead, true>(field_idx,
+                                                      referrer,
+                                                      self,
+                                                      sizeof(mirror::HeapReference<mirror::Object>),
+                                                      &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, true);
-    } else {
-      return field->GetObj(obj);
-    }
+    return field->GetObj(obj);
   }
   return nullptr;  // Will throw exception by checking with Thread::Current.
 }
 
-extern "C" int artSet8StaticFromCode(uint32_t field_idx, uint32_t new_value,
-                                     ArtMethod* referrer, Thread* self)
+extern "C" int artSet8StaticFromCode(uint32_t field_idx,
+                                     uint32_t new_value,
+                                     ArtMethod* referrer,
+                                     Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int8_t));
@@ -310,8 +355,10 @@
   return -1;  // failure
 }
 
-extern "C" int artSet16StaticFromCode(uint32_t field_idx, uint16_t new_value,
-                                      ArtMethod* referrer, Thread* self)
+extern "C" int artSet16StaticFromCode(uint32_t field_idx,
+                                      uint16_t new_value,
+                                      ArtMethod* referrer,
+                                      Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int16_t));
@@ -341,8 +388,10 @@
   return -1;  // failure
 }
 
-extern "C" int artSet32StaticFromCode(uint32_t field_idx, uint32_t new_value,
-                                      ArtMethod* referrer, Thread* self)
+extern "C" int artSet32StaticFromCode(uint32_t field_idx,
+                                      uint32_t new_value,
+                                      ArtMethod* referrer,
+                                      Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int32_t));
@@ -360,8 +409,10 @@
   return -1;  // failure
 }
 
-extern "C" int artSet64StaticFromCode(uint32_t field_idx, ArtMethod* referrer,
-                                      uint64_t new_value, Thread* self)
+extern "C" int artSet64StaticFromCode(uint32_t field_idx,
+                                      ArtMethod* referrer,
+                                      uint64_t new_value,
+                                      Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(int64_t));
@@ -379,11 +430,15 @@
   return -1;  // failure
 }
 
-extern "C" int artSetObjStaticFromCode(uint32_t field_idx, mirror::Object* new_value,
-                                       ArtMethod* referrer, Thread* self)
+extern "C" int artSetObjStaticFromCode(uint32_t field_idx,
+                                       mirror::Object* new_value,
+                                       ArtMethod* referrer,
+                                       Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
-  ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectWrite,
+  ArtField* field = FindFieldFast(field_idx,
+                                  referrer,
+                                  StaticObjectWrite,
                                   sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr)) {
     if (LIKELY(!field->IsPrimitiveType())) {
@@ -392,8 +447,15 @@
       return 0;  // success
     }
   }
-  field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, self,
-                                                     sizeof(mirror::HeapReference<mirror::Object>));
+  {
+    StackHandleScope<1> hs(self);
+    HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&new_value));
+    field = FindFieldFromCode<StaticObjectWrite, true>(
+        field_idx,
+        referrer,
+        self,
+        sizeof(mirror::HeapReference<mirror::Object>));
+  }
   if (LIKELY(field != nullptr)) {
     // Compiled code can't use transactional mode.
     field->SetObj<false>(field->GetDeclaringClass(), new_value);
@@ -402,8 +464,11 @@
   return -1;  // failure
 }
 
-extern "C" int artSet8InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint8_t new_value,
-                                       ArtMethod* referrer, Thread* self)
+extern "C" int artSet8InstanceFromCode(uint32_t field_idx,
+                                       mirror::Object* obj,
+                                       uint8_t new_value,
+                                       ArtMethod* referrer,
+                                       Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int8_t));
@@ -418,31 +483,29 @@
     }
     return 0;  // success
   }
-  {
-    StackHandleScope<1> hs(self);
-    HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
-    field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
-                                                            sizeof(int8_t));
-  }
+  field = FindInstanceField<InstancePrimitiveWrite, true>(field_idx,
+                                                          referrer,
+                                                          self,
+                                                          sizeof(int8_t),
+                                                          &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, false);
+    Primitive::Type type = field->GetTypeAsPrimitiveType();
+    // Compiled code can't use transactional mode.
+    if (type == Primitive::kPrimBoolean) {
+      field->SetBoolean<false>(obj, new_value);
     } else {
-      Primitive::Type type = field->GetTypeAsPrimitiveType();
-      // Compiled code can't use transactional mode.
-      if (type == Primitive::kPrimBoolean) {
-        field->SetBoolean<false>(obj, new_value);
-      } else {
-        field->SetByte<false>(obj, new_value);
-      }
-      return 0;  // success
+      field->SetByte<false>(obj, new_value);
     }
+    return 0;  // success
   }
   return -1;  // failure
 }
 
-extern "C" int artSet16InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint16_t new_value,
-                                        ArtMethod* referrer, Thread* self)
+extern "C" int artSet16InstanceFromCode(uint32_t field_idx,
+                                        mirror::Object* obj,
+                                        uint16_t new_value,
+                                        ArtMethod* referrer,
+                                        Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int16_t));
@@ -457,32 +520,30 @@
     }
     return 0;  // success
   }
-  {
-    StackHandleScope<1> hs(self);
-    HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
-    field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
-                                                            sizeof(int16_t));
-  }
+  field = FindInstanceField<InstancePrimitiveWrite, true>(field_idx,
+                                                          referrer,
+                                                          self,
+                                                          sizeof(int16_t),
+                                                          &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, false);
+    Primitive::Type type = field->GetTypeAsPrimitiveType();
+    // Compiled code can't use transactional mode.
+    if (type == Primitive::kPrimChar) {
+      field->SetChar<false>(obj, new_value);
     } else {
-      Primitive::Type type = field->GetTypeAsPrimitiveType();
-      // Compiled code can't use transactional mode.
-      if (type == Primitive::kPrimChar) {
-        field->SetChar<false>(obj, new_value);
-      } else {
-        DCHECK_EQ(Primitive::kPrimShort, type);
-        field->SetShort<false>(obj, new_value);
-      }
-      return 0;  // success
+      DCHECK_EQ(Primitive::kPrimShort, type);
+      field->SetShort<false>(obj, new_value);
     }
+    return 0;  // success
   }
   return -1;  // failure
 }
 
-extern "C" int artSet32InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint32_t new_value,
-                                        ArtMethod* referrer, Thread* self)
+extern "C" int artSet32InstanceFromCode(uint32_t field_idx,
+                                        mirror::Object* obj,
+                                        uint32_t new_value,
+                                        ArtMethod* referrer,
+                                        Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int32_t));
@@ -491,26 +552,24 @@
     field->Set32<false>(obj, new_value);
     return 0;  // success
   }
-  {
-    StackHandleScope<1> hs(self);
-    HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
-    field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
-                                                            sizeof(int32_t));
-  }
+  field = FindInstanceField<InstancePrimitiveWrite, true>(field_idx,
+                                                          referrer,
+                                                          self,
+                                                          sizeof(int32_t),
+                                                          &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, false);
-    } else {
-      // Compiled code can't use transactional mode.
-      field->Set32<false>(obj, new_value);
-      return 0;  // success
-    }
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(obj, new_value);
+    return 0;  // success
   }
   return -1;  // failure
 }
 
-extern "C" int artSet64InstanceFromCode(uint32_t field_idx, mirror::Object* obj, uint64_t new_value,
-                                        ArtMethod* referrer, Thread* self)
+extern "C" int artSet64InstanceFromCode(uint32_t field_idx,
+                                        mirror::Object* obj,
+                                        uint64_t new_value,
+                                        ArtMethod* referrer,
+                                        Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
   ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(int64_t));
@@ -519,34 +578,45 @@
     field->Set64<false>(obj, new_value);
     return 0;  // success
   }
-  field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, self,
-                                                          sizeof(int64_t));
+  field = FindInstanceField<InstancePrimitiveWrite, true>(field_idx,
+                                                          referrer,
+                                                          self,
+                                                          sizeof(int64_t),
+                                                          &obj);
   if (LIKELY(field != nullptr)) {
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionForFieldAccess(field, false);
-    } else {
-      // Compiled code can't use transactional mode.
-      field->Set64<false>(obj, new_value);
-      return 0;  // success
-    }
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(obj, new_value);
+    return 0;
   }
   return -1;  // failure
 }
 
-extern "C" int artSetObjInstanceFromCode(uint32_t field_idx, mirror::Object* obj,
+extern "C" int artSetObjInstanceFromCode(uint32_t field_idx,
+                                         mirror::Object* obj,
                                          mirror::Object* new_value,
-                                         ArtMethod* referrer, Thread* self)
+                                         ArtMethod* referrer,
+                                         Thread* self)
     SHARED_REQUIRES(Locks::mutator_lock_) {
   ScopedQuickEntrypointChecks sqec(self);
-  ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
+  ArtField* field = FindFieldFast(field_idx,
+                                  referrer,
+                                  InstanceObjectWrite,
                                   sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != nullptr && obj != nullptr)) {
     // Compiled code can't use transactional mode.
     field->SetObj<false>(obj, new_value);
     return 0;  // success
   }
-  field = FindFieldFromCode<InstanceObjectWrite, true>(field_idx, referrer, self,
-                                                       sizeof(mirror::HeapReference<mirror::Object>));
+  {
+    StackHandleScope<2> hs(self);
+    HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj));
+    HandleWrapper<mirror::Object> h_new_value(hs.NewHandleWrapper(&new_value));
+    field = FindFieldFromCode<InstanceObjectWrite, true>(
+        field_idx,
+        referrer,
+        self,
+        sizeof(mirror::HeapReference<mirror::Object>));
+  }
   if (LIKELY(field != nullptr)) {
     if (UNLIKELY(obj == nullptr)) {
       ThrowNullPointerExceptionForFieldAccess(field, false);
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index f87d48d..e72809b 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -127,7 +127,7 @@
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_default_ibase, mterp_alt_ibase, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_alt_ibase, rosalloc_runs, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, rosalloc_runs, thread_local_alloc_stack_top,
-                        sizeof(void*) * kNumRosAllocThreadLocalSizeBrackets);
+                        sizeof(void*) * kNumRosAllocThreadLocalSizeBracketsInThread);
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_top, thread_local_alloc_stack_end,
                         sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_alloc_stack_end, held_mutexes, sizeof(void*));
diff --git a/runtime/gc/allocator/rosalloc-inl.h b/runtime/gc/allocator/rosalloc-inl.h
index 2510514..d1c81e3 100644
--- a/runtime/gc/allocator/rosalloc-inl.h
+++ b/runtime/gc/allocator/rosalloc-inl.h
@@ -62,11 +62,6 @@
   }
   size_t bracket_size;
   size_t idx = SizeToIndexAndBracketSize(size, &bracket_size);
-  DCHECK_EQ(idx, SizeToIndex(size));
-  DCHECK_EQ(bracket_size, IndexToBracketSize(idx));
-  DCHECK_EQ(bracket_size, bracketSizes[idx]);
-  DCHECK_LE(size, bracket_size);
-  DCHECK(size > 512 || bracket_size - size < 16);
   DCHECK_LT(idx, kNumThreadLocalSizeBrackets);
   Run* thread_local_run = reinterpret_cast<Run*>(self->GetRosAllocRun(idx));
   if (kIsDebugBuild) {
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 7d00094..8b125dd 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -638,11 +638,6 @@
   DCHECK_LE(size, kLargeSizeThreshold);
   size_t bracket_size;
   size_t idx = SizeToIndexAndBracketSize(size, &bracket_size);
-  DCHECK_EQ(idx, SizeToIndex(size));
-  DCHECK_EQ(bracket_size, IndexToBracketSize(idx));
-  DCHECK_EQ(bracket_size, bracketSizes[idx]);
-  DCHECK_LE(size, bracket_size);
-  DCHECK(size > 512 || bracket_size - size < 16);
   Locks::mutator_lock_->AssertExclusiveHeld(self);
   void* slot_addr = AllocFromCurrentRunUnlocked(self, idx);
   if (LIKELY(slot_addr != nullptr)) {
@@ -662,14 +657,7 @@
   DCHECK_LE(size, kLargeSizeThreshold);
   size_t bracket_size;
   size_t idx = SizeToIndexAndBracketSize(size, &bracket_size);
-  DCHECK_EQ(idx, SizeToIndex(size));
-  DCHECK_EQ(bracket_size, IndexToBracketSize(idx));
-  DCHECK_EQ(bracket_size, bracketSizes[idx]);
-  DCHECK_LE(size, bracket_size);
-  DCHECK(size > 512 || bracket_size - size < 16);
-
   void* slot_addr;
-
   if (LIKELY(idx < kNumThreadLocalSizeBrackets)) {
     // Use a thread-local run.
     Run* thread_local_run = reinterpret_cast<Run*>(self->GetRosAllocRun(idx));
@@ -881,17 +869,6 @@
   return stream.str();
 }
 
-inline size_t RosAlloc::Run::SlotIndex(Slot* slot) {
-  const uint8_t idx = size_bracket_idx_;
-  const size_t bracket_size = bracketSizes[idx];
-  const size_t offset_from_slot_base = reinterpret_cast<uint8_t*>(slot)
-      - reinterpret_cast<uint8_t*>(FirstSlot());
-  DCHECK_EQ(offset_from_slot_base % bracket_size, static_cast<size_t>(0));
-  size_t slot_idx = offset_from_slot_base / bracket_size;
-  DCHECK_LT(slot_idx, numOfSlots[idx]);
-  return slot_idx;
-}
-
 void RosAlloc::Run::FreeSlot(void* ptr) {
   DCHECK(!IsThreadLocal());
   const uint8_t idx = size_bracket_idx_;
@@ -1647,9 +1624,14 @@
 
 void RosAlloc::Initialize() {
   // bracketSizes.
+  static_assert(kNumRegularSizeBrackets == kNumOfSizeBrackets - 2,
+                "There should be two non-regular brackets");
   for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
-    if (i < kNumOfSizeBrackets - 2) {
-      bracketSizes[i] = 16 * (i + 1);
+    if (i < kNumThreadLocalSizeBrackets) {
+      bracketSizes[i] = kThreadLocalBracketQuantumSize * (i + 1);
+    } else if (i < kNumRegularSizeBrackets) {
+      bracketSizes[i] = kBracketQuantumSize * (i - kNumThreadLocalSizeBrackets + 1) +
+          (kThreadLocalBracketQuantumSize *  kNumThreadLocalSizeBrackets);
     } else if (i == kNumOfSizeBrackets - 2) {
       bracketSizes[i] = 1 * KB;
     } else {
@@ -1662,16 +1644,13 @@
   }
   // numOfPages.
   for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
-    if (i < 4) {
+    if (i < kNumThreadLocalSizeBrackets) {
       numOfPages[i] = 1;
-    } else if (i < 8) {
-      numOfPages[i] = 1;
-    } else if (i < 16) {
+    } else if (i < (kNumThreadLocalSizeBrackets + kNumRegularSizeBrackets) / 2) {
       numOfPages[i] = 4;
-    } else if (i < 32) {
+    } else if (i < kNumRegularSizeBrackets) {
       numOfPages[i] = 8;
-    } else if (i == 32) {
-      DCHECK_EQ(i, kNumOfSizeBrackets - 2);
+    } else if (i == kNumOfSizeBrackets - 2) {
       numOfPages[i] = 16;
     } else {
       DCHECK_EQ(i, kNumOfSizeBrackets - 1);
@@ -1701,8 +1680,8 @@
       size_t tmp_header_size = (tmp_unaligned_header_size % bracket_size == 0) ?
           tmp_unaligned_header_size :
           tmp_unaligned_header_size + (bracket_size - tmp_unaligned_header_size % bracket_size);
-      DCHECK_EQ(tmp_header_size % bracket_size, static_cast<size_t>(0));
-      DCHECK_EQ(tmp_header_size % 8, static_cast<size_t>(0));
+      DCHECK_EQ(tmp_header_size % bracket_size, 0U);
+      DCHECK_EQ(tmp_header_size % sizeof(uint64_t), 0U);
       if (tmp_slots_size + tmp_header_size <= run_size) {
         // Found the right number of slots, that is, there was enough
         // space for the header (including the bit maps.)
@@ -1711,8 +1690,8 @@
         break;
       }
     }
-    DCHECK_GT(num_of_slots, 0U);
-    DCHECK_GT(header_size, 0U);
+    DCHECK_GT(num_of_slots, 0U) << i;
+    DCHECK_GT(header_size, 0U) << i;
     // Add the padding for the alignment remainder.
     header_size += run_size % bracket_size;
     DCHECK_EQ(header_size + num_of_slots * bracket_size, run_size);
@@ -1723,7 +1702,7 @@
                 << ", headerSizes[" << i << "]=" << headerSizes[i];
     }
   }
-  // Fill the alloc bitmap so nobody can successfully allocate from it.
+  // Set up the dedicated full run so that nobody can successfully allocate from it.
   if (kIsDebugBuild) {
     dedicated_full_run_->magic_num_ = kMagicNum;
   }
@@ -1735,6 +1714,9 @@
 
   // The smallest bracket size must be at least as large as the sizeof(Slot).
   DCHECK_LE(sizeof(Slot), bracketSizes[0]) << "sizeof(Slot) <= the smallest bracket size";
+  // Check the invariants between the max bracket sizes and the number of brackets.
+  DCHECK_EQ(kMaxThreadLocalBracketSize, bracketSizes[kNumThreadLocalSizeBrackets - 1]);
+  DCHECK_EQ(kMaxRegularBracketSize, bracketSizes[kNumRegularSizeBrackets - 1]);
 }
 
 void RosAlloc::BytesAllocatedCallback(void* start ATTRIBUTE_UNUSED, void* end ATTRIBUTE_UNUSED,
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 3ce3d63..a472a8b 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -366,7 +366,7 @@
     static size_t fixed_header_size() {
       return sizeof(Run);
     }
-    Slot* FirstSlot() {
+    Slot* FirstSlot() const {
       const uint8_t idx = size_bracket_idx_;
       return reinterpret_cast<Slot*>(reinterpret_cast<uintptr_t>(this) + headerSizes[idx]);
     }
@@ -473,7 +473,16 @@
       DCHECK_LT(slot_idx, numOfSlots[idx]);
       return reinterpret_cast<Slot*>(ptr);
     }
-    size_t SlotIndex(Slot* slot);
+    size_t SlotIndex(Slot* slot) const {
+      const uint8_t idx = size_bracket_idx_;
+      const size_t bracket_size = bracketSizes[idx];
+      const size_t offset_from_slot_base = reinterpret_cast<uint8_t*>(slot)
+          - reinterpret_cast<uint8_t*>(FirstSlot());
+      DCHECK_EQ(offset_from_slot_base % bracket_size, 0U);
+      size_t slot_idx = offset_from_slot_base / bracket_size;
+      DCHECK_LT(slot_idx, numOfSlots[idx]);
+      return slot_idx;
+    }
 
     // TODO: DISALLOW_COPY_AND_ASSIGN(Run);
   };
@@ -482,10 +491,8 @@
   static constexpr uint8_t kMagicNum = 42;
   // The magic number for free pages.
   static constexpr uint8_t kMagicNumFree = 43;
-  // The number of size brackets. Sync this with the length of Thread::rosalloc_runs_.
-  static constexpr size_t kNumOfSizeBrackets = kNumRosAllocThreadLocalSizeBrackets;
-  // The number of smaller size brackets that are the quantum size apart.
-  static constexpr size_t kNumOfQuantumSizeBrackets = 32;
+  // The number of size brackets.
+  static constexpr size_t kNumOfSizeBrackets = 42;
   // The sizes (the slot sizes, in bytes) of the size brackets.
   static size_t bracketSizes[kNumOfSizeBrackets];
   // The numbers of pages that are used for runs for each size bracket.
@@ -506,16 +513,23 @@
   }
   // Returns the index of the size bracket from the bracket size.
   static size_t BracketSizeToIndex(size_t size) {
-    DCHECK(16 <= size && ((size < 1 * KB && size % 16 == 0) || size == 1 * KB || size == 2 * KB));
+    DCHECK(8 <= size &&
+           ((size <= kMaxThreadLocalBracketSize && size % kThreadLocalBracketQuantumSize == 0) ||
+            (size <= kMaxRegularBracketSize && size % kBracketQuantumSize == 0) ||
+            size == 1 * KB || size == 2 * KB));
     size_t idx;
     if (UNLIKELY(size == 1 * KB)) {
       idx = kNumOfSizeBrackets - 2;
     } else if (UNLIKELY(size == 2 * KB)) {
       idx = kNumOfSizeBrackets - 1;
+    } else if (LIKELY(size <= kMaxThreadLocalBracketSize)) {
+      DCHECK_EQ(size % kThreadLocalBracketQuantumSize, 0U);
+      idx = size / kThreadLocalBracketQuantumSize - 1;
     } else {
-      DCHECK(size < 1 * KB);
-      DCHECK_EQ(size % 16, static_cast<size_t>(0));
-      idx = size / 16 - 1;
+      DCHECK(size <= kMaxRegularBracketSize);
+      DCHECK_EQ((size - kMaxThreadLocalBracketSize) % kBracketQuantumSize, 0U);
+      idx = ((size - kMaxThreadLocalBracketSize) / kBracketQuantumSize - 1)
+          + kNumThreadLocalSizeBrackets;
     }
     DCHECK(bracketSizes[idx] == size);
     return idx;
@@ -530,51 +544,64 @@
   // Rounds up the size up the nearest bracket size.
   static size_t RoundToBracketSize(size_t size) {
     DCHECK(size <= kLargeSizeThreshold);
-    if (LIKELY(size <= 512)) {
-      return RoundUp(size, 16);
-    } else if (512 < size && size <= 1 * KB) {
+    if (LIKELY(size <= kMaxThreadLocalBracketSize)) {
+      return RoundUp(size, kThreadLocalBracketQuantumSize);
+    } else if (size <= kMaxRegularBracketSize) {
+      return RoundUp(size, kBracketQuantumSize);
+    } else if (UNLIKELY(size <= 1 * KB)) {
       return 1 * KB;
     } else {
-      DCHECK(1 * KB < size && size <= 2 * KB);
+      DCHECK_LE(size, 2 * KB);
       return 2 * KB;
     }
   }
   // Returns the size bracket index from the byte size with rounding.
   static size_t SizeToIndex(size_t size) {
     DCHECK(size <= kLargeSizeThreshold);
-    if (LIKELY(size <= 512)) {
-      return RoundUp(size, 16) / 16 - 1;
-    } else if (512 < size && size <= 1 * KB) {
+    if (LIKELY(size <= kMaxThreadLocalBracketSize)) {
+      return RoundUp(size, kThreadLocalBracketQuantumSize) / kThreadLocalBracketQuantumSize - 1;
+    } else if (size <= kMaxRegularBracketSize) {
+      return (RoundUp(size, kBracketQuantumSize) - kMaxThreadLocalBracketSize) / kBracketQuantumSize
+          - 1 + kNumThreadLocalSizeBrackets;
+    } else if (size <= 1 * KB) {
       return kNumOfSizeBrackets - 2;
     } else {
-      DCHECK(1 * KB < size && size <= 2 * KB);
+      DCHECK_LE(size, 2 * KB);
       return kNumOfSizeBrackets - 1;
     }
   }
   // A combination of SizeToIndex() and RoundToBracketSize().
   static size_t SizeToIndexAndBracketSize(size_t size, size_t* bracket_size_out) {
     DCHECK(size <= kLargeSizeThreshold);
-    if (LIKELY(size <= 512)) {
-      size_t bracket_size = RoundUp(size, 16);
-      *bracket_size_out = bracket_size;
-      size_t idx = bracket_size / 16 - 1;
-      DCHECK_EQ(bracket_size, IndexToBracketSize(idx));
-      return idx;
-    } else if (512 < size && size <= 1 * KB) {
-      size_t bracket_size = 1024;
-      *bracket_size_out = bracket_size;
-      size_t idx = kNumOfSizeBrackets - 2;
-      DCHECK_EQ(bracket_size, IndexToBracketSize(idx));
-      return idx;
+    size_t idx;
+    size_t bracket_size;
+    if (LIKELY(size <= kMaxThreadLocalBracketSize)) {
+      bracket_size = RoundUp(size, kThreadLocalBracketQuantumSize);
+      idx = bracket_size / kThreadLocalBracketQuantumSize - 1;
+    } else if (size <= kMaxRegularBracketSize) {
+      bracket_size = RoundUp(size, kBracketQuantumSize);
+      idx = ((bracket_size - kMaxThreadLocalBracketSize) / kBracketQuantumSize - 1)
+          + kNumThreadLocalSizeBrackets;
+    } else if (size <= 1 * KB) {
+      bracket_size = 1 * KB;
+      idx = kNumOfSizeBrackets - 2;
     } else {
-      DCHECK(1 * KB < size && size <= 2 * KB);
-      size_t bracket_size = 2048;
-      *bracket_size_out = bracket_size;
-      size_t idx = kNumOfSizeBrackets - 1;
-      DCHECK_EQ(bracket_size, IndexToBracketSize(idx));
-      return idx;
+      DCHECK(size <= 2 * KB);
+      bracket_size = 2 * KB;
+      idx = kNumOfSizeBrackets - 1;
     }
+    DCHECK_EQ(idx, SizeToIndex(size)) << idx;
+    DCHECK_EQ(bracket_size, IndexToBracketSize(idx)) << idx;
+    DCHECK_EQ(bracket_size, bracketSizes[idx]) << idx;
+    DCHECK_LE(size, bracket_size) << idx;
+    DCHECK(size > kMaxRegularBracketSize ||
+           (size <= kMaxThreadLocalBracketSize &&
+            bracket_size - size < kThreadLocalBracketQuantumSize) ||
+           (size <= kMaxRegularBracketSize && bracket_size - size < kBracketQuantumSize)) << idx;
+    *bracket_size_out = bracket_size;
+    return idx;
   }
+
   // Returns the page map index from an address. Requires that the
   // address is page size aligned.
   size_t ToPageMapIndex(const void* addr) const {
@@ -630,18 +657,37 @@
   // The default value for page_release_size_threshold_.
   static constexpr size_t kDefaultPageReleaseSizeThreshold = 4 * MB;
 
-  // We use thread-local runs for the size Brackets whose indexes
+  // We use thread-local runs for the size brackets whose indexes
   // are less than this index. We use shared (current) runs for the rest.
-  static const size_t kNumThreadLocalSizeBrackets = 8;
+  // Sync this with the length of Thread::rosalloc_runs_.
+  static const size_t kNumThreadLocalSizeBrackets = 16;
+  static_assert(kNumThreadLocalSizeBrackets == kNumRosAllocThreadLocalSizeBracketsInThread,
+                "Mismatch between kNumThreadLocalSizeBrackets and "
+                "kNumRosAllocThreadLocalSizeBracketsInThread");
 
   // The size of the largest bracket we use thread-local runs for.
   // This should be equal to bracketSizes[kNumThreadLocalSizeBrackets - 1].
   static const size_t kMaxThreadLocalBracketSize = 128;
 
-  // The bracket size increment for the brackets of size <= 512 bytes.
+  // We use regular (8 or 16-bytes increment) runs for the size brackets whose indexes are less than
+  // this index.
+  static const size_t kNumRegularSizeBrackets = 40;
+
+  // The size of the largest regular (8 or 16-byte increment) bracket. Non-regular brackets are the
+  // 1 KB and the 2 KB brackets. This should be equal to bracketSizes[kNumRegularSizeBrackets - 1].
+  static const size_t kMaxRegularBracketSize = 512;
+
+  // The bracket size increment for the thread-local brackets (<= kMaxThreadLocalBracketSize bytes).
+  static constexpr size_t kThreadLocalBracketQuantumSize = 8;
+
+  // Equal to Log2(kThreadLocalBracketQuantumSize).
+  static constexpr size_t kThreadLocalBracketQuantumSizeShift = 3;
+
+  // The bracket size increment for the non-thread-local, regular brackets (of size <=
+  // kMaxRegularBracketSize bytes and > kMaxThreadLocalBracketSize bytes).
   static constexpr size_t kBracketQuantumSize = 16;
 
-  // Equal to Log2(kQuantumBracketSizeIncrement).
+  // Equal to Log2(kBracketQuantumSize).
   static constexpr size_t kBracketQuantumSizeShift = 4;
 
  private:
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index c8e913c..ae41226 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -42,6 +42,8 @@
   kCollectorTypeCC,
   // Instrumentation critical section fake collector.
   kCollectorTypeInstrumentation,
+  // Fake collector for adding or removing application image spaces.
+  kCollectorTypeAddRemoveAppImageSpace,
   // A homogeneous space compaction collector used in background transition
   // when both foreground and background collector are CMS.
   kCollectorTypeHomogeneousSpaceCompact,
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index 84243df..679432b 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -34,6 +34,7 @@
     case kGcCauseHomogeneousSpaceCompact: return "HomogeneousSpaceCompact";
     case kGcCauseTrim: return "HeapTrim";
     case kGcCauseInstrumentation: return "Instrumentation";
+    case kGcCauseAddRemoveAppImageSpace: return "AddRemoveAppImageSpace";
     default:
       LOG(FATAL) << "Unreachable";
       UNREACHABLE();
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index 34c7766..c6b505c 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -41,6 +41,8 @@
   kGcCauseTrim,
   // Not a real GC cause, used to implement exclusion between GC and instrumentation.
   kGcCauseInstrumentation,
+  // Not a real GC cause, used to add or remove app image spaces.
+  kGcCauseAddRemoveAppImageSpace,
   // GC triggered for background transition when both foreground and background collector are CMS.
   kGcCauseHomogeneousSpaceCompact,
 };
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 136b793..3c9312f 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -271,7 +271,7 @@
     // The loaded spaces. Secondary images may fail to load, in which case we need to remove
     // already added spaces.
     std::vector<space::Space*> added_image_spaces;
-
+    uint8_t* const original_requested_alloc_space_begin = requested_alloc_space_begin;
     for (size_t index = 0; index < image_file_names.size(); ++index) {
       std::string& image_name = image_file_names[index];
       ATRACE_BEGIN("ImageSpace::Create");
@@ -320,7 +320,7 @@
           delete loaded_space;
         }
         boot_image_spaces_.clear();
-        requested_alloc_space_begin = nullptr;
+        requested_alloc_space_begin = original_requested_alloc_space_begin;
         break;
       }
     }
@@ -2622,6 +2622,10 @@
     }
     if (collector != mark_compact_collector_ && collector != concurrent_copying_collector_) {
       temp_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
+      if (kIsDebugBuild) {
+        // Try to read each page of the memory map in case mprotect didn't work properly b/19894268.
+        temp_space_->GetMemMap()->TryReadable();
+      }
       CHECK(temp_space_->IsEmpty());
     }
     gc_type = collector::kGcTypeFull;  // TODO: Not hard code this in.
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index d185e63..0c06c38 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -305,12 +305,6 @@
   std::string output_image_filename_arg("--output-image-file=");
   output_image_filename_arg += dest_filename;
 
-  std::string input_oat_location_arg("--input-oat-location=");
-  input_oat_location_arg += ImageHeader::GetOatLocationFromImageLocation(image_location);
-
-  std::string output_oat_filename_arg("--output-oat-file=");
-  output_oat_filename_arg += ImageHeader::GetOatLocationFromImageLocation(dest_filename);
-
   std::string instruction_set_arg("--instruction-set=");
   instruction_set_arg += GetInstructionSetString(isa);
 
@@ -324,9 +318,6 @@
   argv.push_back(input_image_location_arg);
   argv.push_back(output_image_filename_arg);
 
-  argv.push_back(input_oat_location_arg);
-  argv.push_back(output_oat_filename_arg);
-
   argv.push_back(instruction_set_arg);
   argv.push_back(base_offset_arg);
 
@@ -925,7 +916,7 @@
     if (fixup_heap_objects_) {
       method->UpdateObjectsForImageRelocation(ForwardObjectAdapter(this));
     }
-    method->UpdateEntrypoints(ForwardCodeAdapter(this));
+    method->UpdateEntrypoints<kWithoutReadBarrier>(ForwardCodeAdapter(this));
   }
 
  private:
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 3eff7fc..4fd3c78 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -27,6 +27,7 @@
 #include "unstarted_runtime.h"
 #include "mterp/mterp.h"
 #include "jit/jit.h"
+#include "jit/jit_code_cache.h"
 
 namespace art {
 namespace interpreter {
@@ -293,9 +294,10 @@
                                         method, 0);
     }
 
-    if (UNLIKELY(Runtime::Current()->GetJit() != nullptr &&
-                 Runtime::Current()->GetJit()->JitAtFirstUse() &&
-                 method->HasAnyCompiledCode())) {
+    jit::Jit* jit = Runtime::Current()->GetJit();
+    if (UNLIKELY(jit != nullptr &&
+                 jit->JitAtFirstUse() &&
+                 jit->GetCodeCache()->ContainsMethod(method))) {
       JValue result;
 
       // Pop the shadow frame before calling into compiled code.
@@ -311,7 +313,7 @@
   shadow_frame.GetMethod()->GetDeclaringClass()->AssertInitializedOrInitializingInThread(self);
 
   bool transaction_active = Runtime::Current()->IsActiveTransaction();
-  if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) {
+  if (LIKELY(shadow_frame.GetMethod()->SkipAccessChecks())) {
     // Enter the "without access check" interpreter.
     if (kInterpreterImplKind == kMterpImplKind) {
       if (transaction_active) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 6c9cc70..cbaa817 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -20,6 +20,7 @@
 
 #include "debugger.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
+#include "jit/jit.h"
 #include "mirror/array-inl.h"
 #include "stack.h"
 #include "unstarted_runtime.h"
@@ -501,23 +502,6 @@
                                 uint32_t (&arg)[kVarArgMax],
                                 uint32_t vregC) ALWAYS_INLINE;
 
-SHARED_REQUIRES(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);
-}
-
 void ArtInterpreterToCompiledCodeBridge(Thread* self,
                                         const DexFile::CodeItem* code_item,
                                         ShadowFrame* shadow_frame,
@@ -637,17 +621,25 @@
         self, new_shadow_frame, StackedShadowFrameType::kShadowFrameUnderConstruction);
     self->EndAssertNoThreadSuspension(old_cause);
 
+    // ArtMethod here is needed to check type information of the call site against the callee.
+    // Type information is retrieved from a DexFile/DexCache for that respective declared method.
+    //
+    // As a special case for proxy methods, which are not dex-backed,
+    // we have to retrieve type information from the proxy's method
+    // interface method instead (which is dex backed since proxies are never interfaces).
+    ArtMethod* method = new_shadow_frame->GetMethod()->GetInterfaceMethodIfProxy(sizeof(void*));
+
     // We need to do runtime check on reference assignment. We need to load the shorty
     // to get the exact type of each reference argument.
-    const DexFile::TypeList* params = new_shadow_frame->GetMethod()->GetParameterTypeList();
+    const DexFile::TypeList* params = method->GetParameterTypeList();
     uint32_t shorty_len = 0;
-    const char* shorty = new_shadow_frame->GetMethod()->GetShorty(&shorty_len);
+    const char* shorty = method->GetShorty(&shorty_len);
 
     // 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()) {
+    if (!method->IsStatic()) {
       size_t receiver_reg = is_range ? vregC : arg[0];
       new_shadow_frame->SetVRegReference(dest_reg, shadow_frame.GetVRegReference(receiver_reg));
       ++dest_reg;
@@ -667,7 +659,7 @@
           if (do_assignability_check && o != nullptr) {
             size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
             Class* arg_type =
-                new_shadow_frame->GetMethod()->GetClassFromTypeIndex(
+                method->GetClassFromTypeIndex(
                     params->GetTypeItem(shorty_pos).type_idx_, true /* resolve */, pointer_size);
             if (arg_type == nullptr) {
               CHECK(self->IsExceptionPending());
@@ -728,7 +720,10 @@
 
   // Do the call now.
   if (LIKELY(Runtime::Current()->IsStarted())) {
-    if (NeedsInterpreter(self, new_shadow_frame)) {
+    ArtMethod* target = new_shadow_frame->GetMethod();
+    if (ClassLinker::ShouldUseInterpreterEntrypoint(
+        target,
+        target->GetEntryPointFromQuickCompiledCode())) {
       ArtInterpreterToInterpreterBridge(self, code_item, new_shadow_frame, result);
     } else {
       ArtInterpreterToCompiledCodeBridge(self, code_item, new_shadow_frame, result);
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index 940d344..ca8598e 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -21,6 +21,7 @@
 #include "base/stl_util.h"  // MakeUnique
 #include "experimental_flags.h"
 #include "interpreter_common.h"
+#include "jit/jit.h"
 #include "safe_math.h"
 
 #include <memory>  // std::unique_ptr
@@ -63,10 +64,15 @@
   currentHandlersTable = handlersTable[ \
       Runtime::Current()->GetInstrumentation()->GetInterpreterHandlerTable()]
 
-#define BRANCH_INSTRUMENTATION(offset) \
-  do { \
+#define BRANCH_INSTRUMENTATION(offset)                                                            \
+  do {                                                                                            \
+    ArtMethod* method = shadow_frame.GetMethod();                                                 \
     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation(); \
-    instrumentation->Branch(self, shadow_frame.GetMethod(), dex_pc, offset); \
+    instrumentation->Branch(self, method, dex_pc, offset);                                        \
+    JValue result;                                                                                \
+    if (jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, &result)) {             \
+      return result;                                                                              \
+    }                                                                                             \
   } while (false)
 
 #define UNREACHABLE_CODE_CHECK()                \
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index f606978..25dbab2 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -17,6 +17,7 @@
 #include "base/stl_util.h"  // MakeUnique
 #include "experimental_flags.h"
 #include "interpreter_common.h"
+#include "jit/jit.h"
 #include "safe_math.h"
 
 #include <memory>  // std::unique_ptr
@@ -69,9 +70,14 @@
     }                                                                                           \
   } while (false)
 
-#define BRANCH_INSTRUMENTATION(offset) \
-  do { \
-    instrumentation->Branch(self, shadow_frame.GetMethod(), dex_pc, offset); \
+#define BRANCH_INSTRUMENTATION(offset)                                                         \
+  do {                                                                                         \
+    ArtMethod* method = shadow_frame.GetMethod();                                              \
+    instrumentation->Branch(self, method, dex_pc, offset);                                     \
+    JValue result;                                                                             \
+    if (jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, &result)) {          \
+      return result;                                                                           \
+    }                                                                                          \
   } while (false)
 
 static bool IsExperimentalInstructionEnabled(const Instruction *inst) {
diff --git a/runtime/interpreter/mterp/arm/binopWide.S b/runtime/interpreter/mterp/arm/binopWide.S
index 57d43c6..1d511ec 100644
--- a/runtime/interpreter/mterp/arm/binopWide.S
+++ b/runtime/interpreter/mterp/arm/binopWide.S
@@ -16,10 +16,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -28,8 +28,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
     $preinstr                           @ optional op; may set condition codes
     $instr                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/arm/binopWide2addr.S b/runtime/interpreter/mterp/arm/binopWide2addr.S
index 4e855f2..81db48b 100644
--- a/runtime/interpreter/mterp/arm/binopWide2addr.S
+++ b/runtime/interpreter/mterp/arm/binopWide2addr.S
@@ -15,17 +15,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if $chkzero
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
     $preinstr                           @ optional op; may set condition codes
     $instr                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/arm/fbinopWide.S b/runtime/interpreter/mterp/arm/fbinopWide.S
index 1bed817..ca13bfb 100644
--- a/runtime/interpreter/mterp/arm/fbinopWide.S
+++ b/runtime/interpreter/mterp/arm/fbinopWide.S
@@ -14,9 +14,9 @@
     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &vBB
     fldd    d1, [r3]                    @ d1<- vCC
     fldd    d0, [r2]                    @ d0<- vBB
-
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     $instr                              @ s2<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vAA
     fstd    d2, [r9]                    @ vAA<- d2
diff --git a/runtime/interpreter/mterp/arm/fbinopWide2addr.S b/runtime/interpreter/mterp/arm/fbinopWide2addr.S
index 9f56986..4e7401d 100644
--- a/runtime/interpreter/mterp/arm/fbinopWide2addr.S
+++ b/runtime/interpreter/mterp/arm/fbinopWide2addr.S
@@ -12,10 +12,10 @@
     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &vB
     and     r9, r9, #15                 @ r9<- A
     fldd    d1, [r3]                    @ d1<- vB
+    CLEAR_SHADOW_PAIR r9, ip, r0        @ Zero out shadow regs
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     fldd    d0, [r9]                    @ d0<- vA
-
     $instr                              @ d2<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     fstd    d2, [r9]                    @ vAA<- d2
diff --git a/runtime/interpreter/mterp/arm/funopWider.S b/runtime/interpreter/mterp/arm/funopWider.S
index 087a1f2..450ba3a 100644
--- a/runtime/interpreter/mterp/arm/funopWider.S
+++ b/runtime/interpreter/mterp/arm/funopWider.S
@@ -12,6 +12,7 @@
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     and     r9, r9, #15                 @ r9<- A
     $instr                              @ d0<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     fstd    d0, [r9]                    @ vA<- d0
diff --git a/runtime/interpreter/mterp/arm/header.S b/runtime/interpreter/mterp/arm/header.S
index 14319d9..b2370bf 100644
--- a/runtime/interpreter/mterp/arm/header.S
+++ b/runtime/interpreter/mterp/arm/header.S
@@ -263,6 +263,19 @@
     str     \reg, [rFP, \vreg, lsl #2]
     str     \reg, [rREFS, \vreg, lsl #2]
 .endm
+.macro SET_VREG_SHADOW reg, vreg
+    str     \reg, [rREFS, \vreg, lsl #2]
+.endm
+
+/*
+ * Clear the corresponding shadow regs for a vreg pair
+ */
+.macro CLEAR_SHADOW_PAIR vreg, tmp1, tmp2
+    mov     \tmp1, #0
+    add     \tmp2, \vreg, #1
+    SET_VREG_SHADOW \tmp1, \vreg
+    SET_VREG_SHADOW \tmp1, \tmp2
+.endm
 
 /*
  * Convert a virtual register index into an address.
diff --git a/runtime/interpreter/mterp/arm/op_aget_wide.S b/runtime/interpreter/mterp/arm/op_aget_wide.S
index caaec71..e1430b4 100644
--- a/runtime/interpreter/mterp/arm/op_aget_wide.S
+++ b/runtime/interpreter/mterp/arm/op_aget_wide.S
@@ -10,6 +10,7 @@
     mov     r3, r0, lsr #8              @ r3<- CC
     GET_VREG r0, r2                     @ r0<- vBB (array object)
     GET_VREG r1, r3                     @ r1<- vCC (requested index)
+    CLEAR_SHADOW_PAIR r9, r2, r3        @ Zero out the shadow regs
     cmp     r0, #0                      @ null array object?
     beq     common_errNullObject        @ yes, bail
     ldr     r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET]    @ r3<- arrayObj->length
diff --git a/runtime/interpreter/mterp/arm/op_const_wide.S b/runtime/interpreter/mterp/arm/op_const_wide.S
index 2cdc426..12394b6 100644
--- a/runtime/interpreter/mterp/arm/op_const_wide.S
+++ b/runtime/interpreter/mterp/arm/op_const_wide.S
@@ -6,6 +6,7 @@
     FETCH r3, 4                         @ r3<- HHHH (high)
     mov     r9, rINST, lsr #8           @ r9<- AA
     orr     r1, r2, r3, lsl #16         @ r1<- HHHHhhhh (high word)
+    CLEAR_SHADOW_PAIR r9, r2, r3        @ Zero out the shadow regs
     FETCH_ADVANCE_INST 5                @ advance rPC, load rINST
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/arm/op_const_wide_16.S b/runtime/interpreter/mterp/arm/op_const_wide_16.S
index 56bfc17..3811d86 100644
--- a/runtime/interpreter/mterp/arm/op_const_wide_16.S
+++ b/runtime/interpreter/mterp/arm/op_const_wide_16.S
@@ -3,6 +3,7 @@
     mov     r3, rINST, lsr #8           @ r3<- AA
     mov     r1, r0, asr #31             @ r1<- ssssssss
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
+    CLEAR_SHADOW_PAIR r3, r2, lr        @ Zero out the shadow regs
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r3, {r0-r1}                 @ vAA<- r0/r1
diff --git a/runtime/interpreter/mterp/arm/op_const_wide_32.S b/runtime/interpreter/mterp/arm/op_const_wide_32.S
index 36d4628..0b6f1cc 100644
--- a/runtime/interpreter/mterp/arm/op_const_wide_32.S
+++ b/runtime/interpreter/mterp/arm/op_const_wide_32.S
@@ -4,6 +4,7 @@
     FETCH_S r2, 2                       @ r2<- ssssBBBB (high)
     FETCH_ADVANCE_INST 3                @ advance rPC, load rINST
     orr     r0, r0, r2, lsl #16         @ r0<- BBBBbbbb
+    CLEAR_SHADOW_PAIR r3, r2, lr        @ Zero out the shadow regs
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
     mov     r1, r0, asr #31             @ r1<- ssssssss
     GET_INST_OPCODE ip                  @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/arm/op_const_wide_high16.S b/runtime/interpreter/mterp/arm/op_const_wide_high16.S
index bee592d..b9796eb 100644
--- a/runtime/interpreter/mterp/arm/op_const_wide_high16.S
+++ b/runtime/interpreter/mterp/arm/op_const_wide_high16.S
@@ -4,6 +4,7 @@
     mov     r0, #0                      @ r0<- 00000000
     mov     r1, r1, lsl #16             @ r1<- BBBB0000
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
+    CLEAR_SHADOW_PAIR r3, r0, r2        @ Zero shadow regs
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r3, {r0-r1}                 @ vAA<- r0/r1
diff --git a/runtime/interpreter/mterp/arm/op_iget_wide.S b/runtime/interpreter/mterp/arm/op_iget_wide.S
index f8d2f41..859ffac 100644
--- a/runtime/interpreter/mterp/arm/op_iget_wide.S
+++ b/runtime/interpreter/mterp/arm/op_iget_wide.S
@@ -15,8 +15,9 @@
     PREFETCH_INST 2
     cmp      r3, #0
     bne      MterpException                @ bail out
-    add     r3, rFP, r2, lsl #2            @ r3<- &fp[A]
-    stmia   r3, {r0-r1}                    @ fp[A]<- r0/r1
+    CLEAR_SHADOW_PAIR r2, ip, lr           @ Zero out the shadow regs
+    add      r3, rFP, r2, lsl #2           @ r3<- &fp[A]
+    stmia    r3, {r0-r1}                   @ fp[A]<- r0/r1
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/op_iget_wide_quick.S b/runtime/interpreter/mterp/arm/op_iget_wide_quick.S
index 4d6976e..07f854a 100644
--- a/runtime/interpreter/mterp/arm/op_iget_wide_quick.S
+++ b/runtime/interpreter/mterp/arm/op_iget_wide_quick.S
@@ -8,6 +8,7 @@
     ldrd    r0, [r3, ip]                @ r0<- obj.field (64 bits, aligned)
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    CLEAR_SHADOW_PAIR r2, ip, lr        @ Zero out the shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
     GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/op_move_result_wide.S b/runtime/interpreter/mterp/arm/op_move_result_wide.S
index c64103c..1845ccf 100644
--- a/runtime/interpreter/mterp/arm/op_move_result_wide.S
+++ b/runtime/interpreter/mterp/arm/op_move_result_wide.S
@@ -1,8 +1,9 @@
     /* move-result-wide vAA */
-    mov     r2, rINST, lsr #8           @ r2<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     ldr     r3, [rFP, #OFF_FP_RESULT_REGISTER]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
+    add     r2, rFP, rINST, lsl #2      @ r2<- &fp[AA]
     ldmia   r3, {r0-r1}                 @ r0/r1<- retval.j
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     stmia   r2, {r0-r1}                 @ fp[AA]<- r0/r1
     GET_INST_OPCODE ip                  @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/arm/op_move_wide.S b/runtime/interpreter/mterp/arm/op_move_wide.S
index 1345b95..f5d156d 100644
--- a/runtime/interpreter/mterp/arm/op_move_wide.S
+++ b/runtime/interpreter/mterp/arm/op_move_wide.S
@@ -1,10 +1,11 @@
     /* move-wide vA, vB */
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r2, rINST, #8, #4           @ r2<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[A]
+    add     r2, rFP, rINST, lsl #2      @ r2<- &fp[A]
     ldmia   r3, {r0-r1}                 @ r0/r1<- fp[B]
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r2, {r0-r1}                 @ fp[A]<- r0/r1
diff --git a/runtime/interpreter/mterp/arm/op_move_wide_16.S b/runtime/interpreter/mterp/arm/op_move_wide_16.S
index 133a4c3..8a55c4b 100644
--- a/runtime/interpreter/mterp/arm/op_move_wide_16.S
+++ b/runtime/interpreter/mterp/arm/op_move_wide_16.S
@@ -3,9 +3,10 @@
     FETCH r3, 2                         @ r3<- BBBB
     FETCH r2, 1                         @ r2<- AAAA
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[BBBB]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AAAA]
+    add     lr, rFP, r2, lsl #2         @ r2<- &fp[AAAA]
     ldmia   r3, {r0-r1}                 @ r0/r1<- fp[BBBB]
     FETCH_ADVANCE_INST 3                @ advance rPC, load rINST
-    stmia   r2, {r0-r1}                 @ fp[AAAA]<- r0/r1
+    CLEAR_SHADOW_PAIR r2, r3, ip        @ Zero out the shadow regs
+    stmia   lr, {r0-r1}                 @ fp[AAAA]<- r0/r1
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/op_move_wide_from16.S b/runtime/interpreter/mterp/arm/op_move_wide_from16.S
index f2ae785..b65259d 100644
--- a/runtime/interpreter/mterp/arm/op_move_wide_from16.S
+++ b/runtime/interpreter/mterp/arm/op_move_wide_from16.S
@@ -1,10 +1,11 @@
     /* move-wide/from16 vAA, vBBBB */
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     FETCH r3, 1                         @ r3<- BBBB
-    mov     r2, rINST, lsr #8           @ r2<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[BBBB]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
+    add     r2, rFP, rINST, lsl #2      @ r2<- &fp[AA]
     ldmia   r3, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r2, {r0-r1}                 @ fp[AA]<- r0/r1
diff --git a/runtime/interpreter/mterp/arm/op_sget_wide.S b/runtime/interpreter/mterp/arm/op_sget_wide.S
index 97db05f..3a50908 100644
--- a/runtime/interpreter/mterp/arm/op_sget_wide.S
+++ b/runtime/interpreter/mterp/arm/op_sget_wide.S
@@ -12,10 +12,11 @@
     bl    artGet64StaticFromCode
     ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
     mov   r9, rINST, lsr #8             @ r9<- AA
-    add   r9, rFP, r9, lsl #2           @ r9<- &fp[AA]
+    add   lr, rFP, r9, lsl #2           @ r9<- &fp[AA]
     cmp   r3, #0                        @ Fail to resolve?
     bne   MterpException                @ bail out
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    CLEAR_SHADOW_PAIR r9, r2, ip        @ Zero out the shadow regs
+    stmia lr, {r0-r1}                   @ vAA/vAA+1<- r0/r1
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/arm/unopWide.S b/runtime/interpreter/mterp/arm/unopWide.S
index 7b8739c..a074234 100644
--- a/runtime/interpreter/mterp/arm/unopWide.S
+++ b/runtime/interpreter/mterp/arm/unopWide.S
@@ -8,10 +8,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     $preinstr                           @ optional op; may set condition codes
     $instr                              @ r0/r1<- op, r2-r3 changed
diff --git a/runtime/interpreter/mterp/arm/unopWider.S b/runtime/interpreter/mterp/arm/unopWider.S
index 657a395..23b6b9d 100644
--- a/runtime/interpreter/mterp/arm/unopWider.S
+++ b/runtime/interpreter/mterp/arm/unopWider.S
@@ -8,10 +8,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     GET_VREG r0, r3                     @ r0<- vB
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     $preinstr                           @ optional op; may set condition codes
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     $instr                              @ r0<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
diff --git a/runtime/interpreter/mterp/config_x86 b/runtime/interpreter/mterp/config_x86
index 5fab379..f1501e1 100644
--- a/runtime/interpreter/mterp/config_x86
+++ b/runtime/interpreter/mterp/config_x86
@@ -19,6 +19,10 @@
 handler-style computed-goto
 handler-size 128
 
+function-type-format FUNCTION_TYPE(%s)
+function-size-format SIZE(%s,%s)
+global-name-format SYMBOL(%s)
+
 # source for alternate entry stub
 asm-alt-stub x86/alt_stub.S
 
diff --git a/runtime/interpreter/mterp/gen_mterp.py b/runtime/interpreter/mterp/gen_mterp.py
index f56d8bd..5839b5f 100755
--- a/runtime/interpreter/mterp/gen_mterp.py
+++ b/runtime/interpreter/mterp/gen_mterp.py
@@ -41,6 +41,9 @@
 alt_label_prefix = ".L_ALT" # use ".L" to hide labels from gdb
 style = None                # interpreter style
 generate_alt_table = False
+function_type_format = ".type   %s, %%function"
+function_size_format = ".size   %s, .-%s"
+global_name_format = "%s"
 
 # Exception class.
 class DataParseError(SyntaxError):
@@ -147,7 +150,24 @@
         raise DataParseError("import requires one argument")
     default_alt_stub = tokens[1]
     generate_alt_table = True
-
+#
+# Change the default function type format
+#
+def setFunctionTypeFormat(tokens):
+    global function_type_format
+    function_type_format = tokens[1]
+#
+# Change the default function size format
+#
+def setFunctionSizeFormat(tokens):
+    global function_size_format
+    function_size_format = tokens[1]
+#
+# Change the global name format
+#
+def setGlobalNameFormat(tokens):
+    global global_name_format
+    global_name_format = tokens[1]
 #
 # Parse arch config file --
 # Start of opcode list.
@@ -259,12 +279,12 @@
     sister_list = []
     assert len(opcodes) == kNumPackedOpcodes
     need_dummy_start = False
-    start_label = "artMterpAsmInstructionStart"
-    end_label = "artMterpAsmInstructionEnd"
+    start_label = global_name_format % "artMterpAsmInstructionStart"
+    end_label = global_name_format % "artMterpAsmInstructionEnd"
 
     # point MterpAsmInstructionStart at the first handler or stub
     asm_fp.write("\n    .global %s\n" % start_label)
-    asm_fp.write("    .type   %s, %%function\n" % start_label)
+    asm_fp.write("    " + (function_type_format % start_label) + "\n");
     asm_fp.write("%s = " % start_label + label_prefix + "_op_nop\n")
     asm_fp.write("    .text\n\n")
 
@@ -290,21 +310,23 @@
         asm_fp.write(label_prefix + "_op_nop:   /* dummy */\n");
 
     emitAlign()
-    asm_fp.write("    .size   %s, .-%s\n" % (start_label, start_label))
+    asm_fp.write("    " + (function_size_format % (start_label, start_label)) + "\n")
     asm_fp.write("    .global %s\n" % end_label)
     asm_fp.write("%s:\n" % end_label)
 
     if style == "computed-goto":
+        start_sister_label = global_name_format % "artMterpAsmSisterStart"
+        end_sister_label = global_name_format % "artMterpAsmSisterEnd"
         emitSectionComment("Sister implementations", asm_fp)
-        asm_fp.write("    .global artMterpAsmSisterStart\n")
-        asm_fp.write("    .type   artMterpAsmSisterStart, %function\n")
+        asm_fp.write("    .global %s\n" % start_sister_label)
+        asm_fp.write("    " + (function_type_format % start_sister_label) + "\n");
         asm_fp.write("    .text\n")
         asm_fp.write("    .balign 4\n")
-        asm_fp.write("artMterpAsmSisterStart:\n")
+        asm_fp.write("%s:\n" % start_sister_label)
         asm_fp.writelines(sister_list)
-        asm_fp.write("\n    .size   artMterpAsmSisterStart, .-artMterpAsmSisterStart\n")
-        asm_fp.write("    .global artMterpAsmSisterEnd\n")
-        asm_fp.write("artMterpAsmSisterEnd:\n\n")
+        asm_fp.write("\n    " + (function_size_format % (start_sister_label, start_sister_label)) + "\n")
+        asm_fp.write("    .global %s\n" % end_sister_label)
+        asm_fp.write("%s:\n\n" % end_sister_label)
 
 #
 # Load an alternate entry stub
@@ -324,12 +346,12 @@
 #
 def loadAndEmitAltOpcodes():
     assert len(opcodes) == kNumPackedOpcodes
-    start_label = "artMterpAsmAltInstructionStart"
-    end_label = "artMterpAsmAltInstructionEnd"
+    start_label = global_name_format % "artMterpAsmAltInstructionStart"
+    end_label = global_name_format % "artMterpAsmAltInstructionEnd"
 
     # point MterpAsmInstructionStart at the first handler or stub
     asm_fp.write("\n    .global %s\n" % start_label)
-    asm_fp.write("    .type   %s, %%function\n" % start_label)
+    asm_fp.write("    " + (function_type_format % start_label) + "\n");
     asm_fp.write("    .text\n\n")
     asm_fp.write("%s = " % start_label + label_prefix + "_ALT_op_nop\n")
 
@@ -342,7 +364,7 @@
         loadAndEmitAltStub(source, i)
 
     emitAlign()
-    asm_fp.write("    .size   %s, .-%s\n" % (start_label, start_label))
+    asm_fp.write("    " + (function_size_format % (start_label, start_label)) + "\n")
     asm_fp.write("    .global %s\n" % end_label)
     asm_fp.write("%s:\n" % end_label)
 
@@ -579,6 +601,12 @@
                 splitops = True
             elif tokens[0] == "fallback-stub":
                setFallbackStub(tokens)
+            elif tokens[0] == "function-type-format":
+               setFunctionTypeFormat(tokens)
+            elif tokens[0] == "function-size-format":
+               setFunctionSizeFormat(tokens)
+            elif tokens[0] == "global-name-format":
+               setGlobalNameFormat(tokens)
             else:
                 raise DataParseError, "unrecognized command '%s'" % tokens[0]
             if style == None:
diff --git a/runtime/interpreter/mterp/out/mterp_arm.S b/runtime/interpreter/mterp/out/mterp_arm.S
index 78c784b..ee19559 100644
--- a/runtime/interpreter/mterp/out/mterp_arm.S
+++ b/runtime/interpreter/mterp/out/mterp_arm.S
@@ -270,6 +270,19 @@
     str     \reg, [rFP, \vreg, lsl #2]
     str     \reg, [rREFS, \vreg, lsl #2]
 .endm
+.macro SET_VREG_SHADOW reg, vreg
+    str     \reg, [rREFS, \vreg, lsl #2]
+.endm
+
+/*
+ * Clear the corresponding shadow regs for a vreg pair
+ */
+.macro CLEAR_SHADOW_PAIR vreg, tmp1, tmp2
+    mov     \tmp1, #0
+    add     \tmp2, \vreg, #1
+    SET_VREG_SHADOW \tmp1, \vreg
+    SET_VREG_SHADOW \tmp1, \tmp2
+.endm
 
 /*
  * Convert a virtual register index into an address.
@@ -426,10 +439,11 @@
     /* move-wide vA, vB */
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r2, rINST, #8, #4           @ r2<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[A]
+    add     r2, rFP, rINST, lsl #2      @ r2<- &fp[A]
     ldmia   r3, {r0-r1}                 @ r0/r1<- fp[B]
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r2, {r0-r1}                 @ fp[A]<- r0/r1
@@ -442,10 +456,11 @@
     /* move-wide/from16 vAA, vBBBB */
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     FETCH r3, 1                         @ r3<- BBBB
-    mov     r2, rINST, lsr #8           @ r2<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[BBBB]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
+    add     r2, rFP, rINST, lsl #2      @ r2<- &fp[AA]
     ldmia   r3, {r0-r1}                 @ r0/r1<- fp[BBBB]
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r2, {r0-r1}                 @ fp[AA]<- r0/r1
@@ -460,10 +475,11 @@
     FETCH r3, 2                         @ r3<- BBBB
     FETCH r2, 1                         @ r2<- AAAA
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[BBBB]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AAAA]
+    add     lr, rFP, r2, lsl #2         @ r2<- &fp[AAAA]
     ldmia   r3, {r0-r1}                 @ r0/r1<- fp[BBBB]
     FETCH_ADVANCE_INST 3                @ advance rPC, load rINST
-    stmia   r2, {r0-r1}                 @ fp[AAAA]<- r0/r1
+    CLEAR_SHADOW_PAIR r2, r3, ip        @ Zero out the shadow regs
+    stmia   lr, {r0-r1}                 @ fp[AAAA]<- r0/r1
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
@@ -550,10 +566,11 @@
 .L_op_move_result_wide: /* 0x0b */
 /* File: arm/op_move_result_wide.S */
     /* move-result-wide vAA */
-    mov     r2, rINST, lsr #8           @ r2<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     ldr     r3, [rFP, #OFF_FP_RESULT_REGISTER]
-    add     r2, rFP, r2, lsl #2         @ r2<- &fp[AA]
+    add     r2, rFP, rINST, lsl #2      @ r2<- &fp[AA]
     ldmia   r3, {r0-r1}                 @ r0/r1<- retval.j
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     stmia   r2, {r0-r1}                 @ fp[AA]<- r0/r1
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -731,6 +748,7 @@
     mov     r3, rINST, lsr #8           @ r3<- AA
     mov     r1, r0, asr #31             @ r1<- ssssssss
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
+    CLEAR_SHADOW_PAIR r3, r2, lr        @ Zero out the shadow regs
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r3, {r0-r1}                 @ vAA<- r0/r1
@@ -746,6 +764,7 @@
     FETCH_S r2, 2                       @ r2<- ssssBBBB (high)
     FETCH_ADVANCE_INST 3                @ advance rPC, load rINST
     orr     r0, r0, r2, lsl #16         @ r0<- BBBBbbbb
+    CLEAR_SHADOW_PAIR r3, r2, lr        @ Zero out the shadow regs
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
     mov     r1, r0, asr #31             @ r1<- ssssssss
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -764,6 +783,7 @@
     FETCH r3, 4                         @ r3<- HHHH (high)
     mov     r9, rINST, lsr #8           @ r9<- AA
     orr     r1, r2, r3, lsl #16         @ r1<- HHHHhhhh (high word)
+    CLEAR_SHADOW_PAIR r9, r2, r3        @ Zero out the shadow regs
     FETCH_ADVANCE_INST 5                @ advance rPC, load rINST
     add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -780,6 +800,7 @@
     mov     r0, #0                      @ r0<- 00000000
     mov     r1, r1, lsl #16             @ r1<- BBBB0000
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
+    CLEAR_SHADOW_PAIR r3, r0, r2        @ Zero shadow regs
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[AA]
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r3, {r0-r1}                 @ vAA<- r0/r1
@@ -2068,6 +2089,7 @@
     mov     r3, r0, lsr #8              @ r3<- CC
     GET_VREG r0, r2                     @ r0<- vBB (array object)
     GET_VREG r1, r3                     @ r1<- vCC (requested index)
+    CLEAR_SHADOW_PAIR r9, r2, r3        @ Zero out the shadow regs
     cmp     r0, #0                      @ null array object?
     beq     common_errNullObject        @ yes, bail
     ldr     r3, [r0, #MIRROR_ARRAY_LENGTH_OFFSET]    @ r3<- arrayObj->length
@@ -2519,8 +2541,9 @@
     PREFETCH_INST 2
     cmp      r3, #0
     bne      MterpException                @ bail out
-    add     r3, rFP, r2, lsl #2            @ r3<- &fp[A]
-    stmia   r3, {r0-r1}                    @ fp[A]<- r0/r1
+    CLEAR_SHADOW_PAIR r2, ip, lr           @ Zero out the shadow regs
+    add      r3, rFP, r2, lsl #2           @ r3<- &fp[A]
+    stmia    r3, {r0-r1}                   @ fp[A]<- r0/r1
     ADVANCE 2
     GET_INST_OPCODE ip                     @ extract opcode from rINST
     GOTO_OPCODE ip                         @ jump to next instruction
@@ -2909,11 +2932,12 @@
     bl    artGet64StaticFromCode
     ldr   r3, [rSELF, #THREAD_EXCEPTION_OFFSET]
     mov   r9, rINST, lsr #8             @ r9<- AA
-    add   r9, rFP, r9, lsl #2           @ r9<- &fp[AA]
+    add   lr, rFP, r9, lsl #2           @ r9<- &fp[AA]
     cmp   r3, #0                        @ Fail to resolve?
     bne   MterpException                @ bail out
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-    stmia   r9, {r0-r1}                 @ vAA/vAA+1<- r0/r1
+    CLEAR_SHADOW_PAIR r9, r2, ip        @ Zero out the shadow regs
+    stmia lr, {r0-r1}                   @ vAA/vAA+1<- r0/r1
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     GOTO_OPCODE ip                      @ jump to next instruction
 
@@ -3622,10 +3646,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     rsbs    r0, r0, #0                           @ optional op; may set condition codes
     rsc     r1, r1, #0                              @ r0/r1<- op, r2-r3 changed
@@ -3649,10 +3674,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     mvn     r0, r0                           @ optional op; may set condition codes
     mvn     r1, r1                              @ r0/r1<- op, r2-r3 changed
@@ -3702,10 +3728,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
                                @ optional op; may set condition codes
     add     r1, r1, #0x80000000                              @ r0/r1<- op, r2-r3 changed
@@ -3729,10 +3756,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     GET_VREG r0, r3                     @ r0<- vB
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
                                @ optional op; may set condition codes
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     mov     r1, r0, asr #31                              @ r0<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -3785,6 +3813,7 @@
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     and     r9, r9, #15                 @ r9<- A
     fsitod  d0, s0                              @ d0<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     fstd    d0, [r9]                    @ vA<- d0
@@ -3912,10 +3941,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     GET_VREG r0, r3                     @ r0<- vB
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
                                @ optional op; may set condition codes
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     bl      f2l_doconv                              @ r0<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -3944,6 +3974,7 @@
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     and     r9, r9, #15                 @ r9<- A
     fcvtds  d0, s0                              @ d0<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     fstd    d0, [r9]                    @ vA<- d0
@@ -3990,10 +4021,11 @@
      */
     /* unop vA, vB */
     mov     r3, rINST, lsr #12          @ r3<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r3, {r0-r1}                 @ r0/r1<- vAA
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
                                @ optional op; may set condition codes
     bl      d2l_doconv                              @ r0/r1<- op, r2-r3 changed
@@ -4570,10 +4602,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -4582,8 +4614,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
     adds    r0, r0, r2                           @ optional op; may set condition codes
     adc     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -4614,10 +4646,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -4626,8 +4658,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
     subs    r0, r0, r2                           @ optional op; may set condition codes
     sbc     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -4699,10 +4731,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -4711,8 +4743,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
                                @ optional op; may set condition codes
     bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -4744,10 +4776,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -4756,8 +4788,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
                                @ optional op; may set condition codes
     bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -4788,10 +4820,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -4800,8 +4832,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
     and     r0, r0, r2                           @ optional op; may set condition codes
     and     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -4832,10 +4864,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -4844,8 +4876,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
     orr     r0, r0, r2                           @ optional op; may set condition codes
     orr     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -4876,10 +4908,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -4888,8 +4920,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
     eor     r0, r0, r2                           @ optional op; may set condition codes
     eor     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -5177,9 +5209,9 @@
     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &vBB
     fldd    d1, [r3]                    @ d1<- vCC
     fldd    d0, [r2]                    @ d0<- vBB
-
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     faddd   d2, d0, d1                              @ s2<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vAA
     fstd    d2, [r9]                    @ vAA<- d2
@@ -5207,9 +5239,9 @@
     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &vBB
     fldd    d1, [r3]                    @ d1<- vCC
     fldd    d0, [r2]                    @ d0<- vBB
-
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     fsubd   d2, d0, d1                              @ s2<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vAA
     fstd    d2, [r9]                    @ vAA<- d2
@@ -5237,9 +5269,9 @@
     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &vBB
     fldd    d1, [r3]                    @ d1<- vCC
     fldd    d0, [r2]                    @ d0<- vBB
-
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     fmuld   d2, d0, d1                              @ s2<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vAA
     fstd    d2, [r9]                    @ vAA<- d2
@@ -5267,9 +5299,9 @@
     VREG_INDEX_TO_ADDR r2, r2           @ r2<- &vBB
     fldd    d1, [r3]                    @ d1<- vCC
     fldd    d0, [r2]                    @ d0<- vBB
-
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     fdivd   d2, d0, d1                              @ s2<- op
+    CLEAR_SHADOW_PAIR r9, ip, lr        @ Zero shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vAA
     fstd    d2, [r9]                    @ vAA<- d2
@@ -5299,10 +5331,10 @@
      */
     /* binop vAA, vBB, vCC */
     FETCH r0, 1                         @ r0<- CCBB
-    mov     r9, rINST, lsr #8           @ r9<- AA
+    mov     rINST, rINST, lsr #8        @ rINST<- AA
     and     r2, r0, #255                @ r2<- BB
     mov     r3, r0, lsr #8              @ r3<- CC
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[AA]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[AA]
     add     r2, rFP, r2, lsl #2         @ r2<- &fp[BB]
     add     r3, rFP, r3, lsl #2         @ r3<- &fp[CC]
     ldmia   r2, {r0-r1}                 @ r0/r1<- vBB/vBB+1
@@ -5311,8 +5343,8 @@
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, lr, ip     @ Zero out the shadow regs
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
-
                                @ optional op; may set condition codes
     bl      fmod                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -5754,17 +5786,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
     adds    r0, r0, r2                           @ optional op; may set condition codes
     adc     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -5794,17 +5826,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
     subs    r0, r0, r2                           @ optional op; may set condition codes
     sbc     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -5863,17 +5895,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 1
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
                                @ optional op; may set condition codes
     bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -5904,17 +5936,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 1
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
                                @ optional op; may set condition codes
     bl      __aeabi_ldivmod                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -5944,17 +5976,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
     and     r0, r0, r2                           @ optional op; may set condition codes
     and     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -5984,17 +6016,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
     orr     r0, r0, r2                           @ optional op; may set condition codes
     orr     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -6024,17 +6056,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
     eor     r0, r0, r2                           @ optional op; may set condition codes
     eor     r1, r1, r3                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -6294,10 +6326,10 @@
     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &vB
     and     r9, r9, #15                 @ r9<- A
     fldd    d1, [r3]                    @ d1<- vB
+    CLEAR_SHADOW_PAIR r9, ip, r0        @ Zero out shadow regs
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     fldd    d0, [r9]                    @ d0<- vA
-
     faddd   d2, d0, d1                              @ d2<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     fstd    d2, [r9]                    @ vAA<- d2
@@ -6323,10 +6355,10 @@
     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &vB
     and     r9, r9, #15                 @ r9<- A
     fldd    d1, [r3]                    @ d1<- vB
+    CLEAR_SHADOW_PAIR r9, ip, r0        @ Zero out shadow regs
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     fldd    d0, [r9]                    @ d0<- vA
-
     fsubd   d2, d0, d1                              @ d2<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     fstd    d2, [r9]                    @ vAA<- d2
@@ -6352,10 +6384,10 @@
     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &vB
     and     r9, r9, #15                 @ r9<- A
     fldd    d1, [r3]                    @ d1<- vB
+    CLEAR_SHADOW_PAIR r9, ip, r0        @ Zero out shadow regs
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     fldd    d0, [r9]                    @ d0<- vA
-
     fmuld   d2, d0, d1                              @ d2<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     fstd    d2, [r9]                    @ vAA<- d2
@@ -6381,10 +6413,10 @@
     VREG_INDEX_TO_ADDR r3, r3           @ r3<- &vB
     and     r9, r9, #15                 @ r9<- A
     fldd    d1, [r3]                    @ d1<- vB
+    CLEAR_SHADOW_PAIR r9, ip, r0        @ Zero out shadow regs
     VREG_INDEX_TO_ADDR r9, r9           @ r9<- &vA
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
     fldd    d0, [r9]                    @ d0<- vA
-
     fdivd   d2, d0, d1                              @ d2<- op
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     fstd    d2, [r9]                    @ vAA<- d2
@@ -6413,17 +6445,17 @@
      */
     /* binop/2addr vA, vB */
     mov     r1, rINST, lsr #12          @ r1<- B
-    ubfx    r9, rINST, #8, #4           @ r9<- A
+    ubfx    rINST, rINST, #8, #4        @ rINST<- A
     add     r1, rFP, r1, lsl #2         @ r1<- &fp[B]
-    add     r9, rFP, r9, lsl #2         @ r9<- &fp[A]
+    add     r9, rFP, rINST, lsl #2      @ r9<- &fp[A]
     ldmia   r1, {r2-r3}                 @ r2/r3<- vBB/vBB+1
     ldmia   r9, {r0-r1}                 @ r0/r1<- vAA/vAA+1
     .if 0
     orrs    ip, r2, r3                  @ second arg (r2-r3) is zero?
     beq     common_errDivideByZero
     .endif
+    CLEAR_SHADOW_PAIR rINST, ip, lr     @ Zero shadow regs
     FETCH_ADVANCE_INST 1                @ advance rPC, load rINST
-
                                @ optional op; may set condition codes
     bl      fmod                              @ result<- op, r0-r3 changed
     GET_INST_OPCODE ip                  @ extract opcode from rINST
@@ -7155,6 +7187,7 @@
     ldrd    r0, [r3, ip]                @ r0<- obj.field (64 bits, aligned)
     FETCH_ADVANCE_INST 2                @ advance rPC, load rINST
     add     r3, rFP, r2, lsl #2         @ r3<- &fp[A]
+    CLEAR_SHADOW_PAIR r2, ip, lr        @ Zero out the shadow regs
     GET_INST_OPCODE ip                  @ extract opcode from rINST
     stmia   r3, {r0-r1}                 @ fp[A]<- r0/r1
     GOTO_OPCODE ip                      @ jump to next instruction
diff --git a/runtime/interpreter/mterp/out/mterp_x86.S b/runtime/interpreter/mterp/out/mterp_x86.S
index e2918dc..96229ce 100644
--- a/runtime/interpreter/mterp/out/mterp_x86.S
+++ b/runtime/interpreter/mterp/out/mterp_x86.S
@@ -96,6 +96,22 @@
  */
 #include "asm_support.h"
 
+/*
+ * Handle mac compiler specific
+ */
+#if defined(__APPLE__)
+    #define MACRO_LITERAL(value) $(value)
+    #define FUNCTION_TYPE(name)
+    #define SIZE(start,end)
+    // Mac OS' symbols have an _ prefix.
+    #define SYMBOL(name) _ ## name
+#else
+    #define MACRO_LITERAL(value) $value
+    #define FUNCTION_TYPE(name) .type name, @function
+    #define SIZE(start,end) .size start, .-end
+    #define SYMBOL(name) name
+#endif
+
 /* Frame size must be 16-byte aligned.
  * Remember about 4 bytes for return address
  */
@@ -199,7 +215,7 @@
  */
 .macro REFRESH_INST _opnum
     movb    rINSTbl, rINSTbh
-    movb    $\_opnum, rINSTbl
+    movb    MACRO_LITERAL(\_opnum), rINSTbl
 .endm
 
 /*
@@ -215,7 +231,7 @@
 .macro GOTO_NEXT
     movzx   rINSTbl,%eax
     movzbl  rINSTbh,rINST
-    shll    $7, %eax
+    shll    MACRO_LITERAL(7), %eax
     addl    rIBASE, %eax
     jmp     *%eax
 .endm
@@ -255,7 +271,7 @@
 
 .macro SET_VREG _reg _vreg
     movl    \_reg, (rFP,\_vreg,4)
-    movl    $0, (rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0), (rREFS,\_vreg,4)
 .endm
 
 /* Write wide value from xmm. xmm is clobbered. */
@@ -276,16 +292,16 @@
 
 .macro SET_VREG_HIGH _reg _vreg
     movl    \_reg, 4(rFP,\_vreg,4)
-    movl    $0, 4(rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0), 4(rREFS,\_vreg,4)
 .endm
 
 .macro CLEAR_REF _vreg
-    movl    $0,  (rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0),  (rREFS,\_vreg,4)
 .endm
 
 .macro CLEAR_WIDE_REF _vreg
-    movl    $0,  (rREFS,\_vreg,4)
-    movl    $0, 4(rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0),  (rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0), 4(rREFS,\_vreg,4)
 .endm
 
 /* File: x86/entry.S */
@@ -309,8 +325,8 @@
  */
 
     .text
-    .global ExecuteMterpImpl
-    .type   ExecuteMterpImpl, %function
+    .global SYMBOL(ExecuteMterpImpl)
+    FUNCTION_TYPE(ExecuteMterpImpl)
 
 /*
  * On entry:
@@ -321,7 +337,7 @@
  *
  */
 
-ExecuteMterpImpl:
+SYMBOL(ExecuteMterpImpl):
     .cfi_startproc
     /* Allocate frame */
     subl    $FRAME_SIZE, %esp
@@ -362,9 +378,9 @@
     /* NOTE: no fallthrough */
 
 
-    .global artMterpAsmInstructionStart
-    .type   artMterpAsmInstructionStart, %function
-artMterpAsmInstructionStart = .L_op_nop
+    .global SYMBOL(artMterpAsmInstructionStart)
+    FUNCTION_TYPE(SYMBOL(artMterpAsmInstructionStart))
+SYMBOL(artMterpAsmInstructionStart) = .L_op_nop
     .text
 
 /* ------------------------------ */
@@ -382,11 +398,11 @@
     movzbl  rINSTbl, %eax                   # eax <- BA
     andb    $0xf, %al                      # eax <- A
     shrl    $4, rINST                      # rINST <- B
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     .if 0
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -398,11 +414,11 @@
     /* op vAA, vBBBB */
     movzx   rINSTbl, %eax                   # eax <- AA
     movw    2(rPC), rINSTw                  # rINSTw <- BBBB
-    GET_VREG rINST rINST                    # rINST <- fp[BBBB]
+    GET_VREG rINST, rINST                   # rINST <- fp[BBBB]
     .if 0
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -414,11 +430,11 @@
     /* op vAAAA, vBBBB */
     movzwl  4(rPC), %ecx                    # ecx <- BBBB
     movzwl  2(rPC), %eax                    # eax <- AAAA
-    GET_VREG rINST %ecx
+    GET_VREG rINST, %ecx
     .if 0
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
 
@@ -431,8 +447,8 @@
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, rINST                      # rINST <- B
     andb    $0xf, %cl                      # ecx <- A
-    GET_WIDE_FP_VREG %xmm0 rINST            # xmm0 <- v[B]
-    SET_WIDE_FP_VREG %xmm0 %ecx             # v[A] <- xmm0
+    GET_WIDE_FP_VREG %xmm0, rINST           # xmm0 <- v[B]
+    SET_WIDE_FP_VREG %xmm0, %ecx            # v[A] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -443,8 +459,8 @@
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     movzwl  2(rPC), %ecx                    # ecx <- BBBB
     movzbl  rINSTbl, %eax                   # eax <- AAAA
-    GET_WIDE_FP_VREG %xmm0 %ecx             # xmm0 <- v[B]
-    SET_WIDE_FP_VREG %xmm0 %eax             # v[A] <- xmm0
+    GET_WIDE_FP_VREG %xmm0, %ecx            # xmm0 <- v[B]
+    SET_WIDE_FP_VREG %xmm0, %eax            # v[A] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -455,8 +471,8 @@
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     movzwl  4(rPC), %ecx                    # ecx<- BBBB
     movzwl  2(rPC), %eax                    # eax<- AAAA
-    GET_WIDE_FP_VREG %xmm0 %ecx             # xmm0 <- v[B]
-    SET_WIDE_FP_VREG %xmm0 %eax             # v[A] <- xmm0
+    GET_WIDE_FP_VREG %xmm0, %ecx            # xmm0 <- v[B]
+    SET_WIDE_FP_VREG %xmm0, %eax            # v[A] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
 
 /* ------------------------------ */
@@ -469,11 +485,11 @@
     movzbl  rINSTbl, %eax                   # eax <- BA
     andb    $0xf, %al                      # eax <- A
     shrl    $4, rINST                      # rINST <- B
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     .if 1
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -487,11 +503,11 @@
     /* op vAA, vBBBB */
     movzx   rINSTbl, %eax                   # eax <- AA
     movw    2(rPC), rINSTw                  # rINSTw <- BBBB
-    GET_VREG rINST rINST                    # rINST <- fp[BBBB]
+    GET_VREG rINST, rINST                   # rINST <- fp[BBBB]
     .if 1
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -505,11 +521,11 @@
     /* op vAAAA, vBBBB */
     movzwl  4(rPC), %ecx                    # ecx <- BBBB
     movzwl  2(rPC), %eax                    # eax <- AAAA
-    GET_VREG rINST %ecx
+    GET_VREG rINST, %ecx
     .if 1
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
 
@@ -523,9 +539,9 @@
     movl    OFF_FP_RESULT_REGISTER(rFP), %eax    # get pointer to result JType.
     movl    (%eax), %eax                    # r0 <- result.i.
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- fp[B]
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- fp[B]
     .else
-    SET_VREG %eax rINST                     # fp[A] <- fp[B]
+    SET_VREG %eax, rINST                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -537,8 +553,8 @@
     movl    OFF_FP_RESULT_REGISTER(rFP), %eax    # get pointer to result JType.
     movl    4(%eax), %ecx                   # Get high
     movl    (%eax), %eax                    # Get low
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
-    SET_VREG_HIGH %ecx rINST                # v[AA+1] <- ecx
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
+    SET_VREG_HIGH %ecx, rINST               # v[AA+1] <- ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -551,9 +567,9 @@
     movl    OFF_FP_RESULT_REGISTER(rFP), %eax    # get pointer to result JType.
     movl    (%eax), %eax                    # r0 <- result.i.
     .if 1
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- fp[B]
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- fp[B]
     .else
-    SET_VREG %eax rINST                     # fp[A] <- fp[B]
+    SET_VREG %eax, rINST                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -565,7 +581,7 @@
     /* move-exception vAA */
     movl    rSELF, %ecx
     movl    THREAD_EXCEPTION_OFFSET(%ecx), %eax
-    SET_VREG_OBJECT %eax rINST              # fp[AA] <- exception object
+    SET_VREG_OBJECT %eax, rINST             # fp[AA] <- exception object
     movl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -574,12 +590,12 @@
 .L_op_return_void: /* 0x0e */
 /* File: x86/op_return_void.S */
     .extern MterpThreadFenceForConstructor
-    call    MterpThreadFenceForConstructor
+    call    SYMBOL(MterpThreadFenceForConstructor)
     movl    rSELF, %eax
     testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
@@ -596,14 +612,14 @@
  */
     /* op vAA */
     .extern MterpThreadFenceForConstructor
-    call    MterpThreadFenceForConstructor
+    call    SYMBOL(MterpThreadFenceForConstructor)
     movl    rSELF, %eax
     testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     xorl    %ecx, %ecx
     jmp     MterpReturn
 
@@ -616,15 +632,15 @@
  */
     /* return-wide vAA */
     .extern MterpThreadFenceForConstructor
-    call    MterpThreadFenceForConstructor
+    call    SYMBOL(MterpThreadFenceForConstructor)
     movl    rSELF, %eax
     testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
-    GET_VREG_HIGH %ecx rINST                # ecx <- v[AA+1]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
+    GET_VREG_HIGH %ecx, rINST               # ecx <- v[AA+1]
     jmp     MterpReturn
 
 /* ------------------------------ */
@@ -639,14 +655,14 @@
  */
     /* op vAA */
     .extern MterpThreadFenceForConstructor
-    call    MterpThreadFenceForConstructor
+    call    SYMBOL(MterpThreadFenceForConstructor)
     movl    rSELF, %eax
     testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     xorl    %ecx, %ecx
     jmp     MterpReturn
 
@@ -660,7 +676,7 @@
     movl    $0xf, rINST
     andl    %eax, rINST                     # rINST <- A
     sarl    $4, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -669,7 +685,7 @@
 /* File: x86/op_const_16.S */
     /* const/16 vAA, #+BBBB */
     movswl  2(rPC), %ecx                    # ecx <- ssssBBBB
-    SET_VREG %ecx rINST                     # vAA <- ssssBBBB
+    SET_VREG %ecx, rINST                    # vAA <- ssssBBBB
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -678,7 +694,7 @@
 /* File: x86/op_const.S */
     /* const vAA, #+BBBBbbbb */
     movl    2(rPC), %eax                    # grab all 32 bits at once
-    SET_VREG %eax rINST                     # vAA<- eax
+    SET_VREG %eax, rINST                    # vAA<- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
 
 /* ------------------------------ */
@@ -688,7 +704,7 @@
     /* const/high16 vAA, #+BBBB0000 */
     movzwl  2(rPC), %eax                    # eax <- 0000BBBB
     sall    $16, %eax                      # eax <- BBBB0000
-    SET_VREG %eax rINST                     # vAA <- eax
+    SET_VREG %eax, rINST                    # vAA <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -699,8 +715,8 @@
     movswl  2(rPC), %eax                    # eax <- ssssBBBB
     movl    rIBASE, %ecx                    # preserve rIBASE (cltd trashes it)
     cltd                                    # rIBASE:eax <- ssssssssssssBBBB
-    SET_VREG_HIGH rIBASE rINST              # store msw
-    SET_VREG %eax rINST                     # store lsw
+    SET_VREG_HIGH rIBASE, rINST             # store msw
+    SET_VREG %eax, rINST                    # store lsw
     movl    %ecx, rIBASE                    # restore rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -712,8 +728,8 @@
     movl    2(rPC), %eax                    # eax <- BBBBbbbb
     movl    rIBASE, %ecx                    # preserve rIBASE (cltd trashes it)
     cltd                                    # rIBASE:eax <- ssssssssssssBBBB
-    SET_VREG_HIGH rIBASE rINST              # store msw
-    SET_VREG %eax rINST                     # store lsw
+    SET_VREG_HIGH rIBASE, rINST             # store msw
+    SET_VREG %eax, rINST                    # store lsw
     movl    %ecx, rIBASE                    # restore rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
 
@@ -725,8 +741,8 @@
     movl    2(rPC), %eax                    # eax <- lsw
     movzbl  rINSTbl, %ecx                   # ecx <- AA
     movl    6(rPC), rINST                   # rINST <- msw
-    SET_VREG %eax %ecx
-    SET_VREG_HIGH  rINST %ecx
+    SET_VREG %eax, %ecx
+    SET_VREG_HIGH  rINST, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 5
 
 /* ------------------------------ */
@@ -736,9 +752,9 @@
     /* const-wide/high16 vAA, #+BBBB000000000000 */
     movzwl  2(rPC), %eax                    # eax <- 0000BBBB
     sall    $16, %eax                      # eax <- BBBB0000
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     xorl    %eax, %eax
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -754,7 +770,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpConstString                # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
@@ -773,7 +789,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpConstString                # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
@@ -792,7 +808,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpConstClass                 # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstClass)         # (index, tgt_reg, shadow_frame, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
@@ -807,11 +823,11 @@
  */
     /* monitor-enter vAA */
     EXPORT_PC
-    GET_VREG %ecx rINST
+    GET_VREG %ecx, rINST
     movl    %ecx, OUT_ARG0(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    artLockObjectFromCode           # (object, self)
+    call    SYMBOL(artLockObjectFromCode)   # (object, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpException
@@ -830,11 +846,11 @@
  */
     /* monitor-exit vAA */
     EXPORT_PC
-    GET_VREG %ecx rINST
+    GET_VREG %ecx, rINST
     movl    %ecx, OUT_ARG0(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    artUnlockObjectFromCode         # (object, self)
+    call    SYMBOL(artUnlockObjectFromCode) # (object, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpException
@@ -857,7 +873,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpCheckCast                  # (index, &obj, method, self)
+    call    SYMBOL(MterpCheckCast)          # (index, &obj, method, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
@@ -885,13 +901,13 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpInstanceOf                 # (index, &obj, method, self)
+    call    SYMBOL(MterpInstanceOf)         # (index, &obj, method, self)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     andb    $0xf, rINSTbl                  # rINSTbl <- A
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -903,12 +919,12 @@
  */
     mov     rINST, %eax                     # eax <- BA
     sarl    $4, rINST                      # rINST <- B
-    GET_VREG %ecx rINST                     # ecx <- vB (object ref)
+    GET_VREG %ecx, rINST                    # ecx <- vB (object ref)
     testl   %ecx, %ecx                      # is null?
     je      common_errNullObject
     andb    $0xf, %al                      # eax <- A
     movl    MIRROR_ARRAY_LENGTH_OFFSET(%ecx), rINST
-    SET_VREG rINST %eax
+    SET_VREG rINST, %eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -926,7 +942,7 @@
     movl    %ecx, OUT_ARG1(%esp)
     REFRESH_INST 34
     movl    rINST, OUT_ARG2(%esp)
-    call    MterpNewInstance
+    call    SYMBOL(MterpNewInstance)
     REFRESH_IBASE
     testl   %eax, %eax                 # 0 means an exception is thrown
     jz      MterpPossibleException
@@ -952,7 +968,7 @@
     movl    rINST, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpNewArray
+    call    SYMBOL(MterpNewArray)
     REFRESH_IBASE
     testl   %eax, %eax                      # 0 means an exception is thrown
     jz      MterpPossibleException
@@ -976,7 +992,7 @@
     movl    rPC, OUT_ARG1(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)
-    call    MterpFilledNewArray
+    call    SYMBOL(MterpFilledNewArray)
     REFRESH_IBASE
     testl   %eax, %eax                      # 0 means an exception is thrown
     jz      MterpPossibleException
@@ -1001,7 +1017,7 @@
     movl    rPC, OUT_ARG1(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)
-    call    MterpFilledNewArrayRange
+    call    SYMBOL(MterpFilledNewArrayRange)
     REFRESH_IBASE
     testl   %eax, %eax                      # 0 means an exception is thrown
     jz      MterpPossibleException
@@ -1016,10 +1032,10 @@
     EXPORT_PC
     movl    2(rPC), %ecx                    # ecx <- BBBBbbbb
     leal    (rPC,%ecx,2), %ecx              # ecx <- PC + BBBBbbbb*2
-    GET_VREG %eax rINST                     # eax <- vAA (array object)
+    GET_VREG %eax, rINST                    # eax <- vAA (array object)
     movl    %eax, OUT_ARG0(%esp)
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpFillArrayData              # (obj, payload)
+    call    SYMBOL(MterpFillArrayData)      # (obj, payload)
     REFRESH_IBASE
     testl   %eax, %eax                      # 0 means an exception is thrown
     jz      MterpPossibleException
@@ -1034,7 +1050,7 @@
  */
     /* throw vAA */
     EXPORT_PC
-    GET_VREG %eax rINST                     # eax<- vAA (exception object)
+    GET_VREG %eax, rINST                    # eax<- vAA (exception object)
     testl   %eax, %eax
     jz      common_errNullObject
     movl    rSELF,%ecx
@@ -1133,11 +1149,11 @@
  */
     /* op vAA, +BBBB */
     movl    2(rPC), %ecx                    # ecx <- BBBBbbbb
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     leal    (rPC,%ecx,2), %ecx              # ecx <- PC + BBBBbbbb*2
     movl    %eax, OUT_ARG1(%esp)            # ARG1 <- vAA
     movl    %ecx, OUT_ARG0(%esp)            # ARG0 <- switchData
-    call    MterpDoPackedSwitch
+    call    SYMBOL(MterpDoPackedSwitch)
     addl    %eax, %eax
     leal    (rPC, %eax), rPC
     FETCH_INST
@@ -1167,11 +1183,11 @@
  */
     /* op vAA, +BBBB */
     movl    2(rPC), %ecx                    # ecx <- BBBBbbbb
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     leal    (rPC,%ecx,2), %ecx              # ecx <- PC + BBBBbbbb*2
     movl    %eax, OUT_ARG1(%esp)            # ARG1 <- vAA
     movl    %ecx, OUT_ARG0(%esp)            # ARG0 <- switchData
-    call    MterpDoSparseSwitch
+    call    SYMBOL(MterpDoSparseSwitch)
     addl    %eax, %eax
     leal    (rPC, %eax), rPC
     FETCH_INST
@@ -1223,7 +1239,7 @@
 .Lop_cmpl_float_less:
     decl    %eax
 .Lop_cmpl_float_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -1264,7 +1280,7 @@
 .Lop_cmpg_float_less:
     decl    %eax
 .Lop_cmpg_float_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -1305,7 +1321,7 @@
 .Lop_cmpl_double_less:
     decl    %eax
 .Lop_cmpl_double_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -1346,7 +1362,7 @@
 .Lop_cmpg_double_less:
     decl    %eax
 .Lop_cmpg_double_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -1361,17 +1377,17 @@
     /* cmp-long vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1], BB is clobbered
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1], BB is clobbered
     cmpl    VREG_HIGH_ADDRESS(%ecx), %eax
     jl      .Lop_cmp_long_smaller
     jg      .Lop_cmp_long_bigger
     movzbl  2(rPC), %eax                    # eax <- BB, restore BB
-    GET_VREG %eax %eax                      # eax <- v[BB]
+    GET_VREG %eax, %eax                     # eax <- v[BB]
     sub     VREG_ADDRESS(%ecx), %eax
     ja      .Lop_cmp_long_bigger
     jb      .Lop_cmp_long_smaller
 .Lop_cmp_long_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .Lop_cmp_long_bigger:
@@ -1397,7 +1413,7 @@
     /* if-cmp vA, vB, +CCCC */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     andb    $0xf, %cl                      # ecx <- A
-    GET_VREG %eax %ecx                      # eax <- vA
+    GET_VREG %eax, %ecx                     # eax <- vA
     sarl    $4, rINST                      # rINST <- B
     cmpl    VREG_ADDRESS(rINST), %eax       # compare (vA, vB)
     movl    $2, %eax                       # assume not taken
@@ -1432,7 +1448,7 @@
     /* if-cmp vA, vB, +CCCC */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     andb    $0xf, %cl                      # ecx <- A
-    GET_VREG %eax %ecx                      # eax <- vA
+    GET_VREG %eax, %ecx                     # eax <- vA
     sarl    $4, rINST                      # rINST <- B
     cmpl    VREG_ADDRESS(rINST), %eax       # compare (vA, vB)
     movl    $2, %eax                       # assume not taken
@@ -1467,7 +1483,7 @@
     /* if-cmp vA, vB, +CCCC */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     andb    $0xf, %cl                      # ecx <- A
-    GET_VREG %eax %ecx                      # eax <- vA
+    GET_VREG %eax, %ecx                     # eax <- vA
     sarl    $4, rINST                      # rINST <- B
     cmpl    VREG_ADDRESS(rINST), %eax       # compare (vA, vB)
     movl    $2, %eax                       # assume not taken
@@ -1502,7 +1518,7 @@
     /* if-cmp vA, vB, +CCCC */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     andb    $0xf, %cl                      # ecx <- A
-    GET_VREG %eax %ecx                      # eax <- vA
+    GET_VREG %eax, %ecx                     # eax <- vA
     sarl    $4, rINST                      # rINST <- B
     cmpl    VREG_ADDRESS(rINST), %eax       # compare (vA, vB)
     movl    $2, %eax                       # assume not taken
@@ -1537,7 +1553,7 @@
     /* if-cmp vA, vB, +CCCC */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     andb    $0xf, %cl                      # ecx <- A
-    GET_VREG %eax %ecx                      # eax <- vA
+    GET_VREG %eax, %ecx                     # eax <- vA
     sarl    $4, rINST                      # rINST <- B
     cmpl    VREG_ADDRESS(rINST), %eax       # compare (vA, vB)
     movl    $2, %eax                       # assume not taken
@@ -1572,7 +1588,7 @@
     /* if-cmp vA, vB, +CCCC */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     andb    $0xf, %cl                      # ecx <- A
-    GET_VREG %eax %ecx                      # eax <- vA
+    GET_VREG %eax, %ecx                     # eax <- vA
     sarl    $4, rINST                      # rINST <- B
     cmpl    VREG_ADDRESS(rINST), %eax       # compare (vA, vB)
     movl    $2, %eax                       # assume not taken
@@ -1857,14 +1873,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     movl   MIRROR_INT_ARRAY_DATA_OFFSET(%eax,%ecx,4), %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -1877,15 +1893,15 @@
     /* aget-wide vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_WIDE_ARRAY_DATA_OFFSET(%eax,%ecx,8), %eax
     movq    (%eax), %xmm0                   # xmm0 <- vBB[vCC]
-    SET_WIDE_FP_VREG %xmm0 rINST            # vAA <- xmm0
+    SET_WIDE_FP_VREG %xmm0, rINST           # vAA <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -1900,17 +1916,17 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecs <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecs <- vCC (requested index)
     EXPORT_PC
     movl    %eax, OUT_ARG0(%esp)
     movl    %ecx, OUT_ARG1(%esp)
-    call    artAGetObjectFromMterp          # (array, index)
+    call    SYMBOL(artAGetObjectFromMterp)  # (array, index)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
-    SET_VREG_OBJECT %eax rINST
+    SET_VREG_OBJECT %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -1927,14 +1943,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     movzbl   MIRROR_BOOLEAN_ARRAY_DATA_OFFSET(%eax,%ecx,1), %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -1952,14 +1968,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     movsbl   MIRROR_BYTE_ARRAY_DATA_OFFSET(%eax,%ecx,1), %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -1977,14 +1993,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     movzwl   MIRROR_CHAR_ARRAY_DATA_OFFSET(%eax,%ecx,2), %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -2002,14 +2018,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     movswl   MIRROR_SHORT_ARRAY_DATA_OFFSET(%eax,%ecx,2), %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -2026,14 +2042,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_INT_ARRAY_DATA_OFFSET(%eax,%ecx,4), %eax
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movl  rINST, (%eax)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2048,14 +2064,14 @@
     /* aput-wide vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_WIDE_ARRAY_DATA_OFFSET(%eax,%ecx,8), %eax
-    GET_WIDE_FP_VREG %xmm0 rINST            # xmm0 <- vAA
+    GET_WIDE_FP_VREG %xmm0, rINST           # xmm0 <- vAA
     movq    %xmm0, (%eax)                   # vBB[vCC] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2073,7 +2089,7 @@
     movl    rPC, OUT_ARG1(%esp)
     REFRESH_INST 77
     movl    rINST, OUT_ARG2(%esp)
-    call    MterpAputObject            # (array, index)
+    call    SYMBOL(MterpAputObject)         # (array, index)
     REFRESH_IBASE
     testl   %eax, %eax
     jz      MterpPossibleException
@@ -2093,14 +2109,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_BOOLEAN_ARRAY_DATA_OFFSET(%eax,%ecx,1), %eax
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movb  rINSTbl, (%eax)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2119,14 +2135,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_BYTE_ARRAY_DATA_OFFSET(%eax,%ecx,1), %eax
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movb  rINSTbl, (%eax)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2145,14 +2161,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_CHAR_ARRAY_DATA_OFFSET(%eax,%ecx,2), %eax
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movw  rINSTw, (%eax)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2171,14 +2187,14 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_SHORT_ARRAY_DATA_OFFSET(%eax,%ecx,2), %eax
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movw  rINSTw, (%eax)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2203,16 +2219,16 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGet32InstanceFromCode
+    call    SYMBOL(artGet32InstanceFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf, rINSTbl                  # rINST <- A
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <-value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
     .else
-    SET_VREG %eax rINST                     # fp[A] <-value
+    SET_VREG %eax, rINST                    # fp[A] <-value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2236,13 +2252,13 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGet64InstanceFromCode
+    call    SYMBOL(artGet64InstanceFromCode)
     mov     rSELF, %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf, rINSTbl                  # rINST <- A
-    SET_VREG %eax rINST
-    SET_VREG_HIGH %edx rINST
+    SET_VREG %eax, rINST
+    SET_VREG_HIGH %edx, rINST
     REFRESH_IBASE_FROM_SELF %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2267,16 +2283,16 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGetObjInstanceFromCode
+    call    SYMBOL(artGetObjInstanceFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf, rINSTbl                  # rINST <- A
     .if 1
-    SET_VREG_OBJECT %eax rINST              # fp[A] <-value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
     .else
-    SET_VREG %eax rINST                     # fp[A] <-value
+    SET_VREG %eax, rINST                    # fp[A] <-value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2302,16 +2318,16 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGetBooleanInstanceFromCode
+    call    SYMBOL(artGetBooleanInstanceFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf, rINSTbl                  # rINST <- A
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <-value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
     .else
-    SET_VREG %eax rINST                     # fp[A] <-value
+    SET_VREG %eax, rINST                    # fp[A] <-value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2337,16 +2353,16 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGetByteInstanceFromCode
+    call    SYMBOL(artGetByteInstanceFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf, rINSTbl                  # rINST <- A
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <-value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
     .else
-    SET_VREG %eax rINST                     # fp[A] <-value
+    SET_VREG %eax, rINST                    # fp[A] <-value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2372,16 +2388,16 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGetCharInstanceFromCode
+    call    SYMBOL(artGetCharInstanceFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf, rINSTbl                  # rINST <- A
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <-value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
     .else
-    SET_VREG %eax rINST                     # fp[A] <-value
+    SET_VREG %eax, rINST                    # fp[A] <-value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2407,16 +2423,16 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGetShortInstanceFromCode
+    call    SYMBOL(artGetShortInstanceFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf, rINSTbl                  # rINST <- A
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <-value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
     .else
-    SET_VREG %eax rINST                     # fp[A] <-value
+    SET_VREG %eax, rINST                    # fp[A] <-value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2444,7 +2460,7 @@
     movl    %eax, OUT_ARG2(%esp)            # fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    artSet32InstanceFromMterp
+    call    SYMBOL(artSet32InstanceFromMterp)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
@@ -2468,7 +2484,7 @@
     movl    %eax, OUT_ARG2(%esp)            # &fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    artSet64InstanceFromMterp
+    call    SYMBOL(artSet64InstanceFromMterp)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
@@ -2486,7 +2502,7 @@
     movl    rINST, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpIputObject
+    call    SYMBOL(MterpIputObject)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -2516,7 +2532,7 @@
     movl    %eax, OUT_ARG2(%esp)            # fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    artSet8InstanceFromMterp
+    call    SYMBOL(artSet8InstanceFromMterp)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
@@ -2547,7 +2563,7 @@
     movl    %eax, OUT_ARG2(%esp)            # fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    artSet8InstanceFromMterp
+    call    SYMBOL(artSet8InstanceFromMterp)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
@@ -2578,7 +2594,7 @@
     movl    %eax, OUT_ARG2(%esp)            # fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    artSet16InstanceFromMterp
+    call    SYMBOL(artSet16InstanceFromMterp)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
@@ -2609,7 +2625,7 @@
     movl    %eax, OUT_ARG2(%esp)            # fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    artSet16InstanceFromMterp
+    call    SYMBOL(artSet16InstanceFromMterp)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
@@ -2634,15 +2650,15 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGet32StaticFromCode
+    call    SYMBOL(artGet32StaticFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     .else
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2663,12 +2679,12 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGet64StaticFromCode
+    call    SYMBOL(artGet64StaticFromCode)
     movl    rSELF, %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
-    SET_VREG %eax rINST                     # fp[A]<- low part
-    SET_VREG_HIGH %edx rINST                # fp[A+1]<- high part
+    SET_VREG %eax, rINST                    # fp[A]<- low part
+    SET_VREG_HIGH %edx, rINST               # fp[A+1]<- high part
     REFRESH_IBASE_FROM_SELF %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2691,15 +2707,15 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGetObjStaticFromCode
+    call    SYMBOL(artGetObjStaticFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     .if 1
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     .else
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2723,15 +2739,15 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGetBooleanStaticFromCode
+    call    SYMBOL(artGetBooleanStaticFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     .else
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2755,15 +2771,15 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGetByteStaticFromCode
+    call    SYMBOL(artGetByteStaticFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     .else
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2787,15 +2803,15 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGetCharStaticFromCode
+    call    SYMBOL(artGetCharStaticFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     .else
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2819,15 +2835,15 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGetShortStaticFromCode
+    call    SYMBOL(artGetShortStaticFromCode)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     .if 0
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     .else
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -2846,13 +2862,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax
     movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movl    rINST, OUT_ARG1(%esp)           # fp[AA]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG2(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artSet32StaticFromCode
+    call    SYMBOL(artSet32StaticFromCode)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
@@ -2877,7 +2893,7 @@
     movl    %eax, OUT_ARG2(%esp)            # &fp[AA]
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artSet64IndirectStaticFromMterp
+    call    SYMBOL(artSet64IndirectStaticFromMterp)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
@@ -2895,7 +2911,7 @@
     movl    rINST, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpSputObject
+    call    SYMBOL(MterpSputObject)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -2916,13 +2932,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax
     movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movl    rINST, OUT_ARG1(%esp)           # fp[AA]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG2(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artSet8StaticFromCode
+    call    SYMBOL(artSet8StaticFromCode)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
@@ -2944,13 +2960,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax
     movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movl    rINST, OUT_ARG1(%esp)           # fp[AA]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG2(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artSet8StaticFromCode
+    call    SYMBOL(artSet8StaticFromCode)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
@@ -2972,13 +2988,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax
     movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movl    rINST, OUT_ARG1(%esp)           # fp[AA]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG2(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artSet16StaticFromCode
+    call    SYMBOL(artSet16StaticFromCode)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
@@ -3000,13 +3016,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax
     movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movl    rINST, OUT_ARG1(%esp)           # fp[AA]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG2(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artSet16StaticFromCode
+    call    SYMBOL(artSet16StaticFromCode)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
@@ -3032,7 +3048,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 110
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeVirtual
+    call    SYMBOL(MterpInvokeVirtual)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3065,7 +3081,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 111
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeSuper
+    call    SYMBOL(MterpInvokeSuper)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3098,7 +3114,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 112
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeDirect
+    call    SYMBOL(MterpInvokeDirect)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3124,7 +3140,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 113
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeStatic
+    call    SYMBOL(MterpInvokeStatic)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3151,7 +3167,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 114
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeInterface
+    call    SYMBOL(MterpInvokeInterface)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3173,7 +3189,7 @@
     testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
@@ -3198,7 +3214,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 116
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeVirtualRange
+    call    SYMBOL(MterpInvokeVirtualRange)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3224,7 +3240,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 117
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeSuperRange
+    call    SYMBOL(MterpInvokeSuperRange)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3250,7 +3266,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 118
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeDirectRange
+    call    SYMBOL(MterpInvokeDirectRange)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3276,7 +3292,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 119
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeStaticRange
+    call    SYMBOL(MterpInvokeStaticRange)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3302,7 +3318,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 120
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeInterfaceRange
+    call    SYMBOL(MterpInvokeInterfaceRange)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -3343,10 +3359,10 @@
     /* unop vA, vB */
     movzbl  rINSTbl,%ecx                    # ecx <- A+
     sarl    $4,rINST                       # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf,%cl                       # ecx <- A
     negl    %eax
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -3362,10 +3378,10 @@
     /* unop vA, vB */
     movzbl  rINSTbl,%ecx                    # ecx <- A+
     sarl    $4,rINST                       # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf,%cl                       # ecx <- A
     notl %eax
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -3377,13 +3393,13 @@
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax %ecx                      # eax <- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # ecx <- v[B+1]
+    GET_VREG %eax, %ecx                     # eax <- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # ecx <- v[B+1]
     negl    %eax
     adcl    $0, %ecx
     negl    %ecx
-    SET_VREG %eax rINST                     # v[A+0] <- eax
-    SET_VREG_HIGH %ecx rINST                # v[A+1] <- ecx
+    SET_VREG %eax, rINST                    # v[A+0] <- eax
+    SET_VREG_HIGH %ecx, rINST               # v[A+1] <- ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -3395,12 +3411,12 @@
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax %ecx                      # eax <- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # ecx <- v[B+1]
+    GET_VREG %eax, %ecx                     # eax <- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # ecx <- v[B+1]
     notl    %eax
     notl    %ecx
-    SET_VREG %eax rINST                     # v[A+0] <- eax
-    SET_VREG_HIGH %ecx rINST                # v[A+1] <- ecx
+    SET_VREG %eax, rINST                    # v[A+0] <- eax
+    SET_VREG_HIGH %ecx, rINST               # v[A+1] <- ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -3456,12 +3472,12 @@
     /* int to long vA, vB */
     movzbl  rINSTbl, %eax                   # eax <- +A
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     andb    $0xf, rINSTbl                  # rINST <- A
     movl    rIBASE, %ecx                    # cltd trashes rIBASE/edx
     cltd                                    # rINST:eax<- sssssssBBBBBBBB
-    SET_VREG_HIGH rIBASE rINST              # v[A+1] <- rIBASE
-    SET_VREG %eax rINST                     # v[A+0] <- %eax
+    SET_VREG_HIGH rIBASE, rINST             # v[A+1] <- rIBASE
+    SET_VREG %eax, rINST                    # v[A+0] <- %eax
     movl    %ecx, rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -3523,11 +3539,11 @@
     movzbl  rINSTbl, %eax                   # eax <- BA
     andb    $0xf, %al                      # eax <- A
     shrl    $4, rINST                      # rINST <- B
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     .if 0
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -3904,10 +3920,10 @@
     /* unop vA, vB */
     movzbl  rINSTbl,%ecx                    # ecx <- A+
     sarl    $4,rINST                       # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf,%cl                       # ecx <- A
     movsbl  %al, %eax
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -3923,10 +3939,10 @@
     /* unop vA, vB */
     movzbl  rINSTbl,%ecx                    # ecx <- A+
     sarl    $4,rINST                       # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf,%cl                       # ecx <- A
     movzwl  %ax,%eax
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -3942,10 +3958,10 @@
     /* unop vA, vB */
     movzbl  rINSTbl,%ecx                    # ecx <- A+
     sarl    $4,rINST                       # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf,%cl                       # ecx <- A
     movswl %ax, %eax
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -3966,9 +3982,9 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     addl    (rFP,%ecx,4), %eax                                  # ex: addl    (rFP,%ecx,4),%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -3989,9 +4005,9 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     subl    (rFP,%ecx,4), %eax                                  # ex: addl    (rFP,%ecx,4),%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4005,11 +4021,11 @@
     /* mul vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     mov     rIBASE, LOCAL0(%esp)
     imull   (rFP,%ecx,4), %eax              # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -4024,8 +4040,8 @@
     /* div/rem vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
-    GET_VREG %ecx %ecx                      # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- vBB
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
     mov     rIBASE, LOCAL0(%esp)
     testl   %ecx, %ecx
     je      common_errDivideByZero
@@ -4061,7 +4077,7 @@
     xorl    %edx, %edx                      # Clear %edx before divide
     div     %cx
 .Lop_div_int_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -4078,8 +4094,8 @@
     /* div/rem vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
-    GET_VREG %ecx %ecx                      # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- vBB
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
     mov     rIBASE, LOCAL0(%esp)
     testl   %ecx, %ecx
     je      common_errDivideByZero
@@ -4115,7 +4131,7 @@
     xorl    %edx, %edx                      # Clear %edx before divide
     div     %cx
 .Lop_rem_int_finish:
-    SET_VREG rIBASE rINST
+    SET_VREG rIBASE, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -4137,9 +4153,9 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     andl    (rFP,%ecx,4), %eax                                  # ex: addl    (rFP,%ecx,4),%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4160,9 +4176,9 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     orl     (rFP,%ecx,4), %eax                                  # ex: addl    (rFP,%ecx,4),%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4183,9 +4199,9 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     xorl    (rFP,%ecx,4), %eax                                  # ex: addl    (rFP,%ecx,4),%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4201,10 +4217,10 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC),%eax                     # eax <- BB
     movzbl  3(rPC),%ecx                     # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     sall    %cl, %eax                                  # ex: addl    %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4220,10 +4236,10 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC),%eax                     # eax <- BB
     movzbl  3(rPC),%ecx                     # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     sarl    %cl, %eax                                  # ex: addl    %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4239,10 +4255,10 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC),%eax                     # eax <- BB
     movzbl  3(rPC),%ecx                     # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     shrl    %cl, %eax                                  # ex: addl    %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4255,16 +4271,16 @@
  * Generic 64-bit binary operation.
  */
     /* binop vAA, vBB, vCC */
-    movzbl  2(rPC),%eax                     # eax <- BB
-    movzbl  3(rPC),%ecx                     # ecx <- CC
-    movl    rIBASE,LOCAL0(%esp)             # save rIBASE
-    GET_VREG rIBASE %eax                    # rIBASE <- v[BB+0]
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1]
+    movzbl  2(rPC), %eax                    # eax <- BB
+    movzbl  3(rPC), %ecx                    # ecx <- CC
+    movl    rIBASE, LOCAL0(%esp)            # save rIBASE
+    GET_VREG rIBASE, %eax                   # rIBASE <- v[BB+0]
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1]
     addl    (rFP,%ecx,4), rIBASE                                 # ex: addl   (rFP,%ecx,4),rIBASE
     adcl    4(rFP,%ecx,4), %eax                                 # ex: adcl   4(rFP,%ecx,4),%eax
-    SET_VREG rIBASE rINST                   # v[AA+0] <- rIBASE
-    movl    LOCAL0(%esp),rIBASE             # restore rIBASE
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG rIBASE, rINST                  # v[AA+0] <- rIBASE
+    movl    LOCAL0(%esp), rIBASE            # restore rIBASE
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4277,16 +4293,16 @@
  * Generic 64-bit binary operation.
  */
     /* binop vAA, vBB, vCC */
-    movzbl  2(rPC),%eax                     # eax <- BB
-    movzbl  3(rPC),%ecx                     # ecx <- CC
-    movl    rIBASE,LOCAL0(%esp)             # save rIBASE
-    GET_VREG rIBASE %eax                    # rIBASE <- v[BB+0]
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1]
+    movzbl  2(rPC), %eax                    # eax <- BB
+    movzbl  3(rPC), %ecx                    # ecx <- CC
+    movl    rIBASE, LOCAL0(%esp)            # save rIBASE
+    GET_VREG rIBASE, %eax                   # rIBASE <- v[BB+0]
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1]
     subl    (rFP,%ecx,4), rIBASE                                 # ex: addl   (rFP,%ecx,4),rIBASE
     sbbl    4(rFP,%ecx,4), %eax                                 # ex: adcl   4(rFP,%ecx,4),%eax
-    SET_VREG rIBASE rINST                   # v[AA+0] <- rIBASE
-    movl    LOCAL0(%esp),rIBASE             # restore rIBASE
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG rIBASE, rINST                  # v[AA+0] <- rIBASE
+    movl    LOCAL0(%esp), rIBASE            # restore rIBASE
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4323,9 +4339,9 @@
     mov     LOCAL0(%esp), rPC               # restore Interpreter PC
     mov     LOCAL1(%esp), rFP               # restore FP
     leal    (%ecx,rIBASE), rIBASE           # full result now in rIBASE:%eax
-    SET_VREG_HIGH rIBASE rINST              # v[B+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[B+1] <- rIBASE
     mov     LOCAL2(%esp), rIBASE            # restore IBASE
-    SET_VREG %eax rINST                     # v[B] <- eax
+    SET_VREG %eax, rINST                    # v[B] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -4340,18 +4356,18 @@
     mov     rIBASE, LOCAL0(%esp)            # save rIBASE/%edx
     mov     rINST, LOCAL1(%esp)             # save rINST/%ebx
     movzbl  3(rPC), %eax                    # eax <- CC
-    GET_VREG %ecx %eax
-    GET_VREG_HIGH %ebx %eax
+    GET_VREG %ecx, %eax
+    GET_VREG_HIGH %ebx, %eax
     movl    %ecx, %edx
     orl     %ebx, %ecx
     jz      common_errDivideByZero
     movzbl  2(rPC), %eax                    # eax <- BB
-    GET_VREG_HIGH %ecx %eax
-    GET_VREG %eax %eax
-    call    art_quick_ldiv
+    GET_VREG_HIGH %ecx, %eax
+    GET_VREG %eax, %eax
+    call    SYMBOL(art_quick_ldiv)
     mov     LOCAL1(%esp), rINST             # restore rINST/%ebx
-    SET_VREG_HIGH rIBASE rINST
-    SET_VREG %eax rINST
+    SET_VREG_HIGH rIBASE, rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE            # restore rIBASE/%edx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -4368,18 +4384,18 @@
     mov     rIBASE, LOCAL0(%esp)            # save rIBASE/%edx
     mov     rINST, LOCAL1(%esp)             # save rINST/%ebx
     movzbl  3(rPC), %eax                    # eax <- CC
-    GET_VREG %ecx %eax
-    GET_VREG_HIGH %ebx %eax
+    GET_VREG %ecx, %eax
+    GET_VREG_HIGH %ebx, %eax
     movl    %ecx, %edx
     orl     %ebx, %ecx
     jz      common_errDivideByZero
     movzbl  2(rPC), %eax                    # eax <- BB
-    GET_VREG_HIGH %ecx %eax
-    GET_VREG %eax %eax
-    call    art_quick_lmod
+    GET_VREG_HIGH %ecx, %eax
+    GET_VREG %eax, %eax
+    call    SYMBOL(art_quick_lmod)
     mov     LOCAL1(%esp), rINST             # restore rINST/%ebx
-    SET_VREG_HIGH rIBASE rINST
-    SET_VREG %eax rINST
+    SET_VREG_HIGH rIBASE, rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE            # restore rIBASE/%edx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -4393,16 +4409,16 @@
  * Generic 64-bit binary operation.
  */
     /* binop vAA, vBB, vCC */
-    movzbl  2(rPC),%eax                     # eax <- BB
-    movzbl  3(rPC),%ecx                     # ecx <- CC
-    movl    rIBASE,LOCAL0(%esp)             # save rIBASE
-    GET_VREG rIBASE %eax                    # rIBASE <- v[BB+0]
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1]
+    movzbl  2(rPC), %eax                    # eax <- BB
+    movzbl  3(rPC), %ecx                    # ecx <- CC
+    movl    rIBASE, LOCAL0(%esp)            # save rIBASE
+    GET_VREG rIBASE, %eax                   # rIBASE <- v[BB+0]
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1]
     andl    (rFP,%ecx,4), rIBASE                                 # ex: addl   (rFP,%ecx,4),rIBASE
     andl    4(rFP,%ecx,4), %eax                                 # ex: adcl   4(rFP,%ecx,4),%eax
-    SET_VREG rIBASE rINST                   # v[AA+0] <- rIBASE
-    movl    LOCAL0(%esp),rIBASE             # restore rIBASE
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG rIBASE, rINST                  # v[AA+0] <- rIBASE
+    movl    LOCAL0(%esp), rIBASE            # restore rIBASE
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4415,16 +4431,16 @@
  * Generic 64-bit binary operation.
  */
     /* binop vAA, vBB, vCC */
-    movzbl  2(rPC),%eax                     # eax <- BB
-    movzbl  3(rPC),%ecx                     # ecx <- CC
-    movl    rIBASE,LOCAL0(%esp)             # save rIBASE
-    GET_VREG rIBASE %eax                    # rIBASE <- v[BB+0]
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1]
+    movzbl  2(rPC), %eax                    # eax <- BB
+    movzbl  3(rPC), %ecx                    # ecx <- CC
+    movl    rIBASE, LOCAL0(%esp)            # save rIBASE
+    GET_VREG rIBASE, %eax                   # rIBASE <- v[BB+0]
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1]
     orl     (rFP,%ecx,4), rIBASE                                 # ex: addl   (rFP,%ecx,4),rIBASE
     orl     4(rFP,%ecx,4), %eax                                 # ex: adcl   4(rFP,%ecx,4),%eax
-    SET_VREG rIBASE rINST                   # v[AA+0] <- rIBASE
-    movl    LOCAL0(%esp),rIBASE             # restore rIBASE
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG rIBASE, rINST                  # v[AA+0] <- rIBASE
+    movl    LOCAL0(%esp), rIBASE            # restore rIBASE
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4437,16 +4453,16 @@
  * Generic 64-bit binary operation.
  */
     /* binop vAA, vBB, vCC */
-    movzbl  2(rPC),%eax                     # eax <- BB
-    movzbl  3(rPC),%ecx                     # ecx <- CC
-    movl    rIBASE,LOCAL0(%esp)             # save rIBASE
-    GET_VREG rIBASE %eax                    # rIBASE <- v[BB+0]
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1]
+    movzbl  2(rPC), %eax                    # eax <- BB
+    movzbl  3(rPC), %ecx                    # ecx <- CC
+    movl    rIBASE, LOCAL0(%esp)            # save rIBASE
+    GET_VREG rIBASE, %eax                   # rIBASE <- v[BB+0]
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1]
     xorl    (rFP,%ecx,4), rIBASE                                 # ex: addl   (rFP,%ecx,4),rIBASE
     xorl    4(rFP,%ecx,4), %eax                                 # ex: adcl   4(rFP,%ecx,4),%eax
-    SET_VREG rIBASE rINST                   # v[AA+0] <- rIBASE
-    movl    LOCAL0(%esp),rIBASE             # restore rIBASE
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG rIBASE, rINST                  # v[AA+0] <- rIBASE
+    movl    LOCAL0(%esp), rIBASE            # restore rIBASE
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -4469,9 +4485,9 @@
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE %eax               # ecx <- v[BB+1]
-    GET_VREG %ecx %ecx                      # ecx <- vCC
-    GET_VREG %eax %eax                      # eax <- v[BB+0]
+    GET_VREG_HIGH rIBASE, %eax              # ecx <- v[BB+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- v[BB+0]
     shldl   %eax,rIBASE
     sall    %cl, %eax
     testb   $32, %cl
@@ -4479,9 +4495,9 @@
     movl    %eax, rIBASE
     xorl    %eax, %eax
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- %eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- %eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -4503,9 +4519,9 @@
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE %eax               # rIBASE<- v[BB+1]
-    GET_VREG %ecx %ecx                      # ecx <- vCC
-    GET_VREG %eax %eax                      # eax <- v[BB+0]
+    GET_VREG_HIGH rIBASE, %eax              # rIBASE<- v[BB+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- v[BB+0]
     shrdl   rIBASE, %eax
     sarl    %cl, rIBASE
     testb   $32, %cl
@@ -4513,9 +4529,9 @@
     movl    rIBASE, %eax
     sarl    $31, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -4537,9 +4553,9 @@
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE %eax               # rIBASE <- v[BB+1]
-    GET_VREG %ecx %ecx                      # ecx <- vCC
-    GET_VREG %eax %eax                      # eax <- v[BB+0]
+    GET_VREG_HIGH rIBASE, %eax              # rIBASE <- v[BB+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- v[BB+0]
     shrdl   rIBASE, %eax
     shrl    %cl, rIBASE
     testb   $32, %cl
@@ -4547,9 +4563,9 @@
     movl    rIBASE, %eax
     xorl    rIBASE, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[BB+0] <- eax
+    SET_VREG %eax, rINST                    # v[BB+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -4728,7 +4744,7 @@
     /* binop/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf, %cl                      # ecx <- A
     addl    %eax, (rFP,%ecx,4)                                  # for ex: addl   %eax,(rFP,%ecx,4)
     CLEAR_REF %ecx
@@ -4753,7 +4769,7 @@
     /* binop/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf, %cl                      # ecx <- A
     subl    %eax, (rFP,%ecx,4)                                  # for ex: addl   %eax,(rFP,%ecx,4)
     CLEAR_REF %ecx
@@ -4767,12 +4783,12 @@
     /* mul vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf, %cl                      # ecx <- A
     mov     rIBASE, LOCAL0(%esp)
     imull   (rFP,%ecx,4), %eax              # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -4788,9 +4804,9 @@
     movzx   rINSTbl, %ecx                   # eax <- BA
     mov     rIBASE, LOCAL0(%esp)
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- vBB
+    GET_VREG %eax, rINST                    # eax <- vBB
     testl   %ecx, %ecx
     je      common_errDivideByZero
     cmpl    $-1, %ecx
@@ -4798,14 +4814,14 @@
     cmpl    $0x80000000, %eax
     jne     .Lop_div_int_2addr_continue_div2addr
     movl    $0x80000000, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 .Lop_div_int_2addr_continue_div2addr:
     cltd
     idivl   %ecx
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -4823,9 +4839,9 @@
     movzx   rINSTbl, %ecx                   # eax <- BA
     mov     rIBASE, LOCAL0(%esp)
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- vBB
+    GET_VREG %eax, rINST                    # eax <- vBB
     testl   %ecx, %ecx
     je      common_errDivideByZero
     cmpl    $-1, %ecx
@@ -4833,14 +4849,14 @@
     cmpl    $0x80000000, %eax
     jne     .Lop_rem_int_2addr_continue_div2addr
     movl    $0, rIBASE
-    SET_VREG rIBASE rINST
+    SET_VREG rIBASE, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 .Lop_rem_int_2addr_continue_div2addr:
     cltd
     idivl   %ecx
-    SET_VREG rIBASE rINST
+    SET_VREG rIBASE, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -4863,7 +4879,7 @@
     /* binop/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf, %cl                      # ecx <- A
     andl    %eax, (rFP,%ecx,4)                                  # for ex: addl   %eax,(rFP,%ecx,4)
     CLEAR_REF %ecx
@@ -4888,7 +4904,7 @@
     /* binop/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf, %cl                      # ecx <- A
     orl     %eax, (rFP,%ecx,4)                                  # for ex: addl   %eax,(rFP,%ecx,4)
     CLEAR_REF %ecx
@@ -4913,7 +4929,7 @@
     /* binop/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $0xf, %cl                      # ecx <- A
     xorl    %eax, (rFP,%ecx,4)                                  # for ex: addl   %eax,(rFP,%ecx,4)
     CLEAR_REF %ecx
@@ -4931,11 +4947,11 @@
     /* shift/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # eax <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     sall    %cl, %eax                                  # ex: sarl %cl, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -4950,11 +4966,11 @@
     /* shift/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # eax <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     sarl    %cl, %eax                                  # ex: sarl %cl, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -4969,11 +4985,11 @@
     /* shift/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # eax <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     shrl    %cl, %eax                                  # ex: sarl %cl, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 
@@ -4986,11 +5002,11 @@
  * Generic 64-bit binary operation.
  */
     /* binop/2addr vA, vB */
-    movzbl  rINSTbl,%ecx                    # ecx<- BA
-    sarl    $4,%ecx                        # ecx<- B
-    GET_VREG %eax %ecx                      # eax<- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # eax<- v[B+1]
-    andb    $0xF,rINSTbl                   # rINST<- A
+    movzbl  rINSTbl, %ecx                   # ecx<- BA
+    sarl    $4, %ecx                       # ecx<- B
+    GET_VREG %eax, %ecx                     # eax<- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # eax<- v[B+1]
+    andb    $0xF, rINSTbl                  # rINST<- A
     addl    %eax, (rFP,rINST,4)                                 # ex: addl   %eax,(rFP,rINST,4)
     adcl    %ecx, 4(rFP,rINST,4)                                 # ex: adcl   %ecx,4(rFP,rINST,4)
     CLEAR_WIDE_REF rINST
@@ -5006,11 +5022,11 @@
  * Generic 64-bit binary operation.
  */
     /* binop/2addr vA, vB */
-    movzbl  rINSTbl,%ecx                    # ecx<- BA
-    sarl    $4,%ecx                        # ecx<- B
-    GET_VREG %eax %ecx                      # eax<- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # eax<- v[B+1]
-    andb    $0xF,rINSTbl                   # rINST<- A
+    movzbl  rINSTbl, %ecx                   # ecx<- BA
+    sarl    $4, %ecx                       # ecx<- B
+    GET_VREG %eax, %ecx                     # eax<- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # eax<- v[B+1]
+    andb    $0xF, rINSTbl                  # rINST<- A
     subl    %eax, (rFP,rINST,4)                                 # ex: addl   %eax,(rFP,rINST,4)
     sbbl    %ecx, 4(rFP,rINST,4)                                 # ex: adcl   %ecx,4(rFP,rINST,4)
     CLEAR_WIDE_REF rINST
@@ -5072,17 +5088,17 @@
     andb    $0xf, rINSTbl                  # rINST <- A
     mov     rINST, LOCAL1(%esp)             # save rINST/%ebx
     movl    %ebx, %ecx
-    GET_VREG %edx %eax
-    GET_VREG_HIGH %ebx %eax
+    GET_VREG %edx, %eax
+    GET_VREG_HIGH %ebx, %eax
     movl    %edx, %eax
     orl     %ebx, %eax
     jz      common_errDivideByZero
-    GET_VREG %eax %ecx
-    GET_VREG_HIGH %ecx %ecx
-    call    art_quick_ldiv
+    GET_VREG %eax, %ecx
+    GET_VREG_HIGH %ecx, %ecx
+    call    SYMBOL(art_quick_ldiv)
     mov     LOCAL1(%esp), rINST             # restore rINST/%ebx
-    SET_VREG_HIGH rIBASE rINST
-    SET_VREG %eax rINST
+    SET_VREG_HIGH rIBASE, rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE            # restore rIBASE/%edx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -5102,17 +5118,17 @@
     andb    $0xf, rINSTbl                  # rINST <- A
     mov     rINST, LOCAL1(%esp)             # save rINST/%ebx
     movl    %ebx, %ecx
-    GET_VREG %edx %eax
-    GET_VREG_HIGH %ebx %eax
+    GET_VREG %edx, %eax
+    GET_VREG_HIGH %ebx, %eax
     movl    %edx, %eax
     orl     %ebx, %eax
     jz      common_errDivideByZero
-    GET_VREG %eax %ecx
-    GET_VREG_HIGH %ecx %ecx
-    call    art_quick_lmod
+    GET_VREG %eax, %ecx
+    GET_VREG_HIGH %ecx, %ecx
+    call    SYMBOL(art_quick_lmod)
     mov     LOCAL1(%esp), rINST             # restore rINST/%ebx
-    SET_VREG_HIGH rIBASE rINST
-    SET_VREG %eax rINST
+    SET_VREG_HIGH rIBASE, rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE            # restore rIBASE/%edx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
@@ -5126,11 +5142,11 @@
  * Generic 64-bit binary operation.
  */
     /* binop/2addr vA, vB */
-    movzbl  rINSTbl,%ecx                    # ecx<- BA
-    sarl    $4,%ecx                        # ecx<- B
-    GET_VREG %eax %ecx                      # eax<- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # eax<- v[B+1]
-    andb    $0xF,rINSTbl                   # rINST<- A
+    movzbl  rINSTbl, %ecx                   # ecx<- BA
+    sarl    $4, %ecx                       # ecx<- B
+    GET_VREG %eax, %ecx                     # eax<- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # eax<- v[B+1]
+    andb    $0xF, rINSTbl                  # rINST<- A
     andl    %eax, (rFP,rINST,4)                                 # ex: addl   %eax,(rFP,rINST,4)
     andl    %ecx, 4(rFP,rINST,4)                                 # ex: adcl   %ecx,4(rFP,rINST,4)
     CLEAR_WIDE_REF rINST
@@ -5146,11 +5162,11 @@
  * Generic 64-bit binary operation.
  */
     /* binop/2addr vA, vB */
-    movzbl  rINSTbl,%ecx                    # ecx<- BA
-    sarl    $4,%ecx                        # ecx<- B
-    GET_VREG %eax %ecx                      # eax<- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # eax<- v[B+1]
-    andb    $0xF,rINSTbl                   # rINST<- A
+    movzbl  rINSTbl, %ecx                   # ecx<- BA
+    sarl    $4, %ecx                       # ecx<- B
+    GET_VREG %eax, %ecx                     # eax<- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # eax<- v[B+1]
+    andb    $0xF, rINSTbl                  # rINST<- A
     orl     %eax, (rFP,rINST,4)                                 # ex: addl   %eax,(rFP,rINST,4)
     orl     %ecx, 4(rFP,rINST,4)                                 # ex: adcl   %ecx,4(rFP,rINST,4)
     CLEAR_WIDE_REF rINST
@@ -5166,11 +5182,11 @@
  * Generic 64-bit binary operation.
  */
     /* binop/2addr vA, vB */
-    movzbl  rINSTbl,%ecx                    # ecx<- BA
-    sarl    $4,%ecx                        # ecx<- B
-    GET_VREG %eax %ecx                      # eax<- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # eax<- v[B+1]
-    andb    $0xF,rINSTbl                   # rINST<- A
+    movzbl  rINSTbl, %ecx                   # ecx<- BA
+    sarl    $4, %ecx                       # ecx<- B
+    GET_VREG %eax, %ecx                     # eax<- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # eax<- v[B+1]
+    andb    $0xF, rINSTbl                  # rINST<- A
     xorl    %eax, (rFP,rINST,4)                                 # ex: addl   %eax,(rFP,rINST,4)
     xorl    %ecx, 4(rFP,rINST,4)                                 # ex: adcl   %ecx,4(rFP,rINST,4)
     CLEAR_WIDE_REF rINST
@@ -5191,11 +5207,11 @@
     /* rINSTw gets AA */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
     sarl    $4, %ecx                       # ecx <- B
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE rINST              # rIBASE <- v[AA+1]
-    GET_VREG %ecx %ecx                      # ecx <- vBB
+    GET_VREG_HIGH rIBASE, rINST             # rIBASE <- v[AA+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vBB
     shldl   %eax, rIBASE
     sall    %cl, %eax
     testb   $32, %cl
@@ -5203,9 +5219,9 @@
     movl    %eax, rIBASE
     xorl    %eax, %eax
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -5222,11 +5238,11 @@
     /* rINSTw gets AA */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
     sarl    $4, %ecx                       # ecx <- B
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE rINST              # rIBASE <- v[AA+1]
-    GET_VREG %ecx %ecx                      # ecx <- vBB
+    GET_VREG_HIGH rIBASE, rINST             # rIBASE <- v[AA+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vBB
     shrdl   rIBASE, %eax
     sarl    %cl, rIBASE
     testb   $32, %cl
@@ -5234,9 +5250,9 @@
     movl    rIBASE, %eax
     sarl    $31, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -5253,11 +5269,11 @@
     /* rINSTw gets AA */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
     sarl    $4, %ecx                       # ecx <- B
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE rINST              # rIBASE <- v[AA+1]
-    GET_VREG %ecx %ecx                      # ecx <- vBB
+    GET_VREG_HIGH rIBASE, rINST             # rIBASE <- v[AA+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vBB
     shrdl   rIBASE, %eax
     shrl    %cl, rIBASE
     testb   $32, %cl
@@ -5265,9 +5281,9 @@
     movl    rIBASE, %eax
     xorl    rIBASE, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 /* ------------------------------ */
@@ -5455,11 +5471,11 @@
     /* binop/lit16 vA, vB, #+CCCC */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     addl    %ecx, %eax                                  # for example: addl %ecx, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5481,11 +5497,11 @@
     /* binop/lit16 vA, vB, #+CCCC */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     subl    %eax, %ecx                                  # for example: addl %ecx, %eax
-    SET_VREG %ecx rINST
+    SET_VREG %ecx, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5497,13 +5513,13 @@
     /* Need A in rINST, ssssCCCC in ecx, vB in eax */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     mov     rIBASE, LOCAL0(%esp)
     imull   %ecx, %eax                      # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -5519,7 +5535,7 @@
     /* Need A in rINST, ssssCCCC in ecx, vB in eax */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     testl   %ecx, %ecx
@@ -5529,14 +5545,14 @@
     cmpl    $0x80000000, %eax
     jne     .Lop_div_int_lit16_continue_div
     movl    $0x80000000, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .Lop_div_int_lit16_continue_div:
     mov     rIBASE, LOCAL0(%esp)
     cltd
     idivl   %ecx
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -5554,7 +5570,7 @@
     /* Need A in rINST, ssssCCCC in ecx, vB in eax */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     testl   %ecx, %ecx
@@ -5564,14 +5580,14 @@
     cmpl    $0x80000000, %eax
     jne     .Lop_rem_int_lit16_continue_div
     movl    $0, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .Lop_rem_int_lit16_continue_div:
     mov     rIBASE, LOCAL0(%esp)
     cltd
     idivl   %ecx
-    SET_VREG rIBASE rINST
+    SET_VREG rIBASE, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -5593,11 +5609,11 @@
     /* binop/lit16 vA, vB, #+CCCC */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     andl    %ecx, %eax                                  # for example: addl %ecx, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5618,11 +5634,11 @@
     /* binop/lit16 vA, vB, #+CCCC */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     orl     %ecx, %eax                                  # for example: addl %ecx, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5643,11 +5659,11 @@
     /* binop/lit16 vA, vB, #+CCCC */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $0xf, rINSTbl                  # rINST <- A
     xorl    %ecx, %eax                                  # for example: addl %ecx, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5669,9 +5685,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     addl    %ecx, %eax                                  # ex: addl %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5693,9 +5709,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     subl    %eax, %ecx                                  # ex: addl %ecx,%eax
-    SET_VREG %ecx rINST
+    SET_VREG %ecx, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5706,11 +5722,11 @@
     /* mul/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG  %eax  %eax                    # eax <- rBB
+    GET_VREG  %eax, %eax                    # eax <- rBB
     mov     rIBASE, LOCAL0(%esp)
     imull   %ecx, %eax                      # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -5725,7 +5741,7 @@
     /* div/rem/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG  %eax %eax                     # eax <- rBB
+    GET_VREG  %eax, %eax                    # eax <- rBB
     testl   %ecx, %ecx
     je      common_errDivideByZero
     cmpl    $0x80000000, %eax
@@ -5733,14 +5749,14 @@
     cmpl    $-1, %ecx
     jne     .Lop_div_int_lit8_continue_div
     movl    $0x80000000, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .Lop_div_int_lit8_continue_div:
     mov     rIBASE, LOCAL0(%esp)
     cltd
     idivl   %ecx
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -5757,7 +5773,7 @@
     /* div/rem/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG  %eax %eax                     # eax <- rBB
+    GET_VREG  %eax, %eax                    # eax <- rBB
     testl   %ecx, %ecx
     je      common_errDivideByZero
     cmpl    $0x80000000, %eax
@@ -5765,14 +5781,14 @@
     cmpl    $-1, %ecx
     jne     .Lop_rem_int_lit8_continue_div
     movl    $0, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .Lop_rem_int_lit8_continue_div:
     mov     rIBASE, LOCAL0(%esp)
     cltd
     idivl   %ecx
-    SET_VREG rIBASE rINST
+    SET_VREG rIBASE, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -5795,9 +5811,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     andl    %ecx, %eax                                  # ex: addl %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5819,9 +5835,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     orl     %ecx, %eax                                  # ex: addl %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5843,9 +5859,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     xorl    %ecx, %eax                                  # ex: addl %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5867,9 +5883,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     sall    %cl, %eax                                  # ex: addl %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5891,9 +5907,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     sarl    %cl, %eax                                  # ex: addl %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5915,9 +5931,9 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     shrl    %cl, %eax                                  # ex: addl %ecx,%eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -5929,13 +5945,13 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     movl (%ecx,%eax,1), %eax
     andb    $0xf,rINSTbl                   # rINST <- A
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -5945,13 +5961,13 @@
     /* iget-wide-quick vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     movq    (%ecx,%eax,1), %xmm0
     andb    $0xf, rINSTbl                  # rINST <- A
-    SET_WIDE_FP_VREG %xmm0 rINST
+    SET_WIDE_FP_VREG %xmm0, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -5962,18 +5978,18 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     movl    %ecx, OUT_ARG0(%esp)
     movl    %eax, OUT_ARG1(%esp)
     EXPORT_PC
-    call    artIGetObjectFromMterp          # (obj, offset)
+    call    SYMBOL(artIGetObjectFromMterp)  # (obj, offset)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $0xf,rINSTbl                   # rINST <- A
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 /* ------------------------------ */
@@ -5984,11 +6000,11 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG rINST rINST                    # rINST <- v[A]
+    GET_VREG rINST, rINST                   # rINST <- v[A]
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     movl    rINST, (%ecx,%eax,1)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
@@ -6000,13 +6016,13 @@
     /* iput-wide-quick vA, vB, offset@CCCC */
     movzbl    rINSTbl, %ecx                 # ecx<- BA
     sarl      $4, %ecx                     # ecx<- B
-    GET_VREG  %ecx %ecx                     # vB (object we're operating on)
+    GET_VREG  %ecx, %ecx                    # vB (object we're operating on)
     testl     %ecx, %ecx                    # is object null?
     je        common_errNullObject
     movzwl    2(rPC), %eax                  # eax<- field byte offset
     leal      (%ecx,%eax,1), %ecx           # ecx<- Address of 64-bit target
     andb      $0xf, rINSTbl                # rINST<- A
-    GET_WIDE_FP_VREG %xmm0 rINST            # xmm0<- fp[A]/fp[A+1]
+    GET_WIDE_FP_VREG %xmm0, rINST           # xmm0<- fp[A]/fp[A+1]
     movq      %xmm0, (%ecx)                 # obj.field<- r0/r1
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
@@ -6020,7 +6036,7 @@
     movl    rPC, OUT_ARG1(%esp)
     REFRESH_INST 232
     movl    rINST, OUT_ARG2(%esp)
-    call    MterpIputObjectQuick
+    call    SYMBOL(MterpIputObjectQuick)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -6045,7 +6061,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 233
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeVirtualQuick
+    call    SYMBOL(MterpInvokeVirtualQuick)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -6071,7 +6087,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST 234
     movl    rINST, OUT_ARG3(%esp)
-    call    MterpInvokeVirtualQuickRange
+    call    SYMBOL(MterpInvokeVirtualQuickRange)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
@@ -6087,11 +6103,11 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG rINST rINST                    # rINST <- v[A]
+    GET_VREG rINST, rINST                   # rINST <- v[A]
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     movb    rINSTbl, (%ecx,%eax,1)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
@@ -6106,11 +6122,11 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG rINST rINST                    # rINST <- v[A]
+    GET_VREG rINST, rINST                   # rINST <- v[A]
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     movb    rINSTbl, (%ecx,%eax,1)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
@@ -6125,11 +6141,11 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG rINST rINST                    # rINST <- v[A]
+    GET_VREG rINST, rINST                   # rINST <- v[A]
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     movw    rINSTw, (%ecx,%eax,1)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
@@ -6144,11 +6160,11 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     andb    $0xf, rINSTbl                  # rINST <- A
-    GET_VREG rINST rINST                    # rINST <- v[A]
+    GET_VREG rINST, rINST                   # rINST <- v[A]
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     movw    rINSTw, (%ecx,%eax,1)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
@@ -6163,13 +6179,13 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     movsbl (%ecx,%eax,1), %eax
     andb    $0xf,rINSTbl                   # rINST <- A
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -6182,13 +6198,13 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     movsbl (%ecx,%eax,1), %eax
     andb    $0xf,rINSTbl                   # rINST <- A
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -6201,13 +6217,13 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     movzwl (%ecx,%eax,1), %eax
     andb    $0xf,rINSTbl                   # rINST <- A
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -6220,13 +6236,13 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     movswl (%ecx,%eax,1), %eax
     andb    $0xf,rINSTbl                   # rINST <- A
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 
@@ -6350,31 +6366,31 @@
 
 
     .balign 128
-    .size   artMterpAsmInstructionStart, .-artMterpAsmInstructionStart
-    .global artMterpAsmInstructionEnd
-artMterpAsmInstructionEnd:
+    SIZE(SYMBOL(artMterpAsmInstructionStart),SYMBOL(artMterpAsmInstructionStart))
+    .global SYMBOL(artMterpAsmInstructionEnd)
+SYMBOL(artMterpAsmInstructionEnd):
 
 /*
  * ===========================================================================
  *  Sister implementations
  * ===========================================================================
  */
-    .global artMterpAsmSisterStart
-    .type   artMterpAsmSisterStart, %function
+    .global SYMBOL(artMterpAsmSisterStart)
+    FUNCTION_TYPE(SYMBOL(artMterpAsmSisterStart))
     .text
     .balign 4
-artMterpAsmSisterStart:
+SYMBOL(artMterpAsmSisterStart):
 
-    .size   artMterpAsmSisterStart, .-artMterpAsmSisterStart
-    .global artMterpAsmSisterEnd
-artMterpAsmSisterEnd:
+    SIZE(SYMBOL(artMterpAsmSisterStart),SYMBOL(artMterpAsmSisterStart))
+    .global SYMBOL(artMterpAsmSisterEnd)
+SYMBOL(artMterpAsmSisterEnd):
 
 
-    .global artMterpAsmAltInstructionStart
-    .type   artMterpAsmAltInstructionStart, %function
+    .global SYMBOL(artMterpAsmAltInstructionStart)
+    FUNCTION_TYPE(SYMBOL(artMterpAsmAltInstructionStart))
     .text
 
-artMterpAsmAltInstructionStart = .L_ALT_op_nop
+SYMBOL(artMterpAsmAltInstructionStart) = .L_ALT_op_nop
 /* ------------------------------ */
     .balign 128
 .L_ALT_op_nop: /* 0x00 */
@@ -6396,7 +6412,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(0*128)
 
@@ -6421,7 +6437,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(1*128)
 
@@ -6446,7 +6462,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(2*128)
 
@@ -6471,7 +6487,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(3*128)
 
@@ -6496,7 +6512,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(4*128)
 
@@ -6521,7 +6537,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(5*128)
 
@@ -6546,7 +6562,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(6*128)
 
@@ -6571,7 +6587,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(7*128)
 
@@ -6596,7 +6612,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(8*128)
 
@@ -6621,7 +6637,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(9*128)
 
@@ -6646,7 +6662,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(10*128)
 
@@ -6671,7 +6687,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(11*128)
 
@@ -6696,7 +6712,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(12*128)
 
@@ -6721,7 +6737,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(13*128)
 
@@ -6746,7 +6762,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(14*128)
 
@@ -6771,7 +6787,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(15*128)
 
@@ -6796,7 +6812,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(16*128)
 
@@ -6821,7 +6837,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(17*128)
 
@@ -6846,7 +6862,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(18*128)
 
@@ -6871,7 +6887,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(19*128)
 
@@ -6896,7 +6912,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(20*128)
 
@@ -6921,7 +6937,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(21*128)
 
@@ -6946,7 +6962,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(22*128)
 
@@ -6971,7 +6987,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(23*128)
 
@@ -6996,7 +7012,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(24*128)
 
@@ -7021,7 +7037,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(25*128)
 
@@ -7046,7 +7062,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(26*128)
 
@@ -7071,7 +7087,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(27*128)
 
@@ -7096,7 +7112,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(28*128)
 
@@ -7121,7 +7137,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(29*128)
 
@@ -7146,7 +7162,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(30*128)
 
@@ -7171,7 +7187,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(31*128)
 
@@ -7196,7 +7212,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(32*128)
 
@@ -7221,7 +7237,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(33*128)
 
@@ -7246,7 +7262,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(34*128)
 
@@ -7271,7 +7287,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(35*128)
 
@@ -7296,7 +7312,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(36*128)
 
@@ -7321,7 +7337,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(37*128)
 
@@ -7346,7 +7362,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(38*128)
 
@@ -7371,7 +7387,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(39*128)
 
@@ -7396,7 +7412,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(40*128)
 
@@ -7421,7 +7437,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(41*128)
 
@@ -7446,7 +7462,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(42*128)
 
@@ -7471,7 +7487,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(43*128)
 
@@ -7496,7 +7512,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(44*128)
 
@@ -7521,7 +7537,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(45*128)
 
@@ -7546,7 +7562,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(46*128)
 
@@ -7571,7 +7587,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(47*128)
 
@@ -7596,7 +7612,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(48*128)
 
@@ -7621,7 +7637,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(49*128)
 
@@ -7646,7 +7662,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(50*128)
 
@@ -7671,7 +7687,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(51*128)
 
@@ -7696,7 +7712,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(52*128)
 
@@ -7721,7 +7737,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(53*128)
 
@@ -7746,7 +7762,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(54*128)
 
@@ -7771,7 +7787,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(55*128)
 
@@ -7796,7 +7812,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(56*128)
 
@@ -7821,7 +7837,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(57*128)
 
@@ -7846,7 +7862,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(58*128)
 
@@ -7871,7 +7887,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(59*128)
 
@@ -7896,7 +7912,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(60*128)
 
@@ -7921,7 +7937,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(61*128)
 
@@ -7946,7 +7962,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(62*128)
 
@@ -7971,7 +7987,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(63*128)
 
@@ -7996,7 +8012,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(64*128)
 
@@ -8021,7 +8037,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(65*128)
 
@@ -8046,7 +8062,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(66*128)
 
@@ -8071,7 +8087,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(67*128)
 
@@ -8096,7 +8112,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(68*128)
 
@@ -8121,7 +8137,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(69*128)
 
@@ -8146,7 +8162,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(70*128)
 
@@ -8171,7 +8187,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(71*128)
 
@@ -8196,7 +8212,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(72*128)
 
@@ -8221,7 +8237,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(73*128)
 
@@ -8246,7 +8262,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(74*128)
 
@@ -8271,7 +8287,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(75*128)
 
@@ -8296,7 +8312,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(76*128)
 
@@ -8321,7 +8337,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(77*128)
 
@@ -8346,7 +8362,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(78*128)
 
@@ -8371,7 +8387,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(79*128)
 
@@ -8396,7 +8412,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(80*128)
 
@@ -8421,7 +8437,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(81*128)
 
@@ -8446,7 +8462,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(82*128)
 
@@ -8471,7 +8487,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(83*128)
 
@@ -8496,7 +8512,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(84*128)
 
@@ -8521,7 +8537,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(85*128)
 
@@ -8546,7 +8562,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(86*128)
 
@@ -8571,7 +8587,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(87*128)
 
@@ -8596,7 +8612,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(88*128)
 
@@ -8621,7 +8637,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(89*128)
 
@@ -8646,7 +8662,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(90*128)
 
@@ -8671,7 +8687,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(91*128)
 
@@ -8696,7 +8712,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(92*128)
 
@@ -8721,7 +8737,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(93*128)
 
@@ -8746,7 +8762,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(94*128)
 
@@ -8771,7 +8787,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(95*128)
 
@@ -8796,7 +8812,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(96*128)
 
@@ -8821,7 +8837,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(97*128)
 
@@ -8846,7 +8862,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(98*128)
 
@@ -8871,7 +8887,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(99*128)
 
@@ -8896,7 +8912,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(100*128)
 
@@ -8921,7 +8937,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(101*128)
 
@@ -8946,7 +8962,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(102*128)
 
@@ -8971,7 +8987,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(103*128)
 
@@ -8996,7 +9012,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(104*128)
 
@@ -9021,7 +9037,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(105*128)
 
@@ -9046,7 +9062,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(106*128)
 
@@ -9071,7 +9087,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(107*128)
 
@@ -9096,7 +9112,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(108*128)
 
@@ -9121,7 +9137,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(109*128)
 
@@ -9146,7 +9162,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(110*128)
 
@@ -9171,7 +9187,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(111*128)
 
@@ -9196,7 +9212,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(112*128)
 
@@ -9221,7 +9237,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(113*128)
 
@@ -9246,7 +9262,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(114*128)
 
@@ -9271,7 +9287,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(115*128)
 
@@ -9296,7 +9312,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(116*128)
 
@@ -9321,7 +9337,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(117*128)
 
@@ -9346,7 +9362,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(118*128)
 
@@ -9371,7 +9387,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(119*128)
 
@@ -9396,7 +9412,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(120*128)
 
@@ -9421,7 +9437,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(121*128)
 
@@ -9446,7 +9462,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(122*128)
 
@@ -9471,7 +9487,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(123*128)
 
@@ -9496,7 +9512,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(124*128)
 
@@ -9521,7 +9537,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(125*128)
 
@@ -9546,7 +9562,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(126*128)
 
@@ -9571,7 +9587,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(127*128)
 
@@ -9596,7 +9612,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(128*128)
 
@@ -9621,7 +9637,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(129*128)
 
@@ -9646,7 +9662,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(130*128)
 
@@ -9671,7 +9687,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(131*128)
 
@@ -9696,7 +9712,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(132*128)
 
@@ -9721,7 +9737,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(133*128)
 
@@ -9746,7 +9762,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(134*128)
 
@@ -9771,7 +9787,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(135*128)
 
@@ -9796,7 +9812,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(136*128)
 
@@ -9821,7 +9837,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(137*128)
 
@@ -9846,7 +9862,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(138*128)
 
@@ -9871,7 +9887,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(139*128)
 
@@ -9896,7 +9912,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(140*128)
 
@@ -9921,7 +9937,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(141*128)
 
@@ -9946,7 +9962,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(142*128)
 
@@ -9971,7 +9987,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(143*128)
 
@@ -9996,7 +10012,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(144*128)
 
@@ -10021,7 +10037,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(145*128)
 
@@ -10046,7 +10062,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(146*128)
 
@@ -10071,7 +10087,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(147*128)
 
@@ -10096,7 +10112,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(148*128)
 
@@ -10121,7 +10137,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(149*128)
 
@@ -10146,7 +10162,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(150*128)
 
@@ -10171,7 +10187,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(151*128)
 
@@ -10196,7 +10212,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(152*128)
 
@@ -10221,7 +10237,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(153*128)
 
@@ -10246,7 +10262,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(154*128)
 
@@ -10271,7 +10287,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(155*128)
 
@@ -10296,7 +10312,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(156*128)
 
@@ -10321,7 +10337,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(157*128)
 
@@ -10346,7 +10362,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(158*128)
 
@@ -10371,7 +10387,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(159*128)
 
@@ -10396,7 +10412,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(160*128)
 
@@ -10421,7 +10437,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(161*128)
 
@@ -10446,7 +10462,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(162*128)
 
@@ -10471,7 +10487,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(163*128)
 
@@ -10496,7 +10512,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(164*128)
 
@@ -10521,7 +10537,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(165*128)
 
@@ -10546,7 +10562,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(166*128)
 
@@ -10571,7 +10587,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(167*128)
 
@@ -10596,7 +10612,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(168*128)
 
@@ -10621,7 +10637,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(169*128)
 
@@ -10646,7 +10662,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(170*128)
 
@@ -10671,7 +10687,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(171*128)
 
@@ -10696,7 +10712,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(172*128)
 
@@ -10721,7 +10737,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(173*128)
 
@@ -10746,7 +10762,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(174*128)
 
@@ -10771,7 +10787,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(175*128)
 
@@ -10796,7 +10812,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(176*128)
 
@@ -10821,7 +10837,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(177*128)
 
@@ -10846,7 +10862,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(178*128)
 
@@ -10871,7 +10887,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(179*128)
 
@@ -10896,7 +10912,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(180*128)
 
@@ -10921,7 +10937,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(181*128)
 
@@ -10946,7 +10962,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(182*128)
 
@@ -10971,7 +10987,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(183*128)
 
@@ -10996,7 +11012,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(184*128)
 
@@ -11021,7 +11037,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(185*128)
 
@@ -11046,7 +11062,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(186*128)
 
@@ -11071,7 +11087,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(187*128)
 
@@ -11096,7 +11112,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(188*128)
 
@@ -11121,7 +11137,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(189*128)
 
@@ -11146,7 +11162,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(190*128)
 
@@ -11171,7 +11187,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(191*128)
 
@@ -11196,7 +11212,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(192*128)
 
@@ -11221,7 +11237,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(193*128)
 
@@ -11246,7 +11262,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(194*128)
 
@@ -11271,7 +11287,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(195*128)
 
@@ -11296,7 +11312,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(196*128)
 
@@ -11321,7 +11337,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(197*128)
 
@@ -11346,7 +11362,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(198*128)
 
@@ -11371,7 +11387,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(199*128)
 
@@ -11396,7 +11412,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(200*128)
 
@@ -11421,7 +11437,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(201*128)
 
@@ -11446,7 +11462,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(202*128)
 
@@ -11471,7 +11487,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(203*128)
 
@@ -11496,7 +11512,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(204*128)
 
@@ -11521,7 +11537,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(205*128)
 
@@ -11546,7 +11562,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(206*128)
 
@@ -11571,7 +11587,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(207*128)
 
@@ -11596,7 +11612,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(208*128)
 
@@ -11621,7 +11637,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(209*128)
 
@@ -11646,7 +11662,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(210*128)
 
@@ -11671,7 +11687,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(211*128)
 
@@ -11696,7 +11712,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(212*128)
 
@@ -11721,7 +11737,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(213*128)
 
@@ -11746,7 +11762,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(214*128)
 
@@ -11771,7 +11787,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(215*128)
 
@@ -11796,7 +11812,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(216*128)
 
@@ -11821,7 +11837,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(217*128)
 
@@ -11846,7 +11862,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(218*128)
 
@@ -11871,7 +11887,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(219*128)
 
@@ -11896,7 +11912,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(220*128)
 
@@ -11921,7 +11937,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(221*128)
 
@@ -11946,7 +11962,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(222*128)
 
@@ -11971,7 +11987,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(223*128)
 
@@ -11996,7 +12012,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(224*128)
 
@@ -12021,7 +12037,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(225*128)
 
@@ -12046,7 +12062,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(226*128)
 
@@ -12071,7 +12087,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(227*128)
 
@@ -12096,7 +12112,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(228*128)
 
@@ -12121,7 +12137,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(229*128)
 
@@ -12146,7 +12162,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(230*128)
 
@@ -12171,7 +12187,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(231*128)
 
@@ -12196,7 +12212,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(232*128)
 
@@ -12221,7 +12237,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(233*128)
 
@@ -12246,7 +12262,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(234*128)
 
@@ -12271,7 +12287,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(235*128)
 
@@ -12296,7 +12312,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(236*128)
 
@@ -12321,7 +12337,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(237*128)
 
@@ -12346,7 +12362,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(238*128)
 
@@ -12371,7 +12387,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(239*128)
 
@@ -12396,7 +12412,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(240*128)
 
@@ -12421,7 +12437,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(241*128)
 
@@ -12446,7 +12462,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(242*128)
 
@@ -12471,7 +12487,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(243*128)
 
@@ -12496,7 +12512,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(244*128)
 
@@ -12521,7 +12537,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(245*128)
 
@@ -12546,7 +12562,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(246*128)
 
@@ -12571,7 +12587,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(247*128)
 
@@ -12596,7 +12612,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(248*128)
 
@@ -12621,7 +12637,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(249*128)
 
@@ -12646,7 +12662,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(250*128)
 
@@ -12671,7 +12687,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(251*128)
 
@@ -12696,7 +12712,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(252*128)
 
@@ -12721,7 +12737,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(253*128)
 
@@ -12746,7 +12762,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(254*128)
 
@@ -12771,14 +12787,14 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(255*128)
 
     .balign 128
-    .size   artMterpAsmAltInstructionStart, .-artMterpAsmAltInstructionStart
-    .global artMterpAsmAltInstructionEnd
-artMterpAsmAltInstructionEnd:
+    SIZE(SYMBOL(artMterpAsmAltInstructionStart),SYMBOL(artMterpAsmAltInstructionStart))
+    .global SYMBOL(artMterpAsmAltInstructionEnd)
+SYMBOL(artMterpAsmAltInstructionEnd):
 /* File: x86/footer.S */
 /*
  * ===========================================================================
@@ -12802,7 +12818,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogDivideByZeroException
+    call    SYMBOL(MterpLogDivideByZeroException)
 #endif
     jmp     MterpCommonFallback
 
@@ -12813,7 +12829,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogArrayIndexException
+    call    SYMBOL(MterpLogArrayIndexException)
 #endif
     jmp     MterpCommonFallback
 
@@ -12824,7 +12840,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogNegativeArraySizeException
+    call    SYMBOL(MterpLogNegativeArraySizeException)
 #endif
     jmp     MterpCommonFallback
 
@@ -12835,7 +12851,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogNoSuchMethodException
+    call    SYMBOL(MterpLogNoSuchMethodException)
 #endif
     jmp     MterpCommonFallback
 
@@ -12846,7 +12862,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogNullObjectException
+    call    SYMBOL(MterpLogNullObjectException)
 #endif
     jmp     MterpCommonFallback
 
@@ -12857,7 +12873,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG0(%esp)
-    call    MterpLogExceptionThrownException
+    call    SYMBOL(MterpLogExceptionThrownException)
 #endif
     jmp     MterpCommonFallback
 
@@ -12870,7 +12886,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     movl    THREAD_FLAGS_OFFSET(%eax), %eax
     movl    %eax, OUT_ARG2(%esp)
-    call    MterpLogSuspendFallback
+    call    SYMBOL(MterpLogSuspendFallback)
 #endif
     jmp     MterpCommonFallback
 
@@ -12895,7 +12911,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpHandleException
+    call    SYMBOL(MterpHandleException)
     testl   %eax, %eax
     jz      MterpExceptionReturn
     REFRESH_IBASE
@@ -12919,7 +12935,7 @@
     testl   $(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
     REFRESH_IBASE
 1:
     GOTO_NEXT
@@ -12934,7 +12950,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogFallback
+    call    SYMBOL(MterpLogFallback)
 #endif
 MterpCommonFallback:
     xor     %eax, %eax
@@ -12965,5 +12981,5 @@
     ret
 
     .cfi_endproc
-    .size   ExecuteMterpImpl, .-ExecuteMterpImpl
+    SIZE(ExecuteMterpImpl,ExecuteMterpImpl)
 
diff --git a/runtime/interpreter/mterp/x86/alt_stub.S b/runtime/interpreter/mterp/x86/alt_stub.S
index 6462fc5..5a91167 100644
--- a/runtime/interpreter/mterp/x86/alt_stub.S
+++ b/runtime/interpreter/mterp/x86/alt_stub.S
@@ -15,6 +15,6 @@
     movl    %ecx, OUT_ARG0(%esp)
     leal    OFF_FP_SHADOWFRAME(rFP), %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    MterpCheckBefore                # (self, shadow_frame)
+    call    SYMBOL(MterpCheckBefore)        # (self, shadow_frame)
     REFRESH_IBASE
     jmp     .L_op_nop+(${opnum}*${handler_size_bytes})
diff --git a/runtime/interpreter/mterp/x86/bincmp.S b/runtime/interpreter/mterp/x86/bincmp.S
index a9a8c3a..27cf6ea 100644
--- a/runtime/interpreter/mterp/x86/bincmp.S
+++ b/runtime/interpreter/mterp/x86/bincmp.S
@@ -8,7 +8,7 @@
     /* if-cmp vA, vB, +CCCC */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     andb    $$0xf, %cl                      # ecx <- A
-    GET_VREG %eax %ecx                      # eax <- vA
+    GET_VREG %eax, %ecx                     # eax <- vA
     sarl    $$4, rINST                      # rINST <- B
     cmpl    VREG_ADDRESS(rINST), %eax       # compare (vA, vB)
     movl    $$2, %eax                       # assume not taken
diff --git a/runtime/interpreter/mterp/x86/bindiv.S b/runtime/interpreter/mterp/x86/bindiv.S
index 742f758..bb5b319 100644
--- a/runtime/interpreter/mterp/x86/bindiv.S
+++ b/runtime/interpreter/mterp/x86/bindiv.S
@@ -6,8 +6,8 @@
     /* div/rem vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
-    GET_VREG %ecx %ecx                      # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- vBB
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
     mov     rIBASE, LOCAL0(%esp)
     testl   %ecx, %ecx
     je      common_errDivideByZero
@@ -43,6 +43,6 @@
     xorl    %edx, %edx                      # Clear %edx before divide
     div     %cx
 .L${opcode}_finish:
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/bindiv2addr.S b/runtime/interpreter/mterp/x86/bindiv2addr.S
index ee7c523..e620996 100644
--- a/runtime/interpreter/mterp/x86/bindiv2addr.S
+++ b/runtime/interpreter/mterp/x86/bindiv2addr.S
@@ -7,9 +7,9 @@
     movzx   rINSTbl, %ecx                   # eax <- BA
     mov     rIBASE, LOCAL0(%esp)
     sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- vBB
+    GET_VREG %eax, rINST                    # eax <- vBB
     testl   %ecx, %ecx
     je      common_errDivideByZero
     cmpl    $$-1, %ecx
@@ -17,13 +17,13 @@
     cmpl    $$0x80000000, %eax
     jne     .L${opcode}_continue_div2addr
     movl    $special, $result
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
 .L${opcode}_continue_div2addr:
     cltd
     idivl   %ecx
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/bindivLit16.S b/runtime/interpreter/mterp/x86/bindivLit16.S
index a2c4334..be094ae 100644
--- a/runtime/interpreter/mterp/x86/bindivLit16.S
+++ b/runtime/interpreter/mterp/x86/bindivLit16.S
@@ -7,7 +7,7 @@
     /* Need A in rINST, ssssCCCC in ecx, vB in eax */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $$4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $$0xf, rINSTbl                  # rINST <- A
     testl   %ecx, %ecx
@@ -17,13 +17,13 @@
     cmpl    $$0x80000000, %eax
     jne     .L${opcode}_continue_div
     movl    $special, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .L${opcode}_continue_div:
     mov     rIBASE, LOCAL0(%esp)
     cltd
     idivl   %ecx
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/bindivLit8.S b/runtime/interpreter/mterp/x86/bindivLit8.S
index 61bee06..fddb545 100644
--- a/runtime/interpreter/mterp/x86/bindivLit8.S
+++ b/runtime/interpreter/mterp/x86/bindivLit8.S
@@ -6,7 +6,7 @@
     /* div/rem/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG  %eax %eax                     # eax <- rBB
+    GET_VREG  %eax, %eax                    # eax <- rBB
     testl   %ecx, %ecx
     je      common_errDivideByZero
     cmpl    $$0x80000000, %eax
@@ -14,13 +14,13 @@
     cmpl    $$-1, %ecx
     jne     .L${opcode}_continue_div
     movl    $special, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .L${opcode}_continue_div:
     mov     rIBASE, LOCAL0(%esp)
     cltd
     idivl   %ecx
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     mov     LOCAL0(%esp), rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/binop.S b/runtime/interpreter/mterp/x86/binop.S
index 5383f25..d895235 100644
--- a/runtime/interpreter/mterp/x86/binop.S
+++ b/runtime/interpreter/mterp/x86/binop.S
@@ -11,7 +11,7 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     $instr                                  # ex: addl    (rFP,%ecx,4),%eax
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/binop1.S b/runtime/interpreter/mterp/x86/binop1.S
index cd51d0c..5049bb3 100644
--- a/runtime/interpreter/mterp/x86/binop1.S
+++ b/runtime/interpreter/mterp/x86/binop1.S
@@ -6,8 +6,8 @@
     /* binop vAA, vBB, vCC */
     movzbl  2(rPC),%eax                     # eax <- BB
     movzbl  3(rPC),%ecx                     # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     $instr                                  # ex: addl    %ecx,%eax
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/binop2addr.S b/runtime/interpreter/mterp/x86/binop2addr.S
index abee4db..f126234 100644
--- a/runtime/interpreter/mterp/x86/binop2addr.S
+++ b/runtime/interpreter/mterp/x86/binop2addr.S
@@ -12,7 +12,7 @@
     /* binop/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $$4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $$0xf, %cl                      # ecx <- A
     $instr                                  # for ex: addl   %eax,(rFP,%ecx,4)
     CLEAR_REF %ecx
diff --git a/runtime/interpreter/mterp/x86/binopLit16.S b/runtime/interpreter/mterp/x86/binopLit16.S
index 6c7fe61..2fd59de 100644
--- a/runtime/interpreter/mterp/x86/binopLit16.S
+++ b/runtime/interpreter/mterp/x86/binopLit16.S
@@ -11,9 +11,9 @@
     /* binop/lit16 vA, vB, #+CCCC */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $$4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $$0xf, rINSTbl                  # rINST <- A
     $instr                                  # for example: addl %ecx, %eax
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/binopLit8.S b/runtime/interpreter/mterp/x86/binopLit8.S
index 924685d..67cead2 100644
--- a/runtime/interpreter/mterp/x86/binopLit8.S
+++ b/runtime/interpreter/mterp/x86/binopLit8.S
@@ -12,7 +12,7 @@
     /* binop/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG %eax %eax                      # eax <- rBB
+    GET_VREG %eax, %eax                     # eax <- rBB
     $instr                                  # ex: addl %ecx,%eax
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/binopWide.S b/runtime/interpreter/mterp/x86/binopWide.S
index 9f7106e..da1293d 100644
--- a/runtime/interpreter/mterp/x86/binopWide.S
+++ b/runtime/interpreter/mterp/x86/binopWide.S
@@ -2,14 +2,14 @@
  * Generic 64-bit binary operation.
  */
     /* binop vAA, vBB, vCC */
-    movzbl  2(rPC),%eax                     # eax <- BB
-    movzbl  3(rPC),%ecx                     # ecx <- CC
-    movl    rIBASE,LOCAL0(%esp)             # save rIBASE
-    GET_VREG rIBASE %eax                    # rIBASE <- v[BB+0]
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1]
+    movzbl  2(rPC), %eax                    # eax <- BB
+    movzbl  3(rPC), %ecx                    # ecx <- CC
+    movl    rIBASE, LOCAL0(%esp)            # save rIBASE
+    GET_VREG rIBASE, %eax                   # rIBASE <- v[BB+0]
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1]
     $instr1                                 # ex: addl   (rFP,%ecx,4),rIBASE
     $instr2                                 # ex: adcl   4(rFP,%ecx,4),%eax
-    SET_VREG rIBASE rINST                   # v[AA+0] <- rIBASE
-    movl    LOCAL0(%esp),rIBASE             # restore rIBASE
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG rIBASE, rINST                  # v[AA+0] <- rIBASE
+    movl    LOCAL0(%esp), rIBASE            # restore rIBASE
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/binopWide2addr.S b/runtime/interpreter/mterp/x86/binopWide2addr.S
index 7560af4..da816f4 100644
--- a/runtime/interpreter/mterp/x86/binopWide2addr.S
+++ b/runtime/interpreter/mterp/x86/binopWide2addr.S
@@ -2,11 +2,11 @@
  * Generic 64-bit binary operation.
  */
     /* binop/2addr vA, vB */
-    movzbl  rINSTbl,%ecx                    # ecx<- BA
-    sarl    $$4,%ecx                        # ecx<- B
-    GET_VREG %eax %ecx                      # eax<- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # eax<- v[B+1]
-    andb    $$0xF,rINSTbl                   # rINST<- A
+    movzbl  rINSTbl, %ecx                   # ecx<- BA
+    sarl    $$4, %ecx                       # ecx<- B
+    GET_VREG %eax, %ecx                     # eax<- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # eax<- v[B+1]
+    andb    $$0xF, rINSTbl                  # rINST<- A
     $instr1                                 # ex: addl   %eax,(rFP,rINST,4)
     $instr2                                 # ex: adcl   %ecx,4(rFP,rINST,4)
     CLEAR_WIDE_REF rINST
diff --git a/runtime/interpreter/mterp/x86/entry.S b/runtime/interpreter/mterp/x86/entry.S
index a24ef70..b83f7e1 100644
--- a/runtime/interpreter/mterp/x86/entry.S
+++ b/runtime/interpreter/mterp/x86/entry.S
@@ -18,8 +18,8 @@
  */
 
     .text
-    .global ExecuteMterpImpl
-    .type   ExecuteMterpImpl, %function
+    .global SYMBOL(ExecuteMterpImpl)
+    FUNCTION_TYPE(ExecuteMterpImpl)
 
 /*
  * On entry:
@@ -30,7 +30,7 @@
  *
  */
 
-ExecuteMterpImpl:
+SYMBOL(ExecuteMterpImpl):
     .cfi_startproc
     /* Allocate frame */
     subl    $$FRAME_SIZE, %esp
diff --git a/runtime/interpreter/mterp/x86/footer.S b/runtime/interpreter/mterp/x86/footer.S
index a2a36c4..385e784 100644
--- a/runtime/interpreter/mterp/x86/footer.S
+++ b/runtime/interpreter/mterp/x86/footer.S
@@ -20,7 +20,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogDivideByZeroException
+    call    SYMBOL(MterpLogDivideByZeroException)
 #endif
     jmp     MterpCommonFallback
 
@@ -31,7 +31,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogArrayIndexException
+    call    SYMBOL(MterpLogArrayIndexException)
 #endif
     jmp     MterpCommonFallback
 
@@ -42,7 +42,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogNegativeArraySizeException
+    call    SYMBOL(MterpLogNegativeArraySizeException)
 #endif
     jmp     MterpCommonFallback
 
@@ -53,7 +53,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogNoSuchMethodException
+    call    SYMBOL(MterpLogNoSuchMethodException)
 #endif
     jmp     MterpCommonFallback
 
@@ -64,7 +64,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogNullObjectException
+    call    SYMBOL(MterpLogNullObjectException)
 #endif
     jmp     MterpCommonFallback
 
@@ -75,7 +75,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG0(%esp)
-    call    MterpLogExceptionThrownException
+    call    SYMBOL(MterpLogExceptionThrownException)
 #endif
     jmp     MterpCommonFallback
 
@@ -88,7 +88,7 @@
     movl    %ecx, OUT_ARG0(%esp)
     movl    THREAD_FLAGS_OFFSET(%eax), %eax
     movl    %eax, OUT_ARG2(%esp)
-    call    MterpLogSuspendFallback
+    call    SYMBOL(MterpLogSuspendFallback)
 #endif
     jmp     MterpCommonFallback
 
@@ -113,7 +113,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpHandleException
+    call    SYMBOL(MterpHandleException)
     testl   %eax, %eax
     jz      MterpExceptionReturn
     REFRESH_IBASE
@@ -137,7 +137,7 @@
     testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
     REFRESH_IBASE
 1:
     GOTO_NEXT
@@ -152,7 +152,7 @@
     movl    %eax, OUT_ARG0(%esp)
     lea     OFF_FP_SHADOWFRAME(rFP), %ecx
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpLogFallback
+    call    SYMBOL(MterpLogFallback)
 #endif
 MterpCommonFallback:
     xor     %eax, %eax
@@ -183,4 +183,4 @@
     ret
 
     .cfi_endproc
-    .size   ExecuteMterpImpl, .-ExecuteMterpImpl
+    SIZE(ExecuteMterpImpl,ExecuteMterpImpl)
diff --git a/runtime/interpreter/mterp/x86/fpcmp.S b/runtime/interpreter/mterp/x86/fpcmp.S
index 2b98667..5f9eef9 100644
--- a/runtime/interpreter/mterp/x86/fpcmp.S
+++ b/runtime/interpreter/mterp/x86/fpcmp.S
@@ -31,5 +31,5 @@
 .L${opcode}_less:
     decl    %eax
 .L${opcode}_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/header.S b/runtime/interpreter/mterp/x86/header.S
index 2481785..0977b90 100644
--- a/runtime/interpreter/mterp/x86/header.S
+++ b/runtime/interpreter/mterp/x86/header.S
@@ -89,6 +89,22 @@
  */
 #include "asm_support.h"
 
+/*
+ * Handle mac compiler specific
+ */
+#if defined(__APPLE__)
+    #define MACRO_LITERAL(value) $$(value)
+    #define FUNCTION_TYPE(name)
+    #define SIZE(start,end)
+    // Mac OS' symbols have an _ prefix.
+    #define SYMBOL(name) _ ## name
+#else
+    #define MACRO_LITERAL(value) $$value
+    #define FUNCTION_TYPE(name) .type name, @function
+    #define SIZE(start,end) .size start, .-end
+    #define SYMBOL(name) name
+#endif
+
 /* Frame size must be 16-byte aligned.
  * Remember about 4 bytes for return address
  */
@@ -192,7 +208,7 @@
  */
 .macro REFRESH_INST _opnum
     movb    rINSTbl, rINSTbh
-    movb    $$\_opnum, rINSTbl
+    movb    MACRO_LITERAL(\_opnum), rINSTbl
 .endm
 
 /*
@@ -208,7 +224,7 @@
 .macro GOTO_NEXT
     movzx   rINSTbl,%eax
     movzbl  rINSTbh,rINST
-    shll    $$${handler_size_bits}, %eax
+    shll    MACRO_LITERAL(${handler_size_bits}), %eax
     addl    rIBASE, %eax
     jmp     *%eax
 .endm
@@ -248,7 +264,7 @@
 
 .macro SET_VREG _reg _vreg
     movl    \_reg, (rFP,\_vreg,4)
-    movl    $$0, (rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0), (rREFS,\_vreg,4)
 .endm
 
 /* Write wide value from xmm. xmm is clobbered. */
@@ -269,14 +285,14 @@
 
 .macro SET_VREG_HIGH _reg _vreg
     movl    \_reg, 4(rFP,\_vreg,4)
-    movl    $$0, 4(rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0), 4(rREFS,\_vreg,4)
 .endm
 
 .macro CLEAR_REF _vreg
-    movl    $$0,  (rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0),  (rREFS,\_vreg,4)
 .endm
 
 .macro CLEAR_WIDE_REF _vreg
-    movl    $$0,  (rREFS,\_vreg,4)
-    movl    $$0, 4(rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0),  (rREFS,\_vreg,4)
+    movl    MACRO_LITERAL(0), 4(rREFS,\_vreg,4)
 .endm
diff --git a/runtime/interpreter/mterp/x86/invoke.S b/runtime/interpreter/mterp/x86/invoke.S
index 80f7822..054fbfd 100644
--- a/runtime/interpreter/mterp/x86/invoke.S
+++ b/runtime/interpreter/mterp/x86/invoke.S
@@ -13,7 +13,7 @@
     movl    rPC, OUT_ARG2(%esp)
     REFRESH_INST ${opnum}
     movl    rINST, OUT_ARG3(%esp)
-    call    $helper
+    call    SYMBOL($helper)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_aget.S b/runtime/interpreter/mterp/x86/op_aget.S
index 52b5236..338386f 100644
--- a/runtime/interpreter/mterp/x86/op_aget.S
+++ b/runtime/interpreter/mterp/x86/op_aget.S
@@ -8,12 +8,12 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     $load   $data_offset(%eax,%ecx,$shift), %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_aget_object.S b/runtime/interpreter/mterp/x86/op_aget_object.S
index 61f3e91..cbfb50c 100644
--- a/runtime/interpreter/mterp/x86/op_aget_object.S
+++ b/runtime/interpreter/mterp/x86/op_aget_object.S
@@ -6,15 +6,15 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecs <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecs <- vCC (requested index)
     EXPORT_PC
     movl    %eax, OUT_ARG0(%esp)
     movl    %ecx, OUT_ARG1(%esp)
-    call    artAGetObjectFromMterp          # (array, index)
+    call    SYMBOL(artAGetObjectFromMterp)  # (array, index)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
-    SET_VREG_OBJECT %eax rINST
+    SET_VREG_OBJECT %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_aget_wide.S b/runtime/interpreter/mterp/x86/op_aget_wide.S
index 663adc6..92c612a 100644
--- a/runtime/interpreter/mterp/x86/op_aget_wide.S
+++ b/runtime/interpreter/mterp/x86/op_aget_wide.S
@@ -4,13 +4,13 @@
     /* aget-wide vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_WIDE_ARRAY_DATA_OFFSET(%eax,%ecx,8), %eax
     movq    (%eax), %xmm0                   # xmm0 <- vBB[vCC]
-    SET_WIDE_FP_VREG %xmm0 rINST            # vAA <- xmm0
+    SET_WIDE_FP_VREG %xmm0, rINST           # vAA <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_aput.S b/runtime/interpreter/mterp/x86/op_aput.S
index 2ea465d..9d8c52d 100644
--- a/runtime/interpreter/mterp/x86/op_aput.S
+++ b/runtime/interpreter/mterp/x86/op_aput.S
@@ -8,13 +8,13 @@
     /* op vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    $data_offset(%eax,%ecx,$shift), %eax
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     $store  $reg, (%eax)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_aput_object.S b/runtime/interpreter/mterp/x86/op_aput_object.S
index 2af5acb..9cfc221 100644
--- a/runtime/interpreter/mterp/x86/op_aput_object.S
+++ b/runtime/interpreter/mterp/x86/op_aput_object.S
@@ -8,7 +8,7 @@
     movl    rPC, OUT_ARG1(%esp)
     REFRESH_INST ${opnum}
     movl    rINST, OUT_ARG2(%esp)
-    call    MterpAputObject            # (array, index)
+    call    SYMBOL(MterpAputObject)         # (array, index)
     REFRESH_IBASE
     testl   %eax, %eax
     jz      MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_aput_wide.S b/runtime/interpreter/mterp/x86/op_aput_wide.S
index 7a33371..43ef64a 100644
--- a/runtime/interpreter/mterp/x86/op_aput_wide.S
+++ b/runtime/interpreter/mterp/x86/op_aput_wide.S
@@ -5,13 +5,13 @@
     /* aput-wide vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB (array object)
-    GET_VREG %ecx %ecx                      # ecx <- vCC (requested index)
+    GET_VREG %eax, %eax                     # eax <- vBB (array object)
+    GET_VREG %ecx, %ecx                     # ecx <- vCC (requested index)
     testl   %eax, %eax                      # null array object?
     je      common_errNullObject            # bail if so
     cmpl    MIRROR_ARRAY_LENGTH_OFFSET(%eax), %ecx
     jae     common_errArrayIndex            # index >= length, bail.
     leal    MIRROR_WIDE_ARRAY_DATA_OFFSET(%eax,%ecx,8), %eax
-    GET_WIDE_FP_VREG %xmm0 rINST            # xmm0 <- vAA
+    GET_WIDE_FP_VREG %xmm0, rINST           # xmm0 <- vAA
     movq    %xmm0, (%eax)                   # vBB[vCC] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_array_length.S b/runtime/interpreter/mterp/x86/op_array_length.S
index 3e42a7c..60ed80b 100644
--- a/runtime/interpreter/mterp/x86/op_array_length.S
+++ b/runtime/interpreter/mterp/x86/op_array_length.S
@@ -3,10 +3,10 @@
  */
     mov     rINST, %eax                     # eax <- BA
     sarl    $$4, rINST                      # rINST <- B
-    GET_VREG %ecx rINST                     # ecx <- vB (object ref)
+    GET_VREG %ecx, rINST                    # ecx <- vB (object ref)
     testl   %ecx, %ecx                      # is null?
     je      common_errNullObject
     andb    $$0xf, %al                      # eax <- A
     movl    MIRROR_ARRAY_LENGTH_OFFSET(%ecx), rINST
-    SET_VREG rINST %eax
+    SET_VREG rINST, %eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_check_cast.S b/runtime/interpreter/mterp/x86/op_check_cast.S
index 018432a..ae2ff9e 100644
--- a/runtime/interpreter/mterp/x86/op_check_cast.S
+++ b/runtime/interpreter/mterp/x86/op_check_cast.S
@@ -11,7 +11,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpCheckCast                  # (index, &obj, method, self)
+    call    SYMBOL(MterpCheckCast)          # (index, &obj, method, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_cmp_long.S b/runtime/interpreter/mterp/x86/op_cmp_long.S
index bd86738..1f729b0 100644
--- a/runtime/interpreter/mterp/x86/op_cmp_long.S
+++ b/runtime/interpreter/mterp/x86/op_cmp_long.S
@@ -5,17 +5,17 @@
     /* cmp-long vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG_HIGH %eax %eax                 # eax <- v[BB+1], BB is clobbered
+    GET_VREG_HIGH %eax, %eax                # eax <- v[BB+1], BB is clobbered
     cmpl    VREG_HIGH_ADDRESS(%ecx), %eax
     jl      .L${opcode}_smaller
     jg      .L${opcode}_bigger
     movzbl  2(rPC), %eax                    # eax <- BB, restore BB
-    GET_VREG %eax %eax                      # eax <- v[BB]
+    GET_VREG %eax, %eax                     # eax <- v[BB]
     sub     VREG_ADDRESS(%ecx), %eax
     ja      .L${opcode}_bigger
     jb      .L${opcode}_smaller
 .L${opcode}_finish:
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
 
 .L${opcode}_bigger:
diff --git a/runtime/interpreter/mterp/x86/op_const.S b/runtime/interpreter/mterp/x86/op_const.S
index dc69530..544d63b 100644
--- a/runtime/interpreter/mterp/x86/op_const.S
+++ b/runtime/interpreter/mterp/x86/op_const.S
@@ -1,4 +1,4 @@
     /* const vAA, #+BBBBbbbb */
     movl    2(rPC), %eax                    # grab all 32 bits at once
-    SET_VREG %eax rINST                     # vAA<- eax
+    SET_VREG %eax, rINST                    # vAA<- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
diff --git a/runtime/interpreter/mterp/x86/op_const_16.S b/runtime/interpreter/mterp/x86/op_const_16.S
index f5707cf..97cd5fa 100644
--- a/runtime/interpreter/mterp/x86/op_const_16.S
+++ b/runtime/interpreter/mterp/x86/op_const_16.S
@@ -1,4 +1,4 @@
     /* const/16 vAA, #+BBBB */
     movswl  2(rPC), %ecx                    # ecx <- ssssBBBB
-    SET_VREG %ecx rINST                     # vAA <- ssssBBBB
+    SET_VREG %ecx, rINST                    # vAA <- ssssBBBB
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_const_4.S b/runtime/interpreter/mterp/x86/op_const_4.S
index c336411..a60ba96 100644
--- a/runtime/interpreter/mterp/x86/op_const_4.S
+++ b/runtime/interpreter/mterp/x86/op_const_4.S
@@ -3,5 +3,5 @@
     movl    $$0xf, rINST
     andl    %eax, rINST                     # rINST <- A
     sarl    $$4, %eax
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_const_class.S b/runtime/interpreter/mterp/x86/op_const_class.S
index eceb8bc..343e110 100644
--- a/runtime/interpreter/mterp/x86/op_const_class.S
+++ b/runtime/interpreter/mterp/x86/op_const_class.S
@@ -7,7 +7,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpConstClass                 # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstClass)         # (index, tgt_reg, shadow_frame, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_const_high16.S b/runtime/interpreter/mterp/x86/op_const_high16.S
index da78d1b..576967a 100644
--- a/runtime/interpreter/mterp/x86/op_const_high16.S
+++ b/runtime/interpreter/mterp/x86/op_const_high16.S
@@ -1,5 +1,5 @@
     /* const/high16 vAA, #+BBBB0000 */
     movzwl  2(rPC), %eax                    # eax <- 0000BBBB
     sall    $$16, %eax                      # eax <- BBBB0000
-    SET_VREG %eax rINST                     # vAA <- eax
+    SET_VREG %eax, rINST                    # vAA <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_const_string.S b/runtime/interpreter/mterp/x86/op_const_string.S
index 9acd6fe..bbac69c 100644
--- a/runtime/interpreter/mterp/x86/op_const_string.S
+++ b/runtime/interpreter/mterp/x86/op_const_string.S
@@ -7,7 +7,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpConstString                # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_const_string_jumbo.S b/runtime/interpreter/mterp/x86/op_const_string_jumbo.S
index 5c728b2..4236807 100644
--- a/runtime/interpreter/mterp/x86/op_const_string_jumbo.S
+++ b/runtime/interpreter/mterp/x86/op_const_string_jumbo.S
@@ -7,7 +7,7 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpConstString                # (index, tgt_reg, shadow_frame, self)
+    call    SYMBOL(MterpConstString)        # (index, tgt_reg, shadow_frame, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_const_wide.S b/runtime/interpreter/mterp/x86/op_const_wide.S
index 745490e..3750728 100644
--- a/runtime/interpreter/mterp/x86/op_const_wide.S
+++ b/runtime/interpreter/mterp/x86/op_const_wide.S
@@ -2,6 +2,6 @@
     movl    2(rPC), %eax                    # eax <- lsw
     movzbl  rINSTbl, %ecx                   # ecx <- AA
     movl    6(rPC), rINST                   # rINST <- msw
-    SET_VREG %eax %ecx
-    SET_VREG_HIGH  rINST %ecx
+    SET_VREG %eax, %ecx
+    SET_VREG_HIGH  rINST, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 5
diff --git a/runtime/interpreter/mterp/x86/op_const_wide_16.S b/runtime/interpreter/mterp/x86/op_const_wide_16.S
index 8029cfe..1331c32 100644
--- a/runtime/interpreter/mterp/x86/op_const_wide_16.S
+++ b/runtime/interpreter/mterp/x86/op_const_wide_16.S
@@ -2,7 +2,7 @@
     movswl  2(rPC), %eax                    # eax <- ssssBBBB
     movl    rIBASE, %ecx                    # preserve rIBASE (cltd trashes it)
     cltd                                    # rIBASE:eax <- ssssssssssssBBBB
-    SET_VREG_HIGH rIBASE rINST              # store msw
-    SET_VREG %eax rINST                     # store lsw
+    SET_VREG_HIGH rIBASE, rINST             # store msw
+    SET_VREG %eax, rINST                    # store lsw
     movl    %ecx, rIBASE                    # restore rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_const_wide_32.S b/runtime/interpreter/mterp/x86/op_const_wide_32.S
index 3e23d3a..ed7d62b 100644
--- a/runtime/interpreter/mterp/x86/op_const_wide_32.S
+++ b/runtime/interpreter/mterp/x86/op_const_wide_32.S
@@ -2,7 +2,7 @@
     movl    2(rPC), %eax                    # eax <- BBBBbbbb
     movl    rIBASE, %ecx                    # preserve rIBASE (cltd trashes it)
     cltd                                    # rIBASE:eax <- ssssssssssssBBBB
-    SET_VREG_HIGH rIBASE rINST              # store msw
-    SET_VREG %eax rINST                     # store lsw
+    SET_VREG_HIGH rIBASE, rINST             # store msw
+    SET_VREG %eax, rINST                    # store lsw
     movl    %ecx, rIBASE                    # restore rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
diff --git a/runtime/interpreter/mterp/x86/op_const_wide_high16.S b/runtime/interpreter/mterp/x86/op_const_wide_high16.S
index d2a1119..11b9310 100644
--- a/runtime/interpreter/mterp/x86/op_const_wide_high16.S
+++ b/runtime/interpreter/mterp/x86/op_const_wide_high16.S
@@ -1,7 +1,7 @@
     /* const-wide/high16 vAA, #+BBBB000000000000 */
     movzwl  2(rPC), %eax                    # eax <- 0000BBBB
     sall    $$16, %eax                      # eax <- BBBB0000
-    SET_VREG_HIGH %eax rINST                # v[AA+1] <- eax
+    SET_VREG_HIGH %eax, rINST               # v[AA+1] <- eax
     xorl    %eax, %eax
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_div_long.S b/runtime/interpreter/mterp/x86/op_div_long.S
index 5772826..e56a035 100644
--- a/runtime/interpreter/mterp/x86/op_div_long.S
+++ b/runtime/interpreter/mterp/x86/op_div_long.S
@@ -7,17 +7,17 @@
     mov     rIBASE, LOCAL0(%esp)            # save rIBASE/%edx
     mov     rINST, LOCAL1(%esp)             # save rINST/%ebx
     movzbl  3(rPC), %eax                    # eax <- CC
-    GET_VREG %ecx %eax
-    GET_VREG_HIGH %ebx %eax
+    GET_VREG %ecx, %eax
+    GET_VREG_HIGH %ebx, %eax
     movl    %ecx, %edx
     orl     %ebx, %ecx
     jz      common_errDivideByZero
     movzbl  2(rPC), %eax                    # eax <- BB
-    GET_VREG_HIGH %ecx %eax
-    GET_VREG %eax %eax
-    call    $routine
+    GET_VREG_HIGH %ecx, %eax
+    GET_VREG %eax, %eax
+    call    SYMBOL($routine)
     mov     LOCAL1(%esp), rINST             # restore rINST/%ebx
-    SET_VREG_HIGH rIBASE rINST
-    SET_VREG %eax rINST
+    SET_VREG_HIGH rIBASE, rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE            # restore rIBASE/%edx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_div_long_2addr.S b/runtime/interpreter/mterp/x86/op_div_long_2addr.S
index 2696042..159cc44 100644
--- a/runtime/interpreter/mterp/x86/op_div_long_2addr.S
+++ b/runtime/interpreter/mterp/x86/op_div_long_2addr.S
@@ -10,16 +10,16 @@
     andb    $$0xf, rINSTbl                  # rINST <- A
     mov     rINST, LOCAL1(%esp)             # save rINST/%ebx
     movl    %ebx, %ecx
-    GET_VREG %edx %eax
-    GET_VREG_HIGH %ebx %eax
+    GET_VREG %edx, %eax
+    GET_VREG_HIGH %ebx, %eax
     movl    %edx, %eax
     orl     %ebx, %eax
     jz      common_errDivideByZero
-    GET_VREG %eax %ecx
-    GET_VREG_HIGH %ecx %ecx
-    call    $routine
+    GET_VREG %eax, %ecx
+    GET_VREG_HIGH %ecx, %ecx
+    call    SYMBOL($routine)
     mov     LOCAL1(%esp), rINST             # restore rINST/%ebx
-    SET_VREG_HIGH rIBASE rINST
-    SET_VREG %eax rINST
+    SET_VREG_HIGH rIBASE, rINST
+    SET_VREG %eax, rINST
     mov     LOCAL0(%esp), rIBASE            # restore rIBASE/%edx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_fill_array_data.S b/runtime/interpreter/mterp/x86/op_fill_array_data.S
index 0cb05f6..004aed9 100644
--- a/runtime/interpreter/mterp/x86/op_fill_array_data.S
+++ b/runtime/interpreter/mterp/x86/op_fill_array_data.S
@@ -2,10 +2,10 @@
     EXPORT_PC
     movl    2(rPC), %ecx                    # ecx <- BBBBbbbb
     leal    (rPC,%ecx,2), %ecx              # ecx <- PC + BBBBbbbb*2
-    GET_VREG %eax rINST                     # eax <- vAA (array object)
+    GET_VREG %eax, rINST                    # eax <- vAA (array object)
     movl    %eax, OUT_ARG0(%esp)
     movl    %ecx, OUT_ARG1(%esp)
-    call    MterpFillArrayData              # (obj, payload)
+    call    SYMBOL(MterpFillArrayData)      # (obj, payload)
     REFRESH_IBASE
     testl   %eax, %eax                      # 0 means an exception is thrown
     jz      MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_filled_new_array.S b/runtime/interpreter/mterp/x86/op_filled_new_array.S
index c08b09f..a2bac29 100644
--- a/runtime/interpreter/mterp/x86/op_filled_new_array.S
+++ b/runtime/interpreter/mterp/x86/op_filled_new_array.S
@@ -13,7 +13,7 @@
     movl    rPC, OUT_ARG1(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)
-    call    $helper
+    call    SYMBOL($helper)
     REFRESH_IBASE
     testl   %eax, %eax                      # 0 means an exception is thrown
     jz      MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_iget.S b/runtime/interpreter/mterp/x86/op_iget.S
index 868ffd0..9932610 100644
--- a/runtime/interpreter/mterp/x86/op_iget.S
+++ b/runtime/interpreter/mterp/x86/op_iget.S
@@ -15,15 +15,15 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    $helper
+    call    SYMBOL($helper)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $$0xf, rINSTbl                  # rINST <- A
     .if $is_object
-    SET_VREG_OBJECT %eax rINST              # fp[A] <-value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <-value
     .else
-    SET_VREG %eax rINST                     # fp[A] <-value
+    SET_VREG %eax, rINST                    # fp[A] <-value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_iget_object_quick.S b/runtime/interpreter/mterp/x86/op_iget_object_quick.S
index b09772f..fe16694 100644
--- a/runtime/interpreter/mterp/x86/op_iget_object_quick.S
+++ b/runtime/interpreter/mterp/x86/op_iget_object_quick.S
@@ -2,16 +2,16 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     movl    %ecx, OUT_ARG0(%esp)
     movl    %eax, OUT_ARG1(%esp)
     EXPORT_PC
-    call    artIGetObjectFromMterp          # (obj, offset)
+    call    SYMBOL(artIGetObjectFromMterp)  # (obj, offset)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $$0xf,rINSTbl                   # rINST <- A
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_iget_quick.S b/runtime/interpreter/mterp/x86/op_iget_quick.S
index 372071c..1b7440f 100644
--- a/runtime/interpreter/mterp/x86/op_iget_quick.S
+++ b/runtime/interpreter/mterp/x86/op_iget_quick.S
@@ -3,11 +3,11 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     ${load} (%ecx,%eax,1), %eax
     andb    $$0xf,rINSTbl                   # rINST <- A
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_iget_wide.S b/runtime/interpreter/mterp/x86/op_iget_wide.S
index 58e5a65..92126b4 100644
--- a/runtime/interpreter/mterp/x86/op_iget_wide.S
+++ b/runtime/interpreter/mterp/x86/op_iget_wide.S
@@ -14,12 +14,12 @@
     movl    %eax, OUT_ARG2(%esp)            # referrer
     mov     rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artGet64InstanceFromCode
+    call    SYMBOL(artGet64InstanceFromCode)
     mov     rSELF, %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException                  # bail out
     andb    $$0xf, rINSTbl                  # rINST <- A
-    SET_VREG %eax rINST
-    SET_VREG_HIGH %edx rINST
+    SET_VREG %eax, rINST
+    SET_VREG_HIGH %edx, rINST
     REFRESH_IBASE_FROM_SELF %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_iget_wide_quick.S b/runtime/interpreter/mterp/x86/op_iget_wide_quick.S
index 8be336b..7ce74cc 100644
--- a/runtime/interpreter/mterp/x86/op_iget_wide_quick.S
+++ b/runtime/interpreter/mterp/x86/op_iget_wide_quick.S
@@ -1,11 +1,11 @@
     /* iget-wide-quick vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     movq    (%ecx,%eax,1), %xmm0
     andb    $$0xf, rINSTbl                  # rINST <- A
-    SET_WIDE_FP_VREG %xmm0 rINST
+    SET_WIDE_FP_VREG %xmm0, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_instance_of.S b/runtime/interpreter/mterp/x86/op_instance_of.S
index c9bfba5..fd5bf44 100644
--- a/runtime/interpreter/mterp/x86/op_instance_of.S
+++ b/runtime/interpreter/mterp/x86/op_instance_of.S
@@ -16,11 +16,11 @@
     movl    %eax, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpInstanceOf                 # (index, &obj, method, self)
+    call    SYMBOL(MterpInstanceOf)         # (index, &obj, method, self)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     andb    $$0xf, rINSTbl                  # rINSTbl <- A
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_int_to_long.S b/runtime/interpreter/mterp/x86/op_int_to_long.S
index 736ea69..6f9ea26 100644
--- a/runtime/interpreter/mterp/x86/op_int_to_long.S
+++ b/runtime/interpreter/mterp/x86/op_int_to_long.S
@@ -1,12 +1,12 @@
     /* int to long vA, vB */
     movzbl  rINSTbl, %eax                   # eax <- +A
     sarl    $$4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     andb    $$0xf, rINSTbl                  # rINST <- A
     movl    rIBASE, %ecx                    # cltd trashes rIBASE/edx
     cltd                                    # rINST:eax<- sssssssBBBBBBBB
-    SET_VREG_HIGH rIBASE rINST              # v[A+1] <- rIBASE
-    SET_VREG %eax rINST                     # v[A+0] <- %eax
+    SET_VREG_HIGH rIBASE, rINST             # v[A+1] <- rIBASE
+    SET_VREG %eax, rINST                    # v[A+0] <- %eax
     movl    %ecx, rIBASE
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
diff --git a/runtime/interpreter/mterp/x86/op_iput.S b/runtime/interpreter/mterp/x86/op_iput.S
index f8a6549..13cfe5c 100644
--- a/runtime/interpreter/mterp/x86/op_iput.S
+++ b/runtime/interpreter/mterp/x86/op_iput.S
@@ -18,7 +18,7 @@
     movl    %eax, OUT_ARG2(%esp)            # fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    $handler
+    call    SYMBOL($handler)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_iput_object.S b/runtime/interpreter/mterp/x86/op_iput_object.S
index 20d57aa..f63075c 100644
--- a/runtime/interpreter/mterp/x86/op_iput_object.S
+++ b/runtime/interpreter/mterp/x86/op_iput_object.S
@@ -6,7 +6,7 @@
     movl    rINST, OUT_ARG2(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG3(%esp)
-    call    MterpIputObject
+    call    SYMBOL(MterpIputObject)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_iput_object_quick.S b/runtime/interpreter/mterp/x86/op_iput_object_quick.S
index 4c7f4bd..d54b1b7 100644
--- a/runtime/interpreter/mterp/x86/op_iput_object_quick.S
+++ b/runtime/interpreter/mterp/x86/op_iput_object_quick.S
@@ -4,7 +4,7 @@
     movl    rPC, OUT_ARG1(%esp)
     REFRESH_INST ${opnum}
     movl    rINST, OUT_ARG2(%esp)
-    call    MterpIputObjectQuick
+    call    SYMBOL(MterpIputObjectQuick)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_iput_quick.S b/runtime/interpreter/mterp/x86/op_iput_quick.S
index e2f7caf..b67cee0 100644
--- a/runtime/interpreter/mterp/x86/op_iput_quick.S
+++ b/runtime/interpreter/mterp/x86/op_iput_quick.S
@@ -3,11 +3,11 @@
     /* op vA, vB, offset@CCCC */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # vB (object we're operating on)
+    GET_VREG %ecx, %ecx                     # vB (object we're operating on)
     testl   %ecx, %ecx                      # is object null?
     je      common_errNullObject
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG rINST rINST                    # rINST <- v[A]
+    GET_VREG rINST, rINST                   # rINST <- v[A]
     movzwl  2(rPC), %eax                    # eax <- field byte offset
     ${store}    ${reg}, (%ecx,%eax,1)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_iput_wide.S b/runtime/interpreter/mterp/x86/op_iput_wide.S
index 92cb770..573e14d 100644
--- a/runtime/interpreter/mterp/x86/op_iput_wide.S
+++ b/runtime/interpreter/mterp/x86/op_iput_wide.S
@@ -12,7 +12,7 @@
     movl    %eax, OUT_ARG2(%esp)            # &fp[A]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG3(%esp)            # referrer
-    call    artSet64InstanceFromMterp
+    call    SYMBOL(artSet64InstanceFromMterp)
     testl   %eax, %eax
     jnz     MterpPossibleException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_iput_wide_quick.S b/runtime/interpreter/mterp/x86/op_iput_wide_quick.S
index 72285c5..17de6f8 100644
--- a/runtime/interpreter/mterp/x86/op_iput_wide_quick.S
+++ b/runtime/interpreter/mterp/x86/op_iput_wide_quick.S
@@ -1,12 +1,12 @@
     /* iput-wide-quick vA, vB, offset@CCCC */
     movzbl    rINSTbl, %ecx                 # ecx<- BA
     sarl      $$4, %ecx                     # ecx<- B
-    GET_VREG  %ecx %ecx                     # vB (object we're operating on)
+    GET_VREG  %ecx, %ecx                    # vB (object we're operating on)
     testl     %ecx, %ecx                    # is object null?
     je        common_errNullObject
     movzwl    2(rPC), %eax                  # eax<- field byte offset
     leal      (%ecx,%eax,1), %ecx           # ecx<- Address of 64-bit target
     andb      $$0xf, rINSTbl                # rINST<- A
-    GET_WIDE_FP_VREG %xmm0 rINST            # xmm0<- fp[A]/fp[A+1]
+    GET_WIDE_FP_VREG %xmm0, rINST           # xmm0<- fp[A]/fp[A+1]
     movq      %xmm0, (%ecx)                 # obj.field<- r0/r1
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_monitor_enter.S b/runtime/interpreter/mterp/x86/op_monitor_enter.S
index 8236fb3..9e885bd 100644
--- a/runtime/interpreter/mterp/x86/op_monitor_enter.S
+++ b/runtime/interpreter/mterp/x86/op_monitor_enter.S
@@ -3,11 +3,11 @@
  */
     /* monitor-enter vAA */
     EXPORT_PC
-    GET_VREG %ecx rINST
+    GET_VREG %ecx, rINST
     movl    %ecx, OUT_ARG0(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    artLockObjectFromCode           # (object, self)
+    call    SYMBOL(artLockObjectFromCode)   # (object, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpException
diff --git a/runtime/interpreter/mterp/x86/op_monitor_exit.S b/runtime/interpreter/mterp/x86/op_monitor_exit.S
index 56d4eb3..0904800 100644
--- a/runtime/interpreter/mterp/x86/op_monitor_exit.S
+++ b/runtime/interpreter/mterp/x86/op_monitor_exit.S
@@ -7,11 +7,11 @@
  */
     /* monitor-exit vAA */
     EXPORT_PC
-    GET_VREG %ecx rINST
+    GET_VREG %ecx, rINST
     movl    %ecx, OUT_ARG0(%esp)
     movl    rSELF, %eax
     movl    %eax, OUT_ARG1(%esp)
-    call    artUnlockObjectFromCode         # (object, self)
+    call    SYMBOL(artUnlockObjectFromCode) # (object, self)
     REFRESH_IBASE
     testl   %eax, %eax
     jnz     MterpException
diff --git a/runtime/interpreter/mterp/x86/op_move.S b/runtime/interpreter/mterp/x86/op_move.S
index 0a531be..ea173b9 100644
--- a/runtime/interpreter/mterp/x86/op_move.S
+++ b/runtime/interpreter/mterp/x86/op_move.S
@@ -4,10 +4,10 @@
     movzbl  rINSTbl, %eax                   # eax <- BA
     andb    $$0xf, %al                      # eax <- A
     shrl    $$4, rINST                      # rINST <- B
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     .if $is_object
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_move_16.S b/runtime/interpreter/mterp/x86/op_move_16.S
index 0773f41..454deb5 100644
--- a/runtime/interpreter/mterp/x86/op_move_16.S
+++ b/runtime/interpreter/mterp/x86/op_move_16.S
@@ -3,10 +3,10 @@
     /* op vAAAA, vBBBB */
     movzwl  4(rPC), %ecx                    # ecx <- BBBB
     movzwl  2(rPC), %eax                    # eax <- AAAA
-    GET_VREG rINST %ecx
+    GET_VREG rINST, %ecx
     .if $is_object
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
diff --git a/runtime/interpreter/mterp/x86/op_move_exception.S b/runtime/interpreter/mterp/x86/op_move_exception.S
index e37cdfa..d8dc74f 100644
--- a/runtime/interpreter/mterp/x86/op_move_exception.S
+++ b/runtime/interpreter/mterp/x86/op_move_exception.S
@@ -1,6 +1,6 @@
     /* move-exception vAA */
     movl    rSELF, %ecx
     movl    THREAD_EXCEPTION_OFFSET(%ecx), %eax
-    SET_VREG_OBJECT %eax rINST              # fp[AA] <- exception object
+    SET_VREG_OBJECT %eax, rINST             # fp[AA] <- exception object
     movl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_move_from16.S b/runtime/interpreter/mterp/x86/op_move_from16.S
index 623a4d3..e869855 100644
--- a/runtime/interpreter/mterp/x86/op_move_from16.S
+++ b/runtime/interpreter/mterp/x86/op_move_from16.S
@@ -3,10 +3,10 @@
     /* op vAA, vBBBB */
     movzx   rINSTbl, %eax                   # eax <- AA
     movw    2(rPC), rINSTw                  # rINSTw <- BBBB
-    GET_VREG rINST rINST                    # rINST <- fp[BBBB]
+    GET_VREG rINST, rINST                   # rINST <- fp[BBBB]
     .if $is_object
-    SET_VREG_OBJECT rINST %eax              # fp[A] <- fp[B]
+    SET_VREG_OBJECT rINST, %eax             # fp[A] <- fp[B]
     .else
-    SET_VREG rINST %eax                     # fp[A] <- fp[B]
+    SET_VREG rINST, %eax                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_move_result.S b/runtime/interpreter/mterp/x86/op_move_result.S
index 414f2cb..f6f2129 100644
--- a/runtime/interpreter/mterp/x86/op_move_result.S
+++ b/runtime/interpreter/mterp/x86/op_move_result.S
@@ -4,8 +4,8 @@
     movl    OFF_FP_RESULT_REGISTER(rFP), %eax    # get pointer to result JType.
     movl    (%eax), %eax                    # r0 <- result.i.
     .if $is_object
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- fp[B]
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- fp[B]
     .else
-    SET_VREG %eax rINST                     # fp[A] <- fp[B]
+    SET_VREG %eax, rINST                    # fp[A] <- fp[B]
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_move_result_wide.S b/runtime/interpreter/mterp/x86/op_move_result_wide.S
index 0c1683b..7818cce 100644
--- a/runtime/interpreter/mterp/x86/op_move_result_wide.S
+++ b/runtime/interpreter/mterp/x86/op_move_result_wide.S
@@ -2,6 +2,6 @@
     movl    OFF_FP_RESULT_REGISTER(rFP), %eax    # get pointer to result JType.
     movl    4(%eax), %ecx                   # Get high
     movl    (%eax), %eax                    # Get low
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
-    SET_VREG_HIGH %ecx rINST                # v[AA+1] <- ecx
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
+    SET_VREG_HIGH %ecx, rINST               # v[AA+1] <- ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_move_wide.S b/runtime/interpreter/mterp/x86/op_move_wide.S
index 9c0e985..79ce7b7 100644
--- a/runtime/interpreter/mterp/x86/op_move_wide.S
+++ b/runtime/interpreter/mterp/x86/op_move_wide.S
@@ -3,6 +3,6 @@
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $$4, rINST                      # rINST <- B
     andb    $$0xf, %cl                      # ecx <- A
-    GET_WIDE_FP_VREG %xmm0 rINST            # xmm0 <- v[B]
-    SET_WIDE_FP_VREG %xmm0 %ecx             # v[A] <- xmm0
+    GET_WIDE_FP_VREG %xmm0, rINST           # xmm0 <- v[B]
+    SET_WIDE_FP_VREG %xmm0, %ecx            # v[A] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_move_wide_16.S b/runtime/interpreter/mterp/x86/op_move_wide_16.S
index 7522c27..a6b8596 100644
--- a/runtime/interpreter/mterp/x86/op_move_wide_16.S
+++ b/runtime/interpreter/mterp/x86/op_move_wide_16.S
@@ -2,6 +2,6 @@
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     movzwl  4(rPC), %ecx                    # ecx<- BBBB
     movzwl  2(rPC), %eax                    # eax<- AAAA
-    GET_WIDE_FP_VREG %xmm0 %ecx             # xmm0 <- v[B]
-    SET_WIDE_FP_VREG %xmm0 %eax             # v[A] <- xmm0
+    GET_WIDE_FP_VREG %xmm0, %ecx            # xmm0 <- v[B]
+    SET_WIDE_FP_VREG %xmm0, %eax            # v[A] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 3
diff --git a/runtime/interpreter/mterp/x86/op_move_wide_from16.S b/runtime/interpreter/mterp/x86/op_move_wide_from16.S
index 5ad2cb4..ec344de 100644
--- a/runtime/interpreter/mterp/x86/op_move_wide_from16.S
+++ b/runtime/interpreter/mterp/x86/op_move_wide_from16.S
@@ -2,6 +2,6 @@
     /* NOTE: regs can overlap, e.g. "move v6,v7" or "move v7,v6" */
     movzwl  2(rPC), %ecx                    # ecx <- BBBB
     movzbl  rINSTbl, %eax                   # eax <- AAAA
-    GET_WIDE_FP_VREG %xmm0 %ecx             # xmm0 <- v[B]
-    SET_WIDE_FP_VREG %xmm0 %eax             # v[A] <- xmm0
+    GET_WIDE_FP_VREG %xmm0, %ecx            # xmm0 <- v[B]
+    SET_WIDE_FP_VREG %xmm0, %eax            # v[A] <- xmm0
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_mul_int.S b/runtime/interpreter/mterp/x86/op_mul_int.S
index a367ab7..77f4659 100644
--- a/runtime/interpreter/mterp/x86/op_mul_int.S
+++ b/runtime/interpreter/mterp/x86/op_mul_int.S
@@ -4,9 +4,9 @@
     /* mul vAA, vBB, vCC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
-    GET_VREG %eax %eax                      # eax <- vBB
+    GET_VREG %eax, %eax                     # eax <- vBB
     mov     rIBASE, LOCAL0(%esp)
     imull   (rFP,%ecx,4), %eax              # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_mul_int_2addr.S b/runtime/interpreter/mterp/x86/op_mul_int_2addr.S
index 6005075..f92a28e 100644
--- a/runtime/interpreter/mterp/x86/op_mul_int_2addr.S
+++ b/runtime/interpreter/mterp/x86/op_mul_int_2addr.S
@@ -1,10 +1,10 @@
     /* mul vA, vB */
     movzx   rINSTbl, %ecx                   # ecx <- A+
     sarl    $$4, rINST                      # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $$0xf, %cl                      # ecx <- A
     mov     rIBASE, LOCAL0(%esp)
     imull   (rFP,%ecx,4), %eax              # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_mul_int_lit16.S b/runtime/interpreter/mterp/x86/op_mul_int_lit16.S
index 1c0fde3..31ab613 100644
--- a/runtime/interpreter/mterp/x86/op_mul_int_lit16.S
+++ b/runtime/interpreter/mterp/x86/op_mul_int_lit16.S
@@ -2,11 +2,11 @@
     /* Need A in rINST, ssssCCCC in ecx, vB in eax */
     movzbl  rINSTbl, %eax                   # eax <- 000000BA
     sarl    $$4, %eax                       # eax <- B
-    GET_VREG %eax %eax                      # eax <- vB
+    GET_VREG %eax, %eax                     # eax <- vB
     movswl  2(rPC), %ecx                    # ecx <- ssssCCCC
     andb    $$0xf, rINSTbl                  # rINST <- A
     mov     rIBASE, LOCAL0(%esp)
     imull   %ecx, %eax                      # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_mul_int_lit8.S b/runtime/interpreter/mterp/x86/op_mul_int_lit8.S
index 4d7a22d..6637aa7 100644
--- a/runtime/interpreter/mterp/x86/op_mul_int_lit8.S
+++ b/runtime/interpreter/mterp/x86/op_mul_int_lit8.S
@@ -1,9 +1,9 @@
     /* mul/lit8 vAA, vBB, #+CC */
     movzbl  2(rPC), %eax                    # eax <- BB
     movsbl  3(rPC), %ecx                    # ecx <- ssssssCC
-    GET_VREG  %eax  %eax                    # eax <- rBB
+    GET_VREG  %eax, %eax                    # eax <- rBB
     mov     rIBASE, LOCAL0(%esp)
     imull   %ecx, %eax                      # trashes rIBASE/edx
     mov     LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST
+    SET_VREG %eax, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_mul_long.S b/runtime/interpreter/mterp/x86/op_mul_long.S
index 3746e41..f35ca13 100644
--- a/runtime/interpreter/mterp/x86/op_mul_long.S
+++ b/runtime/interpreter/mterp/x86/op_mul_long.S
@@ -27,7 +27,7 @@
     mov     LOCAL0(%esp), rPC               # restore Interpreter PC
     mov     LOCAL1(%esp), rFP               # restore FP
     leal    (%ecx,rIBASE), rIBASE           # full result now in rIBASE:%eax
-    SET_VREG_HIGH rIBASE rINST              # v[B+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[B+1] <- rIBASE
     mov     LOCAL2(%esp), rIBASE            # restore IBASE
-    SET_VREG %eax rINST                     # v[B] <- eax
+    SET_VREG %eax, rINST                    # v[B] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_neg_long.S b/runtime/interpreter/mterp/x86/op_neg_long.S
index 7cc17f0..30da247 100644
--- a/runtime/interpreter/mterp/x86/op_neg_long.S
+++ b/runtime/interpreter/mterp/x86/op_neg_long.S
@@ -2,12 +2,12 @@
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $$4, %ecx                       # ecx <- B
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax %ecx                      # eax <- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # ecx <- v[B+1]
+    GET_VREG %eax, %ecx                     # eax <- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # ecx <- v[B+1]
     negl    %eax
     adcl    $$0, %ecx
     negl    %ecx
-    SET_VREG %eax rINST                     # v[A+0] <- eax
-    SET_VREG_HIGH %ecx rINST                # v[A+1] <- ecx
+    SET_VREG %eax, rINST                    # v[A+0] <- eax
+    SET_VREG_HIGH %ecx, rINST               # v[A+1] <- ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
 
diff --git a/runtime/interpreter/mterp/x86/op_new_array.S b/runtime/interpreter/mterp/x86/op_new_array.S
index 6852183..2490477 100644
--- a/runtime/interpreter/mterp/x86/op_new_array.S
+++ b/runtime/interpreter/mterp/x86/op_new_array.S
@@ -14,7 +14,7 @@
     movl    rINST, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpNewArray
+    call    SYMBOL(MterpNewArray)
     REFRESH_IBASE
     testl   %eax, %eax                      # 0 means an exception is thrown
     jz      MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_new_instance.S b/runtime/interpreter/mterp/x86/op_new_instance.S
index a3632e8..712a5eb 100644
--- a/runtime/interpreter/mterp/x86/op_new_instance.S
+++ b/runtime/interpreter/mterp/x86/op_new_instance.S
@@ -9,7 +9,7 @@
     movl    %ecx, OUT_ARG1(%esp)
     REFRESH_INST ${opnum}
     movl    rINST, OUT_ARG2(%esp)
-    call    MterpNewInstance
+    call    SYMBOL(MterpNewInstance)
     REFRESH_IBASE
     testl   %eax, %eax                 # 0 means an exception is thrown
     jz      MterpPossibleException
diff --git a/runtime/interpreter/mterp/x86/op_not_long.S b/runtime/interpreter/mterp/x86/op_not_long.S
index 55666a1..8f706e1 100644
--- a/runtime/interpreter/mterp/x86/op_not_long.S
+++ b/runtime/interpreter/mterp/x86/op_not_long.S
@@ -2,10 +2,10 @@
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     sarl    $$4, %ecx                       # ecx <- B
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax %ecx                      # eax <- v[B+0]
-    GET_VREG_HIGH %ecx %ecx                 # ecx <- v[B+1]
+    GET_VREG %eax, %ecx                     # eax <- v[B+0]
+    GET_VREG_HIGH %ecx, %ecx                # ecx <- v[B+1]
     notl    %eax
     notl    %ecx
-    SET_VREG %eax rINST                     # v[A+0] <- eax
-    SET_VREG_HIGH %ecx rINST                # v[A+1] <- ecx
+    SET_VREG %eax, rINST                    # v[A+0] <- eax
+    SET_VREG_HIGH %ecx, rINST               # v[A+1] <- ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_packed_switch.S b/runtime/interpreter/mterp/x86/op_packed_switch.S
index 4e39a48..230b58e 100644
--- a/runtime/interpreter/mterp/x86/op_packed_switch.S
+++ b/runtime/interpreter/mterp/x86/op_packed_switch.S
@@ -10,11 +10,11 @@
  */
     /* op vAA, +BBBB */
     movl    2(rPC), %ecx                    # ecx <- BBBBbbbb
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     leal    (rPC,%ecx,2), %ecx              # ecx <- PC + BBBBbbbb*2
     movl    %eax, OUT_ARG1(%esp)            # ARG1 <- vAA
     movl    %ecx, OUT_ARG0(%esp)            # ARG0 <- switchData
-    call    $func
+    call    SYMBOL($func)
     addl    %eax, %eax
     leal    (rPC, %eax), rPC
     FETCH_INST
diff --git a/runtime/interpreter/mterp/x86/op_return.S b/runtime/interpreter/mterp/x86/op_return.S
index 183b3bf..8e3cfad 100644
--- a/runtime/interpreter/mterp/x86/op_return.S
+++ b/runtime/interpreter/mterp/x86/op_return.S
@@ -5,13 +5,13 @@
  */
     /* op vAA */
     .extern MterpThreadFenceForConstructor
-    call    MterpThreadFenceForConstructor
+    call    SYMBOL(MterpThreadFenceForConstructor)
     movl    rSELF, %eax
     testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     xorl    %ecx, %ecx
     jmp     MterpReturn
diff --git a/runtime/interpreter/mterp/x86/op_return_void.S b/runtime/interpreter/mterp/x86/op_return_void.S
index f3e24c7..a14a4f6 100644
--- a/runtime/interpreter/mterp/x86/op_return_void.S
+++ b/runtime/interpreter/mterp/x86/op_return_void.S
@@ -1,10 +1,10 @@
     .extern MterpThreadFenceForConstructor
-    call    MterpThreadFenceForConstructor
+    call    SYMBOL(MterpThreadFenceForConstructor)
     movl    rSELF, %eax
     testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
diff --git a/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S b/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S
index add4e20..1d0e933 100644
--- a/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S
+++ b/runtime/interpreter/mterp/x86/op_return_void_no_barrier.S
@@ -2,7 +2,7 @@
     testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
     xorl    %eax, %eax
     xorl    %ecx, %ecx
diff --git a/runtime/interpreter/mterp/x86/op_return_wide.S b/runtime/interpreter/mterp/x86/op_return_wide.S
index 34a3380..7d1850a 100644
--- a/runtime/interpreter/mterp/x86/op_return_wide.S
+++ b/runtime/interpreter/mterp/x86/op_return_wide.S
@@ -3,13 +3,13 @@
  */
     /* return-wide vAA */
     .extern MterpThreadFenceForConstructor
-    call    MterpThreadFenceForConstructor
+    call    SYMBOL(MterpThreadFenceForConstructor)
     movl    rSELF, %eax
     testl   $$(THREAD_SUSPEND_REQUEST | THREAD_CHECKPOINT_REQUEST), THREAD_FLAGS_OFFSET(%eax)
     jz      1f
     movl    %eax, OUT_ARG0(%esp)
-    call    MterpSuspendCheck
+    call    SYMBOL(MterpSuspendCheck)
 1:
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
-    GET_VREG_HIGH %ecx rINST                # ecx <- v[AA+1]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
+    GET_VREG_HIGH %ecx, rINST               # ecx <- v[AA+1]
     jmp     MterpReturn
diff --git a/runtime/interpreter/mterp/x86/op_sget.S b/runtime/interpreter/mterp/x86/op_sget.S
index ed5aedf..ec96458 100644
--- a/runtime/interpreter/mterp/x86/op_sget.S
+++ b/runtime/interpreter/mterp/x86/op_sget.S
@@ -13,14 +13,14 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    $helper
+    call    SYMBOL($helper)
     movl    rSELF, %ecx
     REFRESH_IBASE_FROM_SELF %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
     .if $is_object
-    SET_VREG_OBJECT %eax rINST              # fp[A] <- value
+    SET_VREG_OBJECT %eax, rINST             # fp[A] <- value
     .else
-    SET_VREG %eax rINST                     # fp[A] <- value
+    SET_VREG %eax, rINST                    # fp[A] <- value
     .endif
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_sget_wide.S b/runtime/interpreter/mterp/x86/op_sget_wide.S
index 76b993b..833f266 100644
--- a/runtime/interpreter/mterp/x86/op_sget_wide.S
+++ b/runtime/interpreter/mterp/x86/op_sget_wide.S
@@ -11,11 +11,11 @@
     movl    %eax, OUT_ARG1(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG2(%esp)            # self
-    call    artGet64StaticFromCode
+    call    SYMBOL(artGet64StaticFromCode)
     movl    rSELF, %ecx
     cmpl    $$0, THREAD_EXCEPTION_OFFSET(%ecx)
     jnz     MterpException
-    SET_VREG %eax rINST                     # fp[A]<- low part
-    SET_VREG_HIGH %edx rINST                # fp[A+1]<- high part
+    SET_VREG %eax, rINST                    # fp[A]<- low part
+    SET_VREG_HIGH %edx, rINST               # fp[A+1]<- high part
     REFRESH_IBASE_FROM_SELF %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_shl_long.S b/runtime/interpreter/mterp/x86/op_shl_long.S
index 56d13e3..aa58a93 100644
--- a/runtime/interpreter/mterp/x86/op_shl_long.S
+++ b/runtime/interpreter/mterp/x86/op_shl_long.S
@@ -13,9 +13,9 @@
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE %eax               # ecx <- v[BB+1]
-    GET_VREG %ecx %ecx                      # ecx <- vCC
-    GET_VREG %eax %eax                      # eax <- v[BB+0]
+    GET_VREG_HIGH rIBASE, %eax              # ecx <- v[BB+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- v[BB+0]
     shldl   %eax,rIBASE
     sall    %cl, %eax
     testb   $$32, %cl
@@ -23,7 +23,7 @@
     movl    %eax, rIBASE
     xorl    %eax, %eax
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- %eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- %eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_shl_long_2addr.S b/runtime/interpreter/mterp/x86/op_shl_long_2addr.S
index 5da873f..6bbf49c 100644
--- a/runtime/interpreter/mterp/x86/op_shl_long_2addr.S
+++ b/runtime/interpreter/mterp/x86/op_shl_long_2addr.S
@@ -8,11 +8,11 @@
     /* rINSTw gets AA */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
     sarl    $$4, %ecx                       # ecx <- B
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE rINST              # rIBASE <- v[AA+1]
-    GET_VREG %ecx %ecx                      # ecx <- vBB
+    GET_VREG_HIGH rIBASE, rINST             # rIBASE <- v[AA+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vBB
     shldl   %eax, rIBASE
     sall    %cl, %eax
     testb   $$32, %cl
@@ -20,7 +20,7 @@
     movl    %eax, rIBASE
     xorl    %eax, %eax
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_shr_long.S b/runtime/interpreter/mterp/x86/op_shr_long.S
index 4490a9a..68aa0ee 100644
--- a/runtime/interpreter/mterp/x86/op_shr_long.S
+++ b/runtime/interpreter/mterp/x86/op_shr_long.S
@@ -13,9 +13,9 @@
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE %eax               # rIBASE<- v[BB+1]
-    GET_VREG %ecx %ecx                      # ecx <- vCC
-    GET_VREG %eax %eax                      # eax <- v[BB+0]
+    GET_VREG_HIGH rIBASE, %eax              # rIBASE<- v[BB+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- v[BB+0]
     shrdl   rIBASE, %eax
     sarl    %cl, rIBASE
     testb   $$32, %cl
@@ -23,7 +23,7 @@
     movl    rIBASE, %eax
     sarl    $$31, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_shr_long_2addr.S b/runtime/interpreter/mterp/x86/op_shr_long_2addr.S
index 57494f9..148bd1b 100644
--- a/runtime/interpreter/mterp/x86/op_shr_long_2addr.S
+++ b/runtime/interpreter/mterp/x86/op_shr_long_2addr.S
@@ -8,11 +8,11 @@
     /* rINSTw gets AA */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
     sarl    $$4, %ecx                       # ecx <- B
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE rINST              # rIBASE <- v[AA+1]
-    GET_VREG %ecx %ecx                      # ecx <- vBB
+    GET_VREG_HIGH rIBASE, rINST             # rIBASE <- v[AA+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vBB
     shrdl   rIBASE, %eax
     sarl    %cl, rIBASE
     testb   $$32, %cl
@@ -20,7 +20,7 @@
     movl    rIBASE, %eax
     sarl    $$31, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/op_sput.S b/runtime/interpreter/mterp/x86/op_sput.S
index 04a8f23..a199281 100644
--- a/runtime/interpreter/mterp/x86/op_sput.S
+++ b/runtime/interpreter/mterp/x86/op_sput.S
@@ -9,13 +9,13 @@
     EXPORT_PC
     movzwl  2(rPC), %eax
     movl    %eax, OUT_ARG0(%esp)            # field ref BBBB
-    GET_VREG rINST rINST
+    GET_VREG rINST, rINST
     movl    rINST, OUT_ARG1(%esp)           # fp[AA]
     movl    OFF_FP_METHOD(rFP), %eax
     movl    %eax, OUT_ARG2(%esp)            # referrer
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    $helper
+    call    SYMBOL($helper)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_sput_object.S b/runtime/interpreter/mterp/x86/op_sput_object.S
index 0480e00..e3e57fc 100644
--- a/runtime/interpreter/mterp/x86/op_sput_object.S
+++ b/runtime/interpreter/mterp/x86/op_sput_object.S
@@ -6,7 +6,7 @@
     movl    rINST, OUT_ARG2(%esp)
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)
-    call    MterpSputObject
+    call    SYMBOL(MterpSputObject)
     testl   %eax, %eax
     jz      MterpException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_sput_wide.S b/runtime/interpreter/mterp/x86/op_sput_wide.S
index d58d5af..7544838 100644
--- a/runtime/interpreter/mterp/x86/op_sput_wide.S
+++ b/runtime/interpreter/mterp/x86/op_sput_wide.S
@@ -13,7 +13,7 @@
     movl    %eax, OUT_ARG2(%esp)            # &fp[AA]
     movl    rSELF, %ecx
     movl    %ecx, OUT_ARG3(%esp)            # self
-    call    artSet64IndirectStaticFromMterp
+    call    SYMBOL(artSet64IndirectStaticFromMterp)
     testl   %eax, %eax
     jnz     MterpException
     REFRESH_IBASE
diff --git a/runtime/interpreter/mterp/x86/op_throw.S b/runtime/interpreter/mterp/x86/op_throw.S
index 15b20b5..a6e6b1e 100644
--- a/runtime/interpreter/mterp/x86/op_throw.S
+++ b/runtime/interpreter/mterp/x86/op_throw.S
@@ -3,7 +3,7 @@
  */
     /* throw vAA */
     EXPORT_PC
-    GET_VREG %eax rINST                     # eax<- vAA (exception object)
+    GET_VREG %eax, rINST                    # eax<- vAA (exception object)
     testl   %eax, %eax
     jz      common_errNullObject
     movl    rSELF,%ecx
diff --git a/runtime/interpreter/mterp/x86/op_ushr_long.S b/runtime/interpreter/mterp/x86/op_ushr_long.S
index 287946e..9527c9c 100644
--- a/runtime/interpreter/mterp/x86/op_ushr_long.S
+++ b/runtime/interpreter/mterp/x86/op_ushr_long.S
@@ -13,9 +13,9 @@
     movzbl  2(rPC), %eax                    # eax <- BB
     movzbl  3(rPC), %ecx                    # ecx <- CC
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE %eax               # rIBASE <- v[BB+1]
-    GET_VREG %ecx %ecx                      # ecx <- vCC
-    GET_VREG %eax %eax                      # eax <- v[BB+0]
+    GET_VREG_HIGH rIBASE, %eax              # rIBASE <- v[BB+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vCC
+    GET_VREG %eax, %eax                     # eax <- v[BB+0]
     shrdl   rIBASE, %eax
     shrl    %cl, rIBASE
     testb   $$32, %cl
@@ -23,7 +23,7 @@
     movl    rIBASE, %eax
     xorl    rIBASE, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[BB+0] <- eax
+    SET_VREG %eax, rINST                    # v[BB+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 2
diff --git a/runtime/interpreter/mterp/x86/op_ushr_long_2addr.S b/runtime/interpreter/mterp/x86/op_ushr_long_2addr.S
index 39c2724..72fcc36 100644
--- a/runtime/interpreter/mterp/x86/op_ushr_long_2addr.S
+++ b/runtime/interpreter/mterp/x86/op_ushr_long_2addr.S
@@ -8,11 +8,11 @@
     /* rINSTw gets AA */
     movzbl  rINSTbl, %ecx                   # ecx <- BA
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- v[AA+0]
+    GET_VREG %eax, rINST                    # eax <- v[AA+0]
     sarl    $$4, %ecx                       # ecx <- B
     movl    rIBASE, LOCAL0(%esp)
-    GET_VREG_HIGH rIBASE rINST              # rIBASE <- v[AA+1]
-    GET_VREG %ecx %ecx                      # ecx <- vBB
+    GET_VREG_HIGH rIBASE, rINST             # rIBASE <- v[AA+1]
+    GET_VREG %ecx, %ecx                     # ecx <- vBB
     shrdl   rIBASE, %eax
     shrl    %cl, rIBASE
     testb   $$32, %cl
@@ -20,7 +20,7 @@
     movl    rIBASE, %eax
     xorl    rIBASE, rIBASE
 2:
-    SET_VREG_HIGH rIBASE rINST              # v[AA+1] <- rIBASE
+    SET_VREG_HIGH rIBASE, rINST             # v[AA+1] <- rIBASE
     movl    LOCAL0(%esp), rIBASE
-    SET_VREG %eax rINST                     # v[AA+0] <- eax
+    SET_VREG %eax, rINST                    # v[AA+0] <- eax
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/shop2addr.S b/runtime/interpreter/mterp/x86/shop2addr.S
index 94d3545..96c9954 100644
--- a/runtime/interpreter/mterp/x86/shop2addr.S
+++ b/runtime/interpreter/mterp/x86/shop2addr.S
@@ -5,9 +5,9 @@
     /* shift/2addr vA, vB */
     movzx   rINSTbl, %ecx                   # eax <- BA
     sarl    $$4, %ecx                       # ecx <- B
-    GET_VREG %ecx %ecx                      # eax <- vBB
+    GET_VREG %ecx, %ecx                     # eax <- vBB
     andb    $$0xf, rINSTbl                  # rINST <- A
-    GET_VREG %eax rINST                     # eax <- vAA
+    GET_VREG %eax, rINST                    # eax <- vAA
     $instr                                  # ex: sarl %cl, %eax
-    SET_VREG $result rINST
+    SET_VREG $result, rINST
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/interpreter/mterp/x86/unop.S b/runtime/interpreter/mterp/x86/unop.S
index 00d3e15..db09fc0 100644
--- a/runtime/interpreter/mterp/x86/unop.S
+++ b/runtime/interpreter/mterp/x86/unop.S
@@ -6,8 +6,8 @@
     /* unop vA, vB */
     movzbl  rINSTbl,%ecx                    # ecx <- A+
     sarl    $$4,rINST                       # rINST <- B
-    GET_VREG %eax rINST                     # eax <- vB
+    GET_VREG %eax, rINST                    # eax <- vB
     andb    $$0xf,%cl                       # ecx <- A
     $instr
-    SET_VREG %eax %ecx
+    SET_VREG %eax, %ecx
     ADVANCE_PC_FETCH_AND_GOTO_NEXT 1
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index fa5c41d..188deb0 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -25,15 +25,19 @@
 #include "jit_code_cache.h"
 #include "jit_instrumentation.h"
 #include "oat_file_manager.h"
+#include "oat_quick_method_header.h"
 #include "offline_profiling_info.h"
 #include "profile_saver.h"
 #include "runtime.h"
 #include "runtime_options.h"
+#include "stack_map.h"
 #include "utils.h"
 
 namespace art {
 namespace jit {
 
+static constexpr bool kEnableOnStackReplacement = true;
+
 JitOptions* JitOptions::CreateFromRuntimeArguments(const RuntimeArgumentMap& options) {
   auto* jit_options = new JitOptions;
   jit_options->use_jit_ = options.GetOrDefault(RuntimeArgumentMap::UseJIT);
@@ -43,6 +47,8 @@
       options.GetOrDefault(RuntimeArgumentMap::JITCodeCacheMaxCapacity);
   jit_options->compile_threshold_ =
       options.GetOrDefault(RuntimeArgumentMap::JITCompileThreshold);
+  // TODO(ngeoffray): Make this a proper option.
+  jit_options->osr_threshold_ = jit_options->compile_threshold_ * 2;
   jit_options->warmup_threshold_ =
       options.GetOrDefault(RuntimeArgumentMap::JITWarmupThreshold);
   jit_options->dump_info_on_shutdown_ =
@@ -121,7 +127,7 @@
     *error_msg = "JIT couldn't find jit_unload entry point";
     return false;
   }
-  jit_compile_method_ = reinterpret_cast<bool (*)(void*, ArtMethod*, Thread*)>(
+  jit_compile_method_ = reinterpret_cast<bool (*)(void*, ArtMethod*, Thread*, bool)>(
       dlsym(jit_library_handle_, "jit_compile_method"));
   if (jit_compile_method_ == nullptr) {
     dlclose(jit_library_handle_);
@@ -156,8 +162,9 @@
   return true;
 }
 
-bool Jit::CompileMethod(ArtMethod* method, Thread* self) {
+bool Jit::CompileMethod(ArtMethod* method, Thread* self, bool osr) {
   DCHECK(!method->IsRuntimeMethod());
+
   // Don't compile the method if it has breakpoints.
   if (Dbg::IsDebuggerActive() && Dbg::MethodHasAnyBreakpoints(method)) {
     VLOG(jit) << "JIT not compiling " << PrettyMethod(method) << " due to breakpoint";
@@ -171,11 +178,15 @@
     return false;
   }
 
-  if (!code_cache_->NotifyCompilationOf(method, self)) {
+  // If we get a request to compile a proxy method, we pass the actual Java method
+  // of that proxy method, as the compiler does not expect a proxy method.
+  ArtMethod* method_to_compile = method->GetInterfaceMethodIfProxy(sizeof(void*));
+  if (!code_cache_->NotifyCompilationOf(method_to_compile, self, osr)) {
+    VLOG(jit) << "JIT not compiling " << PrettyMethod(method) << " due to code cache";
     return false;
   }
-  bool success = jit_compile_method_(jit_compiler_handle_, method, self);
-  code_cache_->DoneCompiling(method, self);
+  bool success = jit_compile_method_(jit_compiler_handle_, method_to_compile, self, osr);
+  code_cache_->DoneCompiling(method_to_compile, self);
   return success;
 }
 
@@ -224,9 +235,11 @@
   }
 }
 
-void Jit::CreateInstrumentationCache(size_t compile_threshold, size_t warmup_threshold) {
+void Jit::CreateInstrumentationCache(size_t compile_threshold,
+                                     size_t warmup_threshold,
+                                     size_t osr_threshold) {
   instrumentation_cache_.reset(
-      new jit::JitInstrumentationCache(compile_threshold, warmup_threshold));
+      new jit::JitInstrumentationCache(compile_threshold, warmup_threshold, osr_threshold));
 }
 
 void Jit::NewTypeLoadedIfUsingJit(mirror::Class* type) {
@@ -255,5 +268,149 @@
   }
 }
 
+extern "C" void art_quick_osr_stub(void** stack,
+                                   uint32_t stack_size_in_bytes,
+                                   const uint8_t* native_pc,
+                                   JValue* result,
+                                   const char* shorty,
+                                   Thread* self);
+
+bool Jit::MaybeDoOnStackReplacement(Thread* thread,
+                                    ArtMethod* method,
+                                    uint32_t dex_pc,
+                                    int32_t dex_pc_offset,
+                                    JValue* result) {
+  if (!kEnableOnStackReplacement) {
+    return false;
+  }
+
+  Jit* jit = Runtime::Current()->GetJit();
+  if (jit == nullptr) {
+    return false;
+  }
+
+  if (kRuntimeISA == kMips || kRuntimeISA == kMips64) {
+    VLOG(jit) << "OSR not supported on this platform: " << kRuntimeISA;
+    return false;
+  }
+
+  // Get the actual Java method if this method is from a proxy class. The compiler
+  // and the JIT code cache do not expect methods from proxy classes.
+  method = method->GetInterfaceMethodIfProxy(sizeof(void*));
+
+  // Cheap check if the method has been compiled already. That's an indicator that we should
+  // osr into it.
+  if (!jit->GetCodeCache()->ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
+    return false;
+  }
+
+  // Fetch some data before looking up for an OSR method. We don't want thread
+  // suspension once we hold an OSR method, as the JIT code cache could delete the OSR
+  // method while we are being suspended.
+  const size_t number_of_vregs = method->GetCodeItem()->registers_size_;
+  const char* shorty = method->GetShorty();
+  std::string method_name(VLOG_IS_ON(jit) ? PrettyMethod(method) : "");
+  void** memory = nullptr;
+  size_t frame_size = 0;
+  ShadowFrame* shadow_frame = nullptr;
+  const uint8_t* native_pc = nullptr;
+
+  {
+    ScopedAssertNoThreadSuspension sts(thread, "Holding OSR method");
+    const OatQuickMethodHeader* osr_method = jit->GetCodeCache()->LookupOsrMethodHeader(method);
+    if (osr_method == nullptr) {
+      // No osr method yet, just return to the interpreter.
+      return false;
+    }
+
+    CodeInfo code_info = osr_method->GetOptimizedCodeInfo();
+    StackMapEncoding encoding = code_info.ExtractEncoding();
+
+    // Find stack map starting at the target dex_pc.
+    StackMap stack_map = code_info.GetOsrStackMapForDexPc(dex_pc + dex_pc_offset, encoding);
+    if (!stack_map.IsValid()) {
+      // There is no OSR stack map for this dex pc offset. Just return to the interpreter in the
+      // hope that the next branch has one.
+      return false;
+    }
+
+    // We found a stack map, now fill the frame with dex register values from the interpreter's
+    // shadow frame.
+    DexRegisterMap vreg_map =
+        code_info.GetDexRegisterMapOf(stack_map, encoding, number_of_vregs);
+
+    frame_size = osr_method->GetFrameSizeInBytes();
+
+    // Allocate memory to put shadow frame values. The osr stub will copy that memory to
+    // stack.
+    // Note that we could pass the shadow frame to the stub, and let it copy the values there,
+    // but that is engineering complexity not worth the effort for something like OSR.
+    memory = reinterpret_cast<void**>(malloc(frame_size));
+    CHECK(memory != nullptr);
+    memset(memory, 0, frame_size);
+
+    // Art ABI: ArtMethod is at the bottom of the stack.
+    memory[0] = method;
+
+    shadow_frame = thread->PopShadowFrame();
+    if (!vreg_map.IsValid()) {
+      // If we don't have a dex register map, then there are no live dex registers at
+      // this dex pc.
+    } else {
+      for (uint16_t vreg = 0; vreg < number_of_vregs; ++vreg) {
+        DexRegisterLocation::Kind location =
+            vreg_map.GetLocationKind(vreg, number_of_vregs, code_info, encoding);
+        if (location == DexRegisterLocation::Kind::kNone) {
+          // Dex register is dead or uninitialized.
+          continue;
+        }
+
+        if (location == DexRegisterLocation::Kind::kConstant) {
+          // We skip constants because the compiled code knows how to handle them.
+          continue;
+        }
+
+        DCHECK(location == DexRegisterLocation::Kind::kInStack)
+            << DexRegisterLocation::PrettyDescriptor(location);
+
+        int32_t vreg_value = shadow_frame->GetVReg(vreg);
+        int32_t slot_offset = vreg_map.GetStackOffsetInBytes(vreg,
+                                                             number_of_vregs,
+                                                             code_info,
+                                                             encoding);
+        DCHECK_LT(slot_offset, static_cast<int32_t>(frame_size));
+        DCHECK_GT(slot_offset, 0);
+        (reinterpret_cast<int32_t*>(memory))[slot_offset / sizeof(int32_t)] = vreg_value;
+      }
+    }
+
+    native_pc = stack_map.GetNativePcOffset(encoding) + osr_method->GetEntryPoint();
+    VLOG(jit) << "Jumping to "
+              << method_name
+              << "@"
+              << std::hex << reinterpret_cast<uintptr_t>(native_pc);
+  }
+
+  {
+    ManagedStack fragment;
+    thread->PushManagedStackFragment(&fragment);
+    (*art_quick_osr_stub)(memory,
+                          frame_size,
+                          native_pc,
+                          result,
+                          shorty,
+                          thread);
+
+    if (UNLIKELY(thread->GetException() == Thread::GetDeoptimizationException())) {
+      thread->DeoptimizeWithDeoptimizationException(result);
+    }
+    thread->PopManagedStackFragment(fragment);
+  }
+  free(memory);
+  thread->PushShadowFrame(shadow_frame);
+  VLOG(jit) << "Done running OSR code for " << method_name;
+  return true;
+}
+
 }  // namespace jit
 }  // namespace art
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index a80f51f..042da92 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -49,9 +49,11 @@
 
   virtual ~Jit();
   static Jit* Create(JitOptions* options, std::string* error_msg);
-  bool CompileMethod(ArtMethod* method, Thread* self)
+  bool CompileMethod(ArtMethod* method, Thread* self, bool osr)
       SHARED_REQUIRES(Locks::mutator_lock_);
-  void CreateInstrumentationCache(size_t compile_threshold, size_t warmup_threshold);
+  void CreateInstrumentationCache(size_t compile_threshold,
+                                  size_t warmup_threshold,
+                                  size_t osr_threshold);
   void CreateThreadPool();
   CompilerCallbacks* GetCompilerCallbacks() {
     return compiler_callbacks_;
@@ -88,6 +90,17 @@
 
   bool JitAtFirstUse();
 
+  // If an OSR compiled version is available for `method`,
+  // and `dex_pc + dex_pc_offset` is an entry point of that compiled
+  // version, this method will jump to the compiled code, let it run,
+  // and return true afterwards. Return false otherwise.
+  static bool MaybeDoOnStackReplacement(Thread* thread,
+                                        ArtMethod* method,
+                                        uint32_t dex_pc,
+                                        int32_t dex_pc_offset,
+                                        JValue* result)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
  private:
   Jit();
   bool LoadCompiler(std::string* error_msg);
@@ -97,7 +110,7 @@
   void* jit_compiler_handle_;
   void* (*jit_load_)(CompilerCallbacks**, bool*);
   void (*jit_unload_)(void*);
-  bool (*jit_compile_method_)(void*, ArtMethod*, Thread*);
+  bool (*jit_compile_method_)(void*, ArtMethod*, Thread*, bool);
   void (*jit_types_loaded_)(void*, mirror::Class**, size_t count);
 
   // Performance monitoring.
@@ -123,6 +136,9 @@
   size_t GetWarmupThreshold() const {
     return warmup_threshold_;
   }
+  size_t GetOsrThreshold() const {
+    return osr_threshold_;
+  }
   size_t GetCodeCacheInitialCapacity() const {
     return code_cache_initial_capacity_;
   }
@@ -155,6 +171,7 @@
   size_t code_cache_max_capacity_;
   size_t compile_threshold_;
   size_t warmup_threshold_;
+  size_t osr_threshold_;
   bool dump_info_on_shutdown_;
   bool save_profiling_info_;
 
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index f325949..9111ddf 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -184,7 +184,8 @@
                                   size_t core_spill_mask,
                                   size_t fp_spill_mask,
                                   const uint8_t* code,
-                                  size_t code_size) {
+                                  size_t code_size,
+                                  bool osr) {
   uint8_t* result = CommitCodeInternal(self,
                                        method,
                                        mapping_table,
@@ -194,7 +195,8 @@
                                        core_spill_mask,
                                        fp_spill_mask,
                                        code,
-                                       code_size);
+                                       code_size,
+                                       osr);
   if (result == nullptr) {
     // Retry.
     GarbageCollectCache(self);
@@ -207,7 +209,8 @@
                                 core_spill_mask,
                                 fp_spill_mask,
                                 code,
-                                code_size);
+                                code_size,
+                                osr);
   }
   return result;
 }
@@ -287,7 +290,8 @@
                                           size_t core_spill_mask,
                                           size_t fp_spill_mask,
                                           const uint8_t* code,
-                                          size_t code_size) {
+                                          size_t code_size,
+                                          bool osr) {
   size_t alignment = GetInstructionSetAlignment(kRuntimeISA);
   // Ensure the header ends up at expected instruction alignment.
   size_t header_size = RoundUp(sizeof(OatQuickMethodHeader), alignment);
@@ -329,8 +333,12 @@
   {
     MutexLock mu(self, lock_);
     method_code_map_.Put(code_ptr, method);
-    Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
-        method, method_header->GetEntryPoint());
+    if (osr) {
+      osr_code_map_.Put(method, code_ptr);
+    } else {
+      Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
+          method, method_header->GetEntryPoint());
+    }
     if (collection_in_progress_) {
       // We need to update the live bitmap if there is a GC to ensure it sees this new
       // code.
@@ -338,7 +346,7 @@
     }
     last_update_time_ns_.StoreRelease(NanoTime());
     VLOG(jit)
-        << "JIT added "
+        << "JIT added (osr = " << std::boolalpha << osr << std::noboolalpha << ") "
         << PrettyMethod(method) << "@" << method
         << " ccache_size=" << PrettySize(CodeCacheSizeLocked()) << ": "
         << " dcache_size=" << PrettySize(DataCacheSizeLocked()) << ": "
@@ -569,6 +577,10 @@
         info->GetMethod()->SetProfilingInfo(nullptr);
       }
     }
+
+    // Empty osr method map, as osr compiled code will be deleted (except the ones
+    // on thread stacks).
+    osr_code_map_.clear();
   }
 
   // Run a checkpoint on all threads to mark the JIT compiled code they are running.
@@ -662,6 +674,15 @@
   return method_header;
 }
 
+OatQuickMethodHeader* JitCodeCache::LookupOsrMethodHeader(ArtMethod* method) {
+  MutexLock mu(Thread::Current(), lock_);
+  auto it = osr_code_map_.find(method);
+  if (it == osr_code_map_.end()) {
+    return nullptr;
+  }
+  return OatQuickMethodHeader::FromCodePointer(it->second);
+}
+
 ProfilingInfo* JitCodeCache::AddProfilingInfo(Thread* self,
                                               ArtMethod* method,
                                               const std::vector<uint32_t>& entries,
@@ -733,12 +754,15 @@
   return last_update_time_ns_.LoadAcquire();
 }
 
-bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self) {
-  if (ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
+bool JitCodeCache::NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr) {
+  if (!osr && ContainsPc(method->GetEntryPointFromQuickCompiledCode())) {
     return false;
   }
 
   MutexLock mu(self, lock_);
+  if (osr && (osr_code_map_.find(method) != osr_code_map_.end())) {
+    return false;
+  }
   ProfilingInfo* info = method->GetProfilingInfo(sizeof(void*));
   if (info == nullptr || info->IsMethodBeingCompiled()) {
     return false;
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 69fc553..048f8d0 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -71,7 +71,7 @@
   // Number of compilations done throughout the lifetime of the JIT.
   size_t NumberOfCompilations() REQUIRES(!lock_);
 
-  bool NotifyCompilationOf(ArtMethod* method, Thread* self)
+  bool NotifyCompilationOf(ArtMethod* method, Thread* self, bool osr)
       SHARED_REQUIRES(Locks::mutator_lock_)
       REQUIRES(!lock_);
 
@@ -89,7 +89,8 @@
                       size_t core_spill_mask,
                       size_t fp_spill_mask,
                       const uint8_t* code,
-                      size_t code_size)
+                      size_t code_size,
+                      bool osr)
       SHARED_REQUIRES(Locks::mutator_lock_)
       REQUIRES(!lock_);
 
@@ -131,6 +132,10 @@
       REQUIRES(!lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  OatQuickMethodHeader* LookupOsrMethodHeader(ArtMethod* method)
+      REQUIRES(!lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   // Remove all methods in our cache that were allocated by 'alloc'.
   void RemoveMethodsIn(Thread* self, const LinearAlloc& alloc)
       REQUIRES(!lock_)
@@ -187,7 +192,8 @@
                               size_t core_spill_mask,
                               size_t fp_spill_mask,
                               const uint8_t* code,
-                              size_t code_size)
+                              size_t code_size,
+                              bool osr)
       REQUIRES(!lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
@@ -237,8 +243,10 @@
   void* data_mspace_ GUARDED_BY(lock_);
   // Bitmap for collecting code and data.
   std::unique_ptr<CodeCacheBitmap> live_bitmap_;
-  // This map holds compiled code associated to the ArtMethod.
+  // Holds compiled code associated to the ArtMethod.
   SafeMap<const void*, ArtMethod*> method_code_map_ GUARDED_BY(lock_);
+  // Holds osr compiled code associated to the ArtMethod.
+  SafeMap<ArtMethod*, const void*> osr_code_map_ GUARDED_BY(lock_);
   // ProfilingInfo objects we have allocated.
   std::vector<ProfilingInfo*> profiling_infos_ GUARDED_BY(lock_);
 
diff --git a/runtime/jit/jit_instrumentation.cc b/runtime/jit/jit_instrumentation.cc
index d597b36..a4e40ad 100644
--- a/runtime/jit/jit_instrumentation.cc
+++ b/runtime/jit/jit_instrumentation.cc
@@ -29,7 +29,8 @@
  public:
   enum TaskKind {
     kAllocateProfile,
-    kCompile
+    kCompile,
+    kCompileOsr
   };
 
   JitCompileTask(ArtMethod* method, TaskKind kind) : method_(method), kind_(kind) {
@@ -48,9 +49,14 @@
     ScopedObjectAccess soa(self);
     if (kind_ == kCompile) {
       VLOG(jit) << "JitCompileTask compiling method " << PrettyMethod(method_);
-      if (!Runtime::Current()->GetJit()->CompileMethod(method_, self)) {
+      if (!Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ false)) {
         VLOG(jit) << "Failed to compile method " << PrettyMethod(method_);
       }
+    } else if (kind_ == kCompileOsr) {
+      VLOG(jit) << "JitCompileTask compiling method osr " << PrettyMethod(method_);
+      if (!Runtime::Current()->GetJit()->CompileMethod(method_, self, /* osr */ true)) {
+        VLOG(jit) << "Failed to compile method osr " << PrettyMethod(method_);
+      }
     } else {
       DCHECK(kind_ == kAllocateProfile);
       if (ProfilingInfo::Create(self, method_, /* retry_allocation */ true)) {
@@ -72,9 +78,11 @@
 };
 
 JitInstrumentationCache::JitInstrumentationCache(size_t hot_method_threshold,
-                                                 size_t warm_method_threshold)
+                                                 size_t warm_method_threshold,
+                                                 size_t osr_method_threshold)
     : hot_method_threshold_(hot_method_threshold),
       warm_method_threshold_(warm_method_threshold),
+      osr_method_threshold_(osr_method_threshold),
       listener_(this) {
 }
 
@@ -151,6 +159,11 @@
     DCHECK(thread_pool_ != nullptr);
     thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompile));
   }
+
+  if (sample_count == osr_method_threshold_) {
+    DCHECK(thread_pool_ != nullptr);
+    thread_pool_->AddTask(self, new JitCompileTask(method, JitCompileTask::kCompileOsr));
+  }
 }
 
 JitInstrumentationListener::JitInstrumentationListener(JitInstrumentationCache* cache)
diff --git a/runtime/jit/jit_instrumentation.h b/runtime/jit/jit_instrumentation.h
index 06559ad..d1c5c44 100644
--- a/runtime/jit/jit_instrumentation.h
+++ b/runtime/jit/jit_instrumentation.h
@@ -96,7 +96,9 @@
 // Keeps track of which methods are hot.
 class JitInstrumentationCache {
  public:
-  JitInstrumentationCache(size_t hot_method_threshold, size_t warm_method_threshold);
+  JitInstrumentationCache(size_t hot_method_threshold,
+                          size_t warm_method_threshold,
+                          size_t osr_method_threshold);
   void AddSamples(Thread* self, ArtMethod* method, size_t samples)
       SHARED_REQUIRES(Locks::mutator_lock_);
   void CreateThreadPool();
@@ -112,6 +114,7 @@
  private:
   size_t hot_method_threshold_;
   size_t warm_method_threshold_;
+  size_t osr_method_threshold_;
   JitInstrumentationListener listener_;
   std::unique_ptr<ThreadPool> thread_pool_;
 
diff --git a/runtime/jit/offline_profiling_info.cc b/runtime/jit/offline_profiling_info.cc
index b4b872f..0aff1f7 100644
--- a/runtime/jit/offline_profiling_info.cc
+++ b/runtime/jit/offline_profiling_info.cc
@@ -33,6 +33,21 @@
 
 namespace art {
 
+// Transform the actual dex location into relative paths.
+// Note: this is OK because we don't store profiles of different apps into the same file.
+// Apps with split apks don't cause trouble because each split has a different name and will not
+// collide with other entries.
+std::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) {
+  DCHECK(!dex_location.empty());
+  size_t last_sep_index = dex_location.find_last_of('/');
+  if (last_sep_index == std::string::npos) {
+    return dex_location;
+  } else {
+    DCHECK(last_sep_index < dex_location.size());
+    return dex_location.substr(last_sep_index + 1);
+  }
+}
+
 bool ProfileCompilationInfo::SaveProfilingInfo(const std::string& filename,
                                                const std::vector<ArtMethod*>& methods) {
   if (methods.empty()) {
@@ -58,7 +73,7 @@
     ScopedObjectAccess soa(Thread::Current());
     for (auto it = methods.begin(); it != methods.end(); it++) {
       const DexFile* dex_file = (*it)->GetDexFile();
-      if (!info.AddData(dex_file->GetLocation(),
+      if (!info.AddData(GetProfileDexFileKey(dex_file->GetLocation()),
                         dex_file->GetLocationChecksum(),
                         (*it)->GetDexMethodIndex())) {
         return false;
@@ -107,8 +122,8 @@
  *    dex_location1,dex_location_checksum1,method_id11,method_id12...
  *    dex_location2,dex_location_checksum2,method_id21,method_id22...
  * e.g.
- *    /system/priv-app/app/app.apk,131232145,11,23,454,54
- *    /system/priv-app/app/app.apk:classes5.dex,218490184,39,13,49,1
+ *    app.apk,131232145,11,23,454,54
+ *    app.apk:classes5.dex,218490184,39,13,49,1
  **/
 bool ProfileCompilationInfo::Save(uint32_t fd) {
   DCHECK_GE(fd, 0u);
@@ -270,7 +285,7 @@
 }
 
 bool ProfileCompilationInfo::ContainsMethod(const MethodReference& method_ref) const {
-  auto info_it = info_.find(method_ref.dex_file->GetLocation());
+  auto info_it = info_.find(GetProfileDexFileKey(method_ref.dex_file->GetLocation()));
   if (info_it != info_.end()) {
     if (method_ref.dex_file->GetLocationChecksum() != info_it->second.checksum) {
       return false;
diff --git a/runtime/jit/offline_profiling_info.h b/runtime/jit/offline_profiling_info.h
index ffd1433..c388c4a 100644
--- a/runtime/jit/offline_profiling_info.h
+++ b/runtime/jit/offline_profiling_info.h
@@ -66,6 +66,8 @@
 
   // For testing purposes.
   bool Equals(ProfileCompilationInfo& other);
+  // Exposed for testing purpose.
+  static std::string GetProfileDexFileKey(const std::string& dex_location);
 
  private:
   bool AddData(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 18c52e4..c908b39 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -877,4 +877,22 @@
   return os;
 }
 
+void MemMap::TryReadable() {
+  if (base_begin_ == nullptr && base_size_ == 0) {
+    return;
+  }
+  CHECK_NE(prot_ & PROT_READ, 0);
+  volatile uint8_t* begin = reinterpret_cast<volatile uint8_t*>(base_begin_);
+  volatile uint8_t* end = begin + base_size_;
+  DCHECK(IsAligned<kPageSize>(begin));
+  DCHECK(IsAligned<kPageSize>(end));
+  // Read the first byte of each page. Use volatile to prevent the compiler from optimizing away the
+  // reads.
+  for (volatile uint8_t* ptr = begin; ptr < end; ptr += kPageSize) {
+    // This read could fault if protection wasn't set correctly.
+    uint8_t value = *ptr;
+    UNUSED(value);
+  }
+}
+
 }  // namespace art
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index ebd550a..3eaf576 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -184,6 +184,11 @@
   static void Init() REQUIRES(!Locks::mem_maps_lock_);
   static void Shutdown() REQUIRES(!Locks::mem_maps_lock_);
 
+  // If the map is PROT_READ, try to read each page of the map to check it is in fact readable (not
+  // faulting). This is used to diagnose a bug b/19894268 where mprotect doesn't seem to be working
+  // intermittently.
+  void TryReadable();
+
  private:
   MemMap(const std::string& name,
          uint8_t* begin,
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index b97d994..cdc6204 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -800,11 +800,11 @@
   return nullptr;
 }
 
-void Class::SetPreverifiedFlagOnAllMethods(size_t pointer_size) {
+void Class::SetSkipAccessChecksFlagOnAllMethods(size_t pointer_size) {
   DCHECK(IsVerified());
   for (auto& m : GetMethods(pointer_size)) {
     if (!m.IsNative() && m.IsInvokable()) {
-      m.SetPreverified();
+      m.SetSkipAccessChecks();
     }
   }
 }
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 8fa4975..388a231 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -287,14 +287,18 @@
     return (GetAccessFlags() & kAccSynthetic) != 0;
   }
 
-  // Returns true if the class can avoid access checks.
-  bool IsPreverified() SHARED_REQUIRES(Locks::mutator_lock_) {
-    return (GetAccessFlags() & kAccPreverified) != 0;
+  // Return whether the class had run the verifier at least once.
+  // This does not necessarily mean that access checks are avoidable,
+  // since the class methods might still need to be run with access checks.
+  bool WasVerificationAttempted() SHARED_REQUIRES(Locks::mutator_lock_) {
+    return (GetAccessFlags() & kAccSkipAccessChecks) != 0;
   }
 
-  void SetPreverified() SHARED_REQUIRES(Locks::mutator_lock_) {
+  // Mark the class as having gone through a verification attempt.
+  // Mutually exclusive from whether or not each method is allowed to skip access checks.
+  void SetVerificationAttempted() SHARED_REQUIRES(Locks::mutator_lock_) {
     uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccPreverified);
+    SetAccessFlags(flags | kAccVerificationAttempted);
   }
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -562,7 +566,7 @@
   // The size of java.lang.Class.class.
   static uint32_t ClassClassSize(size_t pointer_size) {
     // The number of vtable entries in java.lang.Class.
-    uint32_t vtable_entries = Object::kVTableLength + 69;
+    uint32_t vtable_entries = Object::kVTableLength + 72;
     return ComputeClassSize(true, vtable_entries, 0, 0, 4, 1, 0, pointer_size);
   }
 
@@ -1136,8 +1140,8 @@
   void VisitNativeRoots(Visitor& visitor, size_t pointer_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
-  // When class is verified, set the kAccPreverified flag on each method.
-  void SetPreverifiedFlagOnAllMethods(size_t pointer_size)
+  // When class is verified, set the kAccSkipAccessChecks flag on each method.
+  void SetSkipAccessChecksFlagOnAllMethods(size_t pointer_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   // Get the descriptor of the class. In a few cases a std::string is required, rather than
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 9946eab..ed4c5fc 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -42,14 +42,16 @@
 
 static constexpr uint32_t kAccJavaFlagsMask = 0xffff;  // bits set from Java sources (low 16)
 
-static constexpr uint32_t kAccConstructor =          0x00010000;  // method (dex only) <(cl)init>
-static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
-static constexpr uint32_t kAccClassIsProxy =         0x00040000;  // class  (dex only)
-static constexpr uint32_t kAccPreverified =          0x00080000;  // class (runtime),
-                                                                  // method (dex only)
-static constexpr uint32_t kAccFastNative =           0x00080000;  // method (dex only)
-static constexpr uint32_t kAccMiranda =              0x00200000;  // method (dex only)
-static constexpr uint32_t kAccDefault =              0x00400000;  // method (runtime)
+static constexpr uint32_t kAccConstructor =           0x00010000;  // method (dex only) <(cl)init>
+static constexpr uint32_t kAccDeclaredSynchronized =  0x00020000;  // method (dex only)
+static constexpr uint32_t kAccClassIsProxy =          0x00040000;  // class  (dex only)
+// Used by a method to denote that its execution does not need to go through slow path interpreter.
+static constexpr uint32_t kAccSkipAccessChecks =      0x00080000;  // method (dex only)
+// Used by a class to denote that the verifier has attempted to check it at least once.
+static constexpr uint32_t kAccVerificationAttempted = 0x00080000;  // class (runtime)
+static constexpr uint32_t kAccFastNative =            0x00080000;  // method (dex only)
+static constexpr uint32_t kAccMiranda =               0x00200000;  // method (dex only)
+static constexpr uint32_t kAccDefault =               0x00400000;  // method (runtime)
 // This is set by the class linker during LinkInterfaceMethods. Prior to that point we do not know
 // if any particular method needs to be a default conflict. Used to figure out at runtime if
 // invoking this method will throw an exception.
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index a7881ac..a092b9f 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -66,6 +66,7 @@
     DEBUG_ENABLE_JNI_LOGGING        = 1 << 4,
     DEBUG_GENERATE_DEBUG_INFO       = 1 << 5,
     DEBUG_ALWAYS_JIT                = 1 << 6,
+    DEBUG_NATIVE_DEBUGGABLE         = 1 << 7,
   };
 
   Runtime* const runtime = Runtime::Current();
@@ -117,6 +118,11 @@
     debug_flags &= ~DEBUG_ALWAYS_JIT;
   }
 
+  if ((debug_flags & DEBUG_NATIVE_DEBUGGABLE) != 0) {
+    runtime->AddCompilerOption("--native-debuggable");
+    debug_flags &= ~DEBUG_NATIVE_DEBUGGABLE;
+  }
+
   if (debug_flags != 0) {
     LOG(ERROR) << StringPrintf("Unknown bits set in debug_flags: %#x", debug_flags);
   }
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 0ddd4a2..b5d859b 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -388,7 +388,7 @@
   auto h_args = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(args));
   Handle<mirror::Class> h_klass = hs.NewHandle(DecodeClass(soa, javaThis));
   ArtMethod* result = nullptr;
-  for (auto& m : h_klass->GetVirtualMethods(sizeof(void*))) {
+  for (auto& m : h_klass->GetDeclaredVirtualMethods(sizeof(void*))) {
     auto* np_method = m.GetInterfaceMethodIfProxy(sizeof(void*));
     // May cause thread suspension.
     mirror::String* np_name = np_method->GetNameAsString(soa.Self());
@@ -469,14 +469,21 @@
   return soa.AddLocalReference<jobjectArray>(ret.Get());
 }
 
-static jobject Class_getDeclaredAnnotation(JNIEnv* env, jobject javaThis, jclass annotationType) {
+static jobject Class_getDeclaredAnnotation(JNIEnv* env, jobject javaThis, jclass annotationClass) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<2> hs(soa.Self());
   Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
+
+  // Handle public contract to throw NPE if the "annotationClass" argument was null.
+  if (UNLIKELY(annotationClass == nullptr)) {
+    ThrowNullPointerException("annotationClass");
+    return nullptr;
+  }
+
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return nullptr;
   }
-  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationClass)));
   return soa.AddLocalReference<jobject>(
       klass->GetDexFile().GetAnnotationForClass(klass, annotation_class));
 }
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index de90f0a..18cf81a 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -24,6 +24,7 @@
 #include "base/stl_util.h"
 #include "class_linker.h"
 #include "dex_file-inl.h"
+#include "gc/scoped_gc_critical_section.h"
 #include "gc/space/image_space.h"
 #include "handle_scope-inl.h"
 #include "mirror/class_loader.h"
@@ -379,27 +380,36 @@
           // spaces array.
           {
             ScopedThreadSuspension sts(self, kSuspended);
+            gc::ScopedGCCriticalSection gcs(self,
+                                            gc::kGcCauseAddRemoveAppImageSpace,
+                                            gc::kCollectorTypeAddRemoveAppImageSpace);
             ScopedSuspendAll ssa("Add image space");
             runtime->GetHeap()->AddSpace(image_space.get());
           }
           added_image_space = true;
-          if (!runtime->GetClassLinker()->AddImageSpace(image_space.get(),
-                                                        h_loader,
-                                                        dex_elements,
-                                                        dex_location,
-                                                        /*out*/&dex_files,
-                                                        /*out*/&temp_error_msg)) {
+          if (runtime->GetClassLinker()->AddImageSpace(image_space.get(),
+                                                       h_loader,
+                                                       dex_elements,
+                                                       dex_location,
+                                                       /*out*/&dex_files,
+                                                       /*out*/&temp_error_msg)) {
+            // Successfully added image space to heap, release the map so that it does not get
+            // freed.
+            image_space.release();
+          } else {
             LOG(INFO) << "Failed to add image file " << temp_error_msg;
             dex_files.clear();
             {
               ScopedThreadSuspension sts(self, kSuspended);
+              gc::ScopedGCCriticalSection gcs(self,
+                                              gc::kGcCauseAddRemoveAppImageSpace,
+                                              gc::kCollectorTypeAddRemoveAppImageSpace);
               ScopedSuspendAll ssa("Remove image space");
               runtime->GetHeap()->RemoveSpace(image_space.get());
             }
             added_image_space = false;
             // Non-fatal, don't update error_msg.
           }
-          image_space.release();
         }
       }
     }
diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h
index 5643739..2b7eca2 100644
--- a/runtime/oat_quick_method_header.h
+++ b/runtime/oat_quick_method_header.h
@@ -108,7 +108,7 @@
   }
 
   template <bool kCheckFrameSize = true>
-  uint32_t GetFrameSizeInBytes() {
+  uint32_t GetFrameSizeInBytes() const {
     uint32_t result = frame_info_.FrameSizeInBytes();
     if (kCheckFrameSize) {
       DCHECK_LE(static_cast<size_t>(kStackAlignment), result);
diff --git a/runtime/openjdkjvm/Android.mk b/runtime/openjdkjvm/Android.mk
new file mode 100644
index 0000000..9b7404e
--- /dev/null
+++ b/runtime/openjdkjvm/Android.mk
@@ -0,0 +1,20 @@
+#
+# Copyright (C) 2016 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := openjdkjvm-phony
+include $(BUILD_PHONY_PACKAGE)
diff --git a/runtime/openjdkjvm/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION b/runtime/openjdkjvm/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/runtime/openjdkjvm/MODULE_LICENSE_GPL_WITH_CLASSPATH_EXCEPTION
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index ab0d934..725067a 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -66,17 +66,13 @@
 #undef LOG_TAG
 #define LOG_TAG "artopenjdk"
 
-using art::DEBUG;
 using art::WARNING;
-using art::VERBOSE;
 using art::INFO;
 using art::ERROR;
 using art::FATAL;
 
 /* posix open() with extensions; used by e.g. ZipFile */
 JNIEXPORT jint JVM_Open(const char* fname, jint flags, jint mode) {
-    LOG(DEBUG) << "JVM_Open fname='" << fname << "', flags=" << flags << ", mode=" << mode;
-
     /*
      * The call is expected to handle JVM_O_DELETE, which causes the file
      * to be removed after it is opened.  Also, some code seems to
@@ -86,7 +82,6 @@
     int fd = TEMP_FAILURE_RETRY(open(fname, flags & ~JVM_O_DELETE, mode));
     if (fd < 0) {
         int err = errno;
-        LOG(DEBUG) << "open(" << fname << ") failed: " << strerror(errno);
         if (err == EEXIST) {
             return JVM_EEXIST;
         } else {
@@ -95,39 +90,32 @@
     }
 
     if (flags & JVM_O_DELETE) {
-        LOG(DEBUG) << "Deleting '" << fname << "' after open\n";
         if (unlink(fname) != 0) {
             LOG(WARNING) << "Post-open deletion of '" << fname << "' failed: " << strerror(errno);
         }
-        /* ignore */
     }
 
-    LOG(VERBOSE) << "open(" << fname << ") --> " << fd;
     return fd;
 }
 
 /* posix close() */
 JNIEXPORT jint JVM_Close(jint fd) {
-    LOG(DEBUG) << "JVM_Close fd=" << fd;
     // don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR
     return close(fd);
 }
 
 /* posix read() */
 JNIEXPORT jint JVM_Read(jint fd, char* buf, jint nbytes) {
-    LOG(DEBUG) << "JVM_Read fd=" << fd << ", buf='" << buf << "', nbytes=" << nbytes;
     return TEMP_FAILURE_RETRY(read(fd, buf, nbytes));
 }
 
 /* posix write(); is used to write messages to stderr */
 JNIEXPORT jint JVM_Write(jint fd, char* buf, jint nbytes) {
-    LOG(DEBUG) << "JVM_Write fd=" << fd << ", buf='" << buf << "', nbytes=" << nbytes;
     return TEMP_FAILURE_RETRY(write(fd, buf, nbytes));
 }
 
 /* posix lseek() */
 JNIEXPORT jlong JVM_Lseek(jint fd, jlong offset, jint whence) {
-    LOG(DEBUG) << "JVM_Lseek fd=" << fd << ", offset=" << offset << ", whence=" << whence;
     return TEMP_FAILURE_RETRY(lseek(fd, offset, whence));
 }
 
@@ -136,42 +124,41 @@
  * mutexes.  They're used by ZipFile.
  */
 JNIEXPORT void* JVM_RawMonitorCreate(void) {
-    LOG(DEBUG) << "JVM_RawMonitorCreate";
-    pthread_mutex_t* newMutex =
+    pthread_mutex_t* mutex =
         reinterpret_cast<pthread_mutex_t*>(malloc(sizeof(pthread_mutex_t)));
-    pthread_mutex_init(newMutex, NULL);
-    return newMutex;
+    CHECK(mutex != nullptr);
+    CHECK_PTHREAD_CALL(pthread_mutex_init, (mutex, nullptr), "JVM_RawMonitorCreate");
+    return mutex;
 }
 
 JNIEXPORT void JVM_RawMonitorDestroy(void* mon) {
-    LOG(DEBUG) << "JVM_RawMonitorDestroy mon=" << mon;
-    pthread_mutex_destroy(reinterpret_cast<pthread_mutex_t*>(mon));
+    CHECK_PTHREAD_CALL(pthread_mutex_destroy,
+                       (reinterpret_cast<pthread_mutex_t*>(mon)),
+                       "JVM_RawMonitorDestroy");
+    free(mon);
 }
 
 JNIEXPORT jint JVM_RawMonitorEnter(void* mon) {
-    LOG(DEBUG) << "JVM_RawMonitorEnter mon=" << mon;
     return pthread_mutex_lock(reinterpret_cast<pthread_mutex_t*>(mon));
 }
 
 JNIEXPORT void JVM_RawMonitorExit(void* mon) {
-    LOG(DEBUG) << "JVM_RawMonitorExit mon=" << mon;
-    pthread_mutex_unlock(reinterpret_cast<pthread_mutex_t*>(mon));
+    CHECK_PTHREAD_CALL(pthread_mutex_unlock,
+                       (reinterpret_cast<pthread_mutex_t*>(mon)),
+                       "JVM_RawMonitorExit");
 }
 
 JNIEXPORT char* JVM_NativePath(char* path) {
-    LOG(DEBUG) << "JVM_NativePath path='" << path << "'";
     return path;
 }
 
 JNIEXPORT jint JVM_GetLastErrorString(char* buf, int len) {
 #if defined(__GLIBC__) || defined(__BIONIC__)
-  int err = errno;    // grab before JVM_TRACE can trash it
-  LOG(DEBUG) << "JVM_GetLastErrorString buf=" << buf << ", len=" << len;
-
   if (len == 0) {
     return 0;
   }
 
+  const int err = errno;
   char* result = strerror_r(err, buf, len);
   if (result != buf) {
     strncpy(buf, result, len);
@@ -203,27 +190,22 @@
 
 /* posix fsync() */
 JNIEXPORT jint JVM_Sync(jint fd) {
-    LOG(DEBUG) << "JVM_Sync fd=" << fd;
     return TEMP_FAILURE_RETRY(fsync(fd));
 }
 
 JNIEXPORT void* JVM_FindLibraryEntry(void* handle, const char* name) {
-    LOG(DEBUG) << "JVM_FindLibraryEntry handle=" << handle << " name=" << name;
     return dlsym(handle, name);
 }
 
-JNIEXPORT jlong JVM_CurrentTimeMillis(JNIEnv* env, jclass clazz ATTRIBUTE_UNUSED) {
-    LOG(DEBUG) << "JVM_CurrentTimeMillis env=" << env;
+JNIEXPORT jlong JVM_CurrentTimeMillis(JNIEnv* env ATTRIBUTE_UNUSED,
+                                      jclass clazz ATTRIBUTE_UNUSED) {
     struct timeval tv;
-
     gettimeofday(&tv, (struct timezone *) NULL);
     jlong when = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
     return when;
 }
 
 JNIEXPORT jint JVM_Socket(jint domain, jint type, jint protocol) {
-    LOG(DEBUG) << "JVM_Socket domain=" << domain << ", type=" << type << ", protocol=" << protocol;
-
     return TEMP_FAILURE_RETRY(socket(domain, type, protocol));
 }
 
@@ -247,21 +229,15 @@
 
 JNIEXPORT jint JVM_SetSockOpt(jint fd, int level, int optname,
     const char* optval, int optlen) {
-  LOG(DEBUG) << "JVM_SetSockOpt fd=" << fd << ", level=" << level << ", optname=" << optname
-             << ", optval=" << optval << ", optlen=" << optlen;
   return TEMP_FAILURE_RETRY(setsockopt(fd, level, optname, optval, optlen));
 }
 
 JNIEXPORT jint JVM_SocketShutdown(jint fd, jint howto) {
-  LOG(DEBUG) << "JVM_SocketShutdown fd=" << fd << ", howto=" << howto;
   return TEMP_FAILURE_RETRY(shutdown(fd, howto));
 }
 
 JNIEXPORT jint JVM_GetSockOpt(jint fd, int level, int optname, char* optval,
   int* optlen) {
-  LOG(DEBUG) << "JVM_GetSockOpt fd=" << fd << ", level=" << level << ", optname=" << optname
-             << ", optval=" << optval << ", optlen=" << optlen;
-
   socklen_t len = *optlen;
   int cc = TEMP_FAILURE_RETRY(getsockopt(fd, level, optname, optval, &len));
   *optlen = len;
@@ -269,8 +245,6 @@
 }
 
 JNIEXPORT jint JVM_GetSockName(jint fd, struct sockaddr* addr, int* addrlen) {
-  LOG(DEBUG) << "JVM_GetSockName fd=" << fd << ", addr=" << addr << ", addrlen=" << addrlen;
-
   socklen_t len = *addrlen;
   int cc = TEMP_FAILURE_RETRY(getsockname(fd, addr, &len));
   *addrlen = len;
@@ -278,10 +252,7 @@
 }
 
 JNIEXPORT jint JVM_SocketAvailable(jint fd, jint* result) {
-  LOG(DEBUG) << "JVM_SocketAvailable fd=" << fd << ", result=" << result;
-
   if (TEMP_FAILURE_RETRY(ioctl(fd, FIONREAD, result)) < 0) {
-      LOG(DEBUG) << "ioctl(" << fd << ", FIONREAD) failed: " << strerror(errno);
       return JNI_FALSE;
   }
 
@@ -289,39 +260,27 @@
 }
 
 JNIEXPORT jint JVM_Send(jint fd, char* buf, jint nBytes, jint flags) {
-  LOG(DEBUG) << "JVM_Send fd=" << fd << ", buf=" << buf << ", nBytes="
-             << nBytes << ", flags=" << flags;
-
   return TEMP_FAILURE_RETRY(send(fd, buf, nBytes, flags));
 }
 
 JNIEXPORT jint JVM_SocketClose(jint fd) {
-  LOG(DEBUG) << "JVM_SocketClose fd=" << fd;
-
-    // don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR
+  // Don't want TEMP_FAILURE_RETRY here -- file is closed even if EINTR.
   return close(fd);
 }
 
 JNIEXPORT jint JVM_Listen(jint fd, jint count) {
-  LOG(DEBUG) << "JVM_Listen fd=" << fd << ", count=" << count;
-
   return TEMP_FAILURE_RETRY(listen(fd, count));
 }
 
 JNIEXPORT jint JVM_Connect(jint fd, struct sockaddr* addr, jint addrlen) {
-  LOG(DEBUG) << "JVM_Connect fd=" << fd << ", addr=" << addr << ", addrlen=" << addrlen;
-
   return TEMP_FAILURE_RETRY(connect(fd, addr, addrlen));
 }
 
 JNIEXPORT int JVM_GetHostName(char* name, int namelen) {
-  LOG(DEBUG) << "JVM_GetHostName name=" << name << ", namelen=" << namelen;
-
   return TEMP_FAILURE_RETRY(gethostname(name, namelen));
 }
 
 JNIEXPORT jstring JVM_InternString(JNIEnv* env, jstring jstr) {
-  LOG(DEBUG) << "JVM_InternString env=" << env << ", jstr=" << jstr;
   art::ScopedFastNativeObjectAccess soa(env);
   art::mirror::String* s = soa.Decode<art::mirror::String*>(jstr);
   art::mirror::String* result = s->Intern();
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index aa64ee3..f9d916a 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -146,6 +146,10 @@
       .Define({"-XX:EnableHSpaceCompactForOOM", "-XX:DisableHSpaceCompactForOOM"})
           .WithValues({true, false})
           .IntoKey(M::EnableHSpaceCompactForOOM)
+      .Define("-XX:DumpNativeStackOnSigQuit:_")
+          .WithType<bool>()
+          .WithValueMap({{"false", false}, {"true", true}})
+          .IntoKey(M::DumpNativeStackOnSigQuit)
       .Define("-Xusejit:_")
           .WithType<bool>()
           .WithValueMap({{"false", false}, {"true", true}})
@@ -277,6 +281,8 @@
           .WithType<ExperimentalFlags>()
           .AppendValues()
           .IntoKey(M::Experimental)
+      .Define("-Xforce-nb-testing")
+          .IntoKey(M::ForceNativeBridge)
       .Ignore({
           "-ea", "-da", "-enableassertions", "-disableassertions", "--runtime-arg", "-esa",
           "-dsa", "-enablesystemassertions", "-disablesystemassertions", "-Xrs", "-Xint:_",
@@ -665,6 +671,7 @@
   UsageMessage(stream, "  -XX:BackgroundGC=none\n");
   UsageMessage(stream, "  -XX:LargeObjectSpace={disabled,map,freelist}\n");
   UsageMessage(stream, "  -XX:LargeObjectThreshold=N\n");
+  UsageMessage(stream, "  -XX:DumpNativeStackOnSigQuit=booleanvalue\n");
   UsageMessage(stream, "  -Xmethod-trace\n");
   UsageMessage(stream, "  -Xmethod-trace-file:filename");
   UsageMessage(stream, "  -Xmethod-trace-file-size:integervalue\n");
diff --git a/runtime/quick/inline_method_analyser.cc b/runtime/quick/inline_method_analyser.cc
index 6b84c8f..9b10f2e 100644
--- a/runtime/quick/inline_method_analyser.cc
+++ b/runtime/quick/inline_method_analyser.cc
@@ -22,6 +22,7 @@
 #include "dex_file-inl.h"
 #include "dex_instruction.h"
 #include "dex_instruction-inl.h"
+#include "dex_instruction_utils.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "verifier/method_verifier-inl.h"
@@ -33,6 +34,366 @@
 
 namespace art {
 
+namespace {  // anonymous namespace
+
+// Helper class for matching a pattern.
+class Matcher {
+ public:
+  // Match function type.
+  typedef bool MatchFn(Matcher* matcher);
+
+  template <size_t size>
+  static bool Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]);
+
+  // Match and advance.
+
+  static bool Mark(Matcher* matcher);
+
+  template <bool (Matcher::*Fn)()>
+  static bool Required(Matcher* matcher);
+
+  template <bool (Matcher::*Fn)()>
+  static bool Repeated(Matcher* matcher);  // On match, returns to the mark.
+
+  // Match an individual instruction.
+
+  template <Instruction::Code opcode> bool Opcode();
+  bool Const0();
+  bool IPutOnThis();
+
+ private:
+  explicit Matcher(const DexFile::CodeItem* code_item)
+      : code_item_(code_item),
+        instruction_(Instruction::At(code_item->insns_)),
+        pos_(0u),
+        mark_(0u) { }
+
+  static bool DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size);
+
+  const DexFile::CodeItem* const code_item_;
+  const Instruction* instruction_;
+  size_t pos_;
+  size_t mark_;
+};
+
+template <size_t size>
+bool Matcher::Match(const DexFile::CodeItem* code_item, MatchFn* const (&pattern)[size]) {
+  return DoMatch(code_item, pattern, size);
+}
+
+bool Matcher::Mark(Matcher* matcher) {
+  matcher->pos_ += 1u;  // Advance to the next match function before marking.
+  matcher->mark_ = matcher->pos_;
+  return true;
+}
+
+template <bool (Matcher::*Fn)()>
+bool Matcher::Required(Matcher* matcher) {
+  if (!(matcher->*Fn)()) {
+    return false;
+  }
+  matcher->pos_ += 1u;
+  matcher->instruction_ = matcher->instruction_->Next();
+  return true;
+}
+
+template <bool (Matcher::*Fn)()>
+bool Matcher::Repeated(Matcher* matcher) {
+  if (!(matcher->*Fn)()) {
+    // Didn't match optional instruction, try the next match function.
+    matcher->pos_ += 1u;
+    return true;
+  }
+  matcher->pos_ = matcher->mark_;
+  matcher->instruction_ = matcher->instruction_->Next();
+  return true;
+}
+
+template <Instruction::Code opcode>
+bool Matcher::Opcode() {
+  return instruction_->Opcode() == opcode;
+}
+
+// Match const 0.
+bool Matcher::Const0() {
+  return IsInstructionDirectConst(instruction_->Opcode()) &&
+      (instruction_->Opcode() == Instruction::CONST_WIDE ? instruction_->VRegB_51l() == 0
+                                                         : instruction_->VRegB() == 0);
+}
+
+bool Matcher::IPutOnThis() {
+  DCHECK_NE(code_item_->ins_size_, 0u);
+  return IsInstructionIPut(instruction_->Opcode()) &&
+      instruction_->VRegB_22c() == code_item_->registers_size_ - code_item_->ins_size_;
+}
+
+bool Matcher::DoMatch(const DexFile::CodeItem* code_item, MatchFn* const* pattern, size_t size) {
+  Matcher matcher(code_item);
+  while (matcher.pos_ != size) {
+    if (!pattern[matcher.pos_](&matcher)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Used for a single invoke in a constructor. In that situation, the method verifier makes
+// sure we invoke a constructor either in the same class or superclass with at least "this".
+ArtMethod* GetTargetConstructor(ArtMethod* method, const Instruction* invoke_direct)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
+  DCHECK_EQ(invoke_direct->VRegC_35c(),
+            method->GetCodeItem()->registers_size_ - method->GetCodeItem()->ins_size_);
+  uint32_t method_index = invoke_direct->VRegB_35c();
+  size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+  ArtMethod* target_method =
+      method->GetDexCache()->GetResolvedMethod(method_index, pointer_size);
+  if (kIsDebugBuild && target_method != nullptr) {
+    CHECK(!target_method->IsStatic());
+    CHECK(target_method->IsConstructor());
+    CHECK(target_method->GetDeclaringClass() == method->GetDeclaringClass() ||
+          target_method->GetDeclaringClass() == method->GetDeclaringClass()->GetSuperClass());
+  }
+  return target_method;
+}
+
+// Return the forwarded arguments and check that all remaining arguments are zero.
+// If the check fails, return static_cast<size_t>(-1).
+size_t CountForwardedConstructorArguments(const DexFile::CodeItem* code_item,
+                                          const Instruction* invoke_direct,
+                                          uint16_t zero_vreg_mask) {
+  DCHECK_EQ(invoke_direct->Opcode(), Instruction::INVOKE_DIRECT);
+  size_t number_of_args = invoke_direct->VRegA_35c();
+  DCHECK_NE(number_of_args, 0u);
+  uint32_t args[Instruction::kMaxVarArgRegs];
+  invoke_direct->GetVarArgs(args);
+  uint16_t this_vreg = args[0];
+  DCHECK_EQ(this_vreg, code_item->registers_size_ - code_item->ins_size_);  // Checked by verifier.
+  size_t forwarded = 1u;
+  while (forwarded < number_of_args &&
+      args[forwarded] == this_vreg + forwarded &&
+      (zero_vreg_mask & (1u << args[forwarded])) == 0) {
+    ++forwarded;
+  }
+  for (size_t i = forwarded; i != number_of_args; ++i) {
+    if ((zero_vreg_mask & (1u << args[i])) == 0) {
+      return static_cast<size_t>(-1);
+    }
+  }
+  return forwarded;
+}
+
+uint16_t GetZeroVRegMask(const Instruction* const0) {
+  DCHECK(IsInstructionDirectConst(const0->Opcode()));
+  DCHECK((const0->Opcode() == Instruction::CONST_WIDE) ? const0->VRegB_51l() == 0u
+                                                       : const0->VRegB() == 0);
+  uint16_t base_mask = IsInstructionConstWide(const0->Opcode()) ? 3u : 1u;
+  return base_mask << const0->VRegA();
+}
+
+// We limit the number of IPUTs storing parameters. There can be any number
+// of IPUTs that store the value 0 as they are useless in a constructor as
+// the object always starts zero-initialized. We also eliminate all but the
+// last store to any field as they are not observable; not even if the field
+// is volatile as no reference to the object can escape from a constructor
+// with this pattern.
+static constexpr size_t kMaxConstructorIPuts = 3u;
+
+struct ConstructorIPutData {
+  ConstructorIPutData() : field_index(DexFile::kDexNoIndex16), arg(0u) { }
+
+  uint16_t field_index;
+  uint16_t arg;
+};
+
+bool RecordConstructorIPut(ArtMethod* method,
+                           const Instruction* new_iput,
+                           uint16_t this_vreg,
+                           uint16_t zero_vreg_mask,
+                           /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts])
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  DCHECK(IsInstructionIPut(new_iput->Opcode()));
+  uint32_t field_index = new_iput->VRegC_22c();
+  size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+  mirror::DexCache* dex_cache = method->GetDexCache();
+  ArtField* field = dex_cache->GetResolvedField(field_index, pointer_size);
+  if (UNLIKELY(field == nullptr)) {
+    return false;
+  }
+  // Remove previous IPUT to the same field, if any. Different field indexes may refer
+  // to the same field, so we need to compare resolved fields from the dex cache.
+  for (size_t old_pos = 0; old_pos != arraysize(iputs); ++old_pos) {
+    if (iputs[old_pos].field_index == DexFile::kDexNoIndex16) {
+      break;
+    }
+    ArtField* f = dex_cache->GetResolvedField(iputs[old_pos].field_index, pointer_size);
+    DCHECK(f != nullptr);
+    if (f == field) {
+      auto back_it = std::copy(iputs + old_pos + 1, iputs + arraysize(iputs), iputs + old_pos);
+      *back_it = ConstructorIPutData();
+      break;
+    }
+  }
+  // If the stored value isn't zero, record the IPUT.
+  if ((zero_vreg_mask & (1u << new_iput->VRegA_22c())) == 0u) {
+    size_t new_pos = 0;
+    while (new_pos != arraysize(iputs) && iputs[new_pos].field_index != DexFile::kDexNoIndex16) {
+      ++new_pos;
+    }
+    if (new_pos == arraysize(iputs)) {
+      return false;  // Exceeded capacity of the output array.
+    }
+    iputs[new_pos].field_index = field_index;
+    iputs[new_pos].arg = new_iput->VRegA_22c() - this_vreg;
+  }
+  return true;
+}
+
+bool DoAnalyseConstructor(const DexFile::CodeItem* code_item,
+                          ArtMethod* method,
+                          /*inout*/ ConstructorIPutData (&iputs)[kMaxConstructorIPuts])
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  // On entry we should not have any IPUTs yet.
+  DCHECK_EQ(0, std::count_if(
+      iputs,
+      iputs + arraysize(iputs),
+      [](const ConstructorIPutData& iput_data) {
+        return iput_data.field_index != DexFile::kDexNoIndex16;
+      }));
+
+  // Limit the maximum number of code units we're willing to match.
+  static constexpr size_t kMaxCodeUnits = 16u;
+
+  // Limit the number of registers that the constructor may use to 16.
+  // Given that IPUTs must use low 16 registers and we do not match MOVEs,
+  // this is a reasonable limitation.
+  static constexpr size_t kMaxVRegs = 16u;
+
+  // We try to match a constructor that calls another constructor (either in
+  // superclass or in the same class) with the same parameters, or with some
+  // parameters truncated (allowed only for calls to superclass constructor)
+  // or with extra parameters with value 0 (with any type, including null).
+  // This call can be followed by optional IPUTs on "this" storing either one
+  // of the parameters or 0 and the code must then finish with RETURN_VOID.
+  // The called constructor must be either java.lang.Object.<init>() or it
+  // must also match the same pattern.
+  static Matcher::MatchFn* const kConstructorPattern[] = {
+      &Matcher::Mark,
+      &Matcher::Repeated<&Matcher::Const0>,
+      &Matcher::Required<&Matcher::Opcode<Instruction::INVOKE_DIRECT>>,
+      &Matcher::Mark,
+      &Matcher::Repeated<&Matcher::Const0>,
+      &Matcher::Repeated<&Matcher::IPutOnThis>,
+      &Matcher::Required<&Matcher::Opcode<Instruction::RETURN_VOID>>,
+  };
+
+  DCHECK(method != nullptr);
+  DCHECK(!method->IsStatic());
+  DCHECK(method->IsConstructor());
+  DCHECK(code_item != nullptr);
+  if (!method->GetDeclaringClass()->IsVerified() ||
+      code_item->insns_size_in_code_units_ > kMaxCodeUnits ||
+      code_item->registers_size_ > kMaxVRegs ||
+      !Matcher::Match(code_item, kConstructorPattern)) {
+    return false;
+  }
+
+  // Verify the invoke, prevent a few odd cases and collect IPUTs.
+  uint16_t this_vreg = code_item->registers_size_ - code_item->ins_size_;
+  uint16_t zero_vreg_mask = 0u;
+  for (const Instruction* instruction = Instruction::At(code_item->insns_);
+      instruction->Opcode() != Instruction::RETURN_VOID;
+      instruction = instruction->Next()) {
+    if (instruction->Opcode() == Instruction::INVOKE_DIRECT) {
+      ArtMethod* target_method = GetTargetConstructor(method, instruction);
+      if (target_method == nullptr) {
+        return false;
+      }
+      // We allow forwarding constructors only if they pass more arguments
+      // to prevent infinite recursion.
+      if (target_method->GetDeclaringClass() == method->GetDeclaringClass() &&
+          instruction->VRegA_35c() <= code_item->ins_size_) {
+        return false;
+      }
+      size_t forwarded = CountForwardedConstructorArguments(code_item, instruction, zero_vreg_mask);
+      if (forwarded == static_cast<size_t>(-1)) {
+        return false;
+      }
+      if (target_method->GetDeclaringClass()->IsObjectClass()) {
+        DCHECK_EQ(Instruction::At(target_method->GetCodeItem()->insns_)->Opcode(),
+                  Instruction::RETURN_VOID);
+      } else {
+        const DexFile::CodeItem* target_code_item = target_method->GetCodeItem();
+        if (target_code_item == nullptr) {
+          return false;  // Native constructor?
+        }
+        if (!DoAnalyseConstructor(target_code_item, target_method, iputs)) {
+          return false;
+        }
+        // Prune IPUTs with zero input.
+        auto kept_end = std::remove_if(
+            iputs,
+            iputs + arraysize(iputs),
+            [forwarded](const ConstructorIPutData& iput_data) {
+              return iput_data.arg >= forwarded;
+            });
+        std::fill(kept_end, iputs + arraysize(iputs), ConstructorIPutData());
+        // If we have any IPUTs from the call, check that the target method is in the same
+        // dex file (compare DexCache references), otherwise field_indexes would be bogus.
+        if (iputs[0].field_index != DexFile::kDexNoIndex16 &&
+            target_method->GetDexCache() != method->GetDexCache()) {
+          return false;
+        }
+      }
+    } else if (IsInstructionDirectConst(instruction->Opcode())) {
+      zero_vreg_mask |= GetZeroVRegMask(instruction);
+      if ((zero_vreg_mask & (1u << this_vreg)) != 0u) {
+        return false;  // Overwriting `this` is unsupported.
+      }
+    } else {
+      DCHECK(IsInstructionIPut(instruction->Opcode()));
+      DCHECK_EQ(instruction->VRegB_22c(), this_vreg);
+      if (!RecordConstructorIPut(method, instruction, this_vreg, zero_vreg_mask, iputs)) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+}  // anonymous namespace
+
+bool AnalyseConstructor(const DexFile::CodeItem* code_item,
+                        ArtMethod* method,
+                        InlineMethod* result)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  ConstructorIPutData iputs[kMaxConstructorIPuts];
+  if (!DoAnalyseConstructor(code_item, method, iputs)) {
+    return false;
+  }
+  static_assert(kMaxConstructorIPuts == 3, "Unexpected limit");  // Code below depends on this.
+  DCHECK(iputs[0].field_index != DexFile::kDexNoIndex16 ||
+         iputs[1].field_index == DexFile::kDexNoIndex16);
+  DCHECK(iputs[1].field_index != DexFile::kDexNoIndex16 ||
+         iputs[2].field_index == DexFile::kDexNoIndex16);
+
+#define STORE_IPUT(n)                                                         \
+  do {                                                                        \
+    result->d.constructor_data.iput##n##_field_index = iputs[n].field_index;  \
+    result->d.constructor_data.iput##n##_arg = iputs[n].arg;                  \
+  } while (false)
+
+  STORE_IPUT(0);
+  STORE_IPUT(1);
+  STORE_IPUT(2);
+#undef STORE_IPUT
+
+  result->opcode = kInlineOpConstructor;
+  result->flags = kInlineSpecial;
+  result->d.constructor_data.reserved = 0u;
+  return true;
+}
+
 static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET), "iget type");
 static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_WIDE), "iget_wide type");
 static_assert(InlineMethodAnalyser::IsInstructionIGet(Instruction::IGET_OBJECT),
@@ -123,7 +484,19 @@
     case Instruction::CONST_16:
     case Instruction::CONST_HIGH16:
       // TODO: Support wide constants (RETURN_WIDE).
-      return AnalyseConstMethod(code_item, result);
+      if (AnalyseConstMethod(code_item, result)) {
+        return true;
+      }
+      FALLTHROUGH_INTENDED;
+    case Instruction::CONST_WIDE:
+    case Instruction::CONST_WIDE_16:
+    case Instruction::CONST_WIDE_32:
+    case Instruction::CONST_WIDE_HIGH16:
+    case Instruction::INVOKE_DIRECT:
+      if (method != nullptr && !method->IsStatic() && method->IsConstructor()) {
+        return AnalyseConstructor(code_item, method, result);
+      }
+      return false;
     case Instruction::IGET:
     case Instruction::IGET_OBJECT:
     case Instruction::IGET_BOOLEAN:
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
index 046d225..0b09a70 100644
--- a/runtime/quick/inline_method_analyser.h
+++ b/runtime/quick/inline_method_analyser.h
@@ -107,6 +107,7 @@
   kInlineOpNonWideConst,
   kInlineOpIGet,
   kInlineOpIPut,
+  kInlineOpConstructor,
   kInlineStringInit,
 };
 std::ostream& operator<<(std::ostream& os, const InlineMethodOpcode& rhs);
@@ -168,6 +169,19 @@
 static_assert(sizeof(InlineReturnArgData) == sizeof(uint64_t),
               "Invalid size of InlineReturnArgData");
 
+struct InlineConstructorData {
+  // There can be up to 3 IPUTs, unused fields are marked with kNoDexIndex16.
+  uint16_t iput0_field_index;
+  uint16_t iput1_field_index;
+  uint16_t iput2_field_index;
+  uint16_t iput0_arg : 4;
+  uint16_t iput1_arg : 4;
+  uint16_t iput2_arg : 4;
+  uint16_t reserved : 4;
+};
+static_assert(sizeof(InlineConstructorData) == sizeof(uint64_t),
+              "Invalid size of InlineConstructorData");
+
 struct InlineMethod {
   InlineMethodOpcode opcode;
   InlineMethodFlags flags;
@@ -175,6 +189,7 @@
     uint64_t data;
     InlineIGetIPutData ifield_data;
     InlineReturnArgData return_data;
+    InlineConstructorData constructor_data;
   } d;
 };
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 0c06ca6..2aeb792 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -335,6 +335,7 @@
     os << "Runtime aborting...\n";
     if (Runtime::Current() == nullptr) {
       os << "(Runtime does not yet exist!)\n";
+      DumpNativeStack(os, GetTid(), nullptr, "  native: ", nullptr);
       return;
     }
     Thread* self = Thread::Current();
@@ -602,9 +603,12 @@
     if (is_native_bridge_loaded_) {
       PreInitializeNativeBridge(".");
     }
+    NativeBridgeAction action = force_native_bridge_
+        ? NativeBridgeAction::kInitialize
+        : NativeBridgeAction::kUnload;
     InitNonZygoteOrPostFork(self->GetJniEnv(),
                             /* is_system_server */ false,
-                            NativeBridgeAction::kInitialize,
+                            action,
                             GetInstructionSetString(kRuntimeISA));
   }
 
@@ -914,6 +918,7 @@
   is_explicit_gc_disabled_ = runtime_options.Exists(Opt::DisableExplicitGC);
   dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::Dex2Oat);
   image_dex2oat_enabled_ = runtime_options.GetOrDefault(Opt::ImageDex2Oat);
+  dump_native_stack_on_sig_quit_ = runtime_options.GetOrDefault(Opt::DumpNativeStackOnSigQuit);
 
   vfprintf_ = runtime_options.GetOrDefault(Opt::HookVfprintf);
   exit_ = runtime_options.GetOrDefault(Opt::HookExit);
@@ -939,6 +944,7 @@
   allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
 
   no_sig_chain_ = runtime_options.Exists(Opt::NoSigChain);
+  force_native_bridge_ = runtime_options.Exists(Opt::ForceNativeBridge);
 
   Split(runtime_options.GetOrDefault(Opt::CpuAbiList), ',', &cpu_abilist_);
 
@@ -1883,7 +1889,8 @@
   if (jit_.get() != nullptr) {
     compiler_callbacks_ = jit_->GetCompilerCallbacks();
     jit_->CreateInstrumentationCache(jit_options_->GetCompileThreshold(),
-                                     jit_options_->GetWarmupThreshold());
+                                     jit_options_->GetWarmupThreshold(),
+                                     jit_options_->GetOsrThreshold());
     jit_->CreateThreadPool();
 
     // Notify native debugger about the classes already loaded before the creation of the jit.
@@ -1914,7 +1921,8 @@
 }
 
 bool Runtime::IsVerificationEnabled() const {
-  return verify_ == verifier::VerifyMode::kEnable;
+  return verify_ == verifier::VerifyMode::kEnable ||
+      verify_ == verifier::VerifyMode::kSoftFail;
 }
 
 bool Runtime::IsVerificationSoftFail() const {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index c8c2ee5..1956bae 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -603,6 +603,10 @@
     safe_mode_ = mode;
   }
 
+  bool GetDumpNativeStackOnSigQuit() const {
+    return dump_native_stack_on_sig_quit_;
+  }
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -774,6 +778,9 @@
   // building a statically link version of dex2oat.
   bool no_sig_chain_;
 
+  // Force the use of native bridge even if the app ISA matches the runtime ISA.
+  bool force_native_bridge_;
+
   // 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,
@@ -810,6 +817,9 @@
   // Whether the application should run in safe mode, that is, interpreter only.
   bool safe_mode_;
 
+  // Whether threads should dump their native stack on SIGQUIT.
+  bool dump_native_stack_on_sig_quit_;
+
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
 std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs);
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 122dcb1..8237b06 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -114,6 +114,9 @@
       switch (signal_code) {
         case SEGV_MAPERR: return "SEGV_MAPERR";
         case SEGV_ACCERR: return "SEGV_ACCERR";
+#if defined(SEGV_BNDERR)
+        case SEGV_BNDERR: return "SEGV_BNDERR";
+#endif
       }
       break;
     case SIGTRAP:
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 308f3ba..838d1a9 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -67,6 +67,7 @@
 RUNTIME_OPTIONS_KEY (bool,                UseTLAB,                        (kUseTlab || kUseReadBarrier))
 RUNTIME_OPTIONS_KEY (bool,                EnableHSpaceCompactForOOM,      true)
 RUNTIME_OPTIONS_KEY (bool,                UseJIT,                         false)
+RUNTIME_OPTIONS_KEY (bool,                DumpNativeStackOnSigQuit,       true)
 RUNTIME_OPTIONS_KEY (unsigned int,        JITCompileThreshold,            jit::Jit::kDefaultCompileThreshold)
 RUNTIME_OPTIONS_KEY (unsigned int,        JITWarmupThreshold,             jit::Jit::kDefaultWarmupThreshold)
 RUNTIME_OPTIONS_KEY (MemoryKiB,           JITCodeCacheInitialCapacity,    jit::JitCodeCache::kInitialCapacity)
@@ -92,6 +93,7 @@
 
 RUNTIME_OPTIONS_KEY (Unit,                DisableExplicitGC)
 RUNTIME_OPTIONS_KEY (Unit,                NoSigChain)
+RUNTIME_OPTIONS_KEY (Unit,                ForceNativeBridge)
 RUNTIME_OPTIONS_KEY (LogVerbosity,        Verbose)
 RUNTIME_OPTIONS_KEY (unsigned int,        LockProfThreshold)
 RUNTIME_OPTIONS_KEY (std::string,         StackTraceFile)
diff --git a/runtime/stack_map.h b/runtime/stack_map.h
index 84185ce..97eb805 100644
--- a/runtime/stack_map.h
+++ b/runtime/stack_map.h
@@ -1195,6 +1195,35 @@
     return StackMap();
   }
 
+  StackMap GetOsrStackMapForDexPc(uint32_t dex_pc, const StackMapEncoding& encoding) const {
+    size_t e = GetNumberOfStackMaps();
+    if (e == 0) {
+      // There cannot be OSR stack map if there is no stack map.
+      return StackMap();
+    }
+    // Walk over all stack maps. If two consecutive stack maps are identical, then we
+    // have found a stack map suitable for OSR.
+    for (size_t i = 0; i < e - 1; ++i) {
+      StackMap stack_map = GetStackMapAt(i, encoding);
+      if (stack_map.GetDexPc(encoding) == dex_pc) {
+        StackMap other = GetStackMapAt(i + 1, encoding);
+        if (other.GetDexPc(encoding) == dex_pc &&
+            other.GetNativePcOffset(encoding) == stack_map.GetNativePcOffset(encoding)) {
+          DCHECK_EQ(other.GetDexRegisterMapOffset(encoding),
+                    stack_map.GetDexRegisterMapOffset(encoding));
+          DCHECK(!stack_map.HasInlineInfo(encoding));
+          if (i < e - 2) {
+            // Make sure there are not three identical stack maps following each other.
+            DCHECK_NE(stack_map.GetNativePcOffset(encoding),
+                      GetStackMapAt(i + 2, encoding).GetNativePcOffset(encoding));
+          }
+          return stack_map;
+        }
+      }
+    }
+    return StackMap();
+  }
+
   StackMap GetStackMapForNativePcOffset(uint32_t native_pc_offset,
                                         const StackMapEncoding& encoding) const {
     // TODO: Safepoint stack maps are sorted by native_pc_offset but catch stack
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 2abcd67..2ee1605 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -936,9 +936,9 @@
      << "]";
 }
 
-void Thread::Dump(std::ostream& os, BacktraceMap* backtrace_map) const {
+void Thread::Dump(std::ostream& os, bool dump_native_stack, BacktraceMap* backtrace_map) const {
   DumpState(os);
-  DumpStack(os, backtrace_map);
+  DumpStack(os, dump_native_stack, backtrace_map);
 }
 
 mirror::String* Thread::GetThreadName(const ScopedObjectAccessAlreadyRunnable& soa) const {
@@ -1497,7 +1497,9 @@
   }
 }
 
-void Thread::DumpStack(std::ostream& os, BacktraceMap* backtrace_map) const {
+void Thread::DumpStack(std::ostream& os,
+                       bool dump_native_stack,
+                       BacktraceMap* backtrace_map) const {
   // TODO: we call this code when dying but may not have suspended the thread ourself. The
   //       IsSuspended check is therefore racy with the use for dumping (normally we inhibit
   //       the race with the thread_suspend_count_lock_).
@@ -1510,7 +1512,7 @@
   }
   if (safe_to_dump) {
     // If we're currently in native code, dump that stack before dumping the managed stack.
-    if (dump_for_abort || ShouldShowNativeStack(this)) {
+    if (dump_native_stack && (dump_for_abort || ShouldShowNativeStack(this))) {
       DumpKernelStack(os, GetTid(), "  kernel: ", false);
       ArtMethod* method = GetCurrentMethod(nullptr, !dump_for_abort);
       DumpNativeStack(os, GetTid(), backtrace_map, "  native: ", method);
@@ -1599,7 +1601,7 @@
   tls32_.state_and_flags.as_struct.state = kNative;
   memset(&tlsPtr_.held_mutexes[0], 0, sizeof(tlsPtr_.held_mutexes));
   std::fill(tlsPtr_.rosalloc_runs,
-            tlsPtr_.rosalloc_runs + kNumRosAllocThreadLocalSizeBrackets,
+            tlsPtr_.rosalloc_runs + kNumRosAllocThreadLocalSizeBracketsInThread,
             gc::allocator::RosAlloc::GetDedicatedFullRun());
   for (uint32_t i = 0; i < kMaxCheckpoints; ++i) {
     tlsPtr_.checkpoint_functions[i] = nullptr;
@@ -3012,4 +3014,25 @@
   return count;
 }
 
+
+void Thread::DeoptimizeWithDeoptimizationException(JValue* result) {
+  DCHECK_EQ(GetException(), Thread::GetDeoptimizationException());
+  ClearException();
+  ShadowFrame* shadow_frame =
+      PopStackedShadowFrame(StackedShadowFrameType::kDeoptimizationShadowFrame);
+  mirror::Throwable* pending_exception = nullptr;
+  bool from_code = false;
+  PopDeoptimizationContext(result, &pending_exception, &from_code);
+  CHECK(!from_code) << "Deoptimizing from code should be done with single frame deoptimization";
+  SetTopOfStack(nullptr);
+  SetTopOfShadowStack(shadow_frame);
+
+  // Restore the exception that was pending before deoptimization then interpret the
+  // deoptimized frames.
+  if (pending_exception != nullptr) {
+    SetException(pending_exception);
+  }
+  interpreter::EnterInterpreterFromDeoptimize(this, shadow_frame, from_code, result);
+}
+
 }  // namespace art
diff --git a/runtime/thread.h b/runtime/thread.h
index d7887ca..2726e91 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -113,7 +113,8 @@
   kSingleFrameDeoptimizationShadowFrame
 };
 
-static constexpr size_t kNumRosAllocThreadLocalSizeBrackets = 34;
+// This should match RosAlloc::kNumThreadLocalSizeBrackets.
+static constexpr size_t kNumRosAllocThreadLocalSizeBracketsInThread = 16;
 
 // Thread's stack layout for implicit stack overflow checks:
 //
@@ -186,7 +187,9 @@
   void ShortDump(std::ostream& os) const;
 
   // Dumps the detailed thread state and the thread stack (used for SIGQUIT).
-  void Dump(std::ostream& os, BacktraceMap* backtrace_map = nullptr) const
+  void Dump(std::ostream& os,
+            bool dump_native_stack = true,
+            BacktraceMap* backtrace_map = nullptr) const
       REQUIRES(!Locks::thread_suspend_count_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
@@ -552,6 +555,9 @@
         OFFSETOF_MEMBER(tls_32bit_sized_values, is_gc_marking));
   }
 
+  // Deoptimize the Java stack.
+  void DeoptimizeWithDeoptimizationException(JValue* result) SHARED_REQUIRES(Locks::mutator_lock_);
+
  private:
   template<size_t pointer_size>
   static ThreadOffset<pointer_size> ThreadOffsetFromTlsPtr(size_t tls_ptr_offset) {
@@ -1107,7 +1113,9 @@
   void VerifyStackImpl() SHARED_REQUIRES(Locks::mutator_lock_);
 
   void DumpState(std::ostream& os) const SHARED_REQUIRES(Locks::mutator_lock_);
-  void DumpStack(std::ostream& os, BacktraceMap* backtrace_map = nullptr) const
+  void DumpStack(std::ostream& os,
+                 bool dump_native_stack = true,
+                 BacktraceMap* backtrace_map = nullptr) const
       REQUIRES(!Locks::thread_suspend_count_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
@@ -1421,7 +1429,7 @@
     void* mterp_alt_ibase;
 
     // There are RosAlloc::kNumThreadLocalSizeBrackets thread-local size brackets per thread.
-    void* rosalloc_runs[kNumRosAllocThreadLocalSizeBrackets];
+    void* rosalloc_runs[kNumRosAllocThreadLocalSizeBracketsInThread];
 
     // Thread-local allocation stack data/routines.
     StackReference<mirror::Object>* thread_local_alloc_stack_top;
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index c8714a6..49d54fd 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -140,7 +140,7 @@
       suspend_all_historam_.PrintConfidenceIntervals(os, 0.99, data);  // Dump time to suspend.
     }
   }
-  Dump(os);
+  Dump(os, Runtime::Current()->GetDumpNativeStackOnSigQuit());
   DumpUnattachedThreads(os);
 }
 
@@ -189,8 +189,11 @@
 // A closure used by Thread::Dump.
 class DumpCheckpoint FINAL : public Closure {
  public:
-  explicit DumpCheckpoint(std::ostream* os)
-      : os_(os), barrier_(0), backtrace_map_(BacktraceMap::Create(getpid())) {}
+  DumpCheckpoint(std::ostream* os, bool dump_native_stack)
+      : os_(os),
+        barrier_(0),
+        backtrace_map_(dump_native_stack ? BacktraceMap::Create(getpid()) : nullptr),
+        dump_native_stack_(dump_native_stack) {}
 
   void Run(Thread* thread) OVERRIDE {
     // Note thread and self may not be equal if thread was already suspended at the point of the
@@ -199,7 +202,7 @@
     std::ostringstream local_os;
     {
       ScopedObjectAccess soa(self);
-      thread->Dump(local_os, backtrace_map_.get());
+      thread->Dump(local_os, dump_native_stack_, backtrace_map_.get());
     }
     local_os << "\n";
     {
@@ -228,14 +231,16 @@
   Barrier barrier_;
   // A backtrace map, so that all threads use a shared info and don't reacquire/parse separately.
   std::unique_ptr<BacktraceMap> backtrace_map_;
+  // Whether we should dump the native stack.
+  const bool dump_native_stack_;
 };
 
-void ThreadList::Dump(std::ostream& os) {
+void ThreadList::Dump(std::ostream& os, bool dump_native_stack) {
   {
     MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
     os << "DALVIK THREADS (" << list_.size() << "):\n";
   }
-  DumpCheckpoint checkpoint(&os);
+  DumpCheckpoint checkpoint(&os, dump_native_stack);
   size_t threads_running_checkpoint = RunCheckpoint(&checkpoint);
   if (threads_running_checkpoint != 0) {
     checkpoint.WaitForThreadsToRunThroughCheckpoint(threads_running_checkpoint);
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 2e73f6a..363cab8 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -49,7 +49,7 @@
   void DumpForSigQuit(std::ostream& os)
       REQUIRES(!Locks::thread_list_lock_, !Locks::mutator_lock_);
   // For thread suspend timeout dumps.
-  void Dump(std::ostream& os)
+  void Dump(std::ostream& os, bool dump_native_stack = true)
       REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_);
   pid_t GetLockOwner();  // For SignalCatcher.
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 56154c6..1d31408 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -58,6 +58,10 @@
 // On VLOG(verifier), should we dump the whole state when we run into a hard failure?
 static constexpr bool kDumpRegLinesOnHardFailureIfVLOG = true;
 
+// We print a warning blurb about "dx --no-optimize" when we find monitor-locking issues. Make
+// sure we only print this once.
+static bool gPrintedDxMonitorText = false;
+
 PcToRegisterLineTable::PcToRegisterLineTable(ScopedArenaAllocator& arena)
     : register_lines_(arena.Adapter(kArenaAllocVerifier)) {}
 
@@ -166,23 +170,38 @@
   return kDirect ? it->HasNextDirectMethod() : it->HasNextVirtualMethod();
 }
 
+static MethodVerifier::FailureKind FailureKindMax(MethodVerifier::FailureKind fk1,
+                                                  MethodVerifier::FailureKind fk2) {
+  static_assert(MethodVerifier::FailureKind::kNoFailure <
+                    MethodVerifier::FailureKind::kSoftFailure
+                && MethodVerifier::FailureKind::kSoftFailure <
+                       MethodVerifier::FailureKind::kHardFailure,
+                "Unexpected FailureKind order");
+  return std::max(fk1, fk2);
+}
+
+void MethodVerifier::FailureData::Merge(const MethodVerifier::FailureData& fd) {
+  kind = FailureKindMax(kind, fd.kind);
+  types |= fd.types;
+}
+
 template <bool kDirect>
-void MethodVerifier::VerifyMethods(Thread* self,
-                                   ClassLinker* linker,
-                                   const DexFile* dex_file,
-                                   const DexFile::ClassDef* class_def,
-                                   ClassDataItemIterator* it,
-                                   Handle<mirror::DexCache> dex_cache,
-                                   Handle<mirror::ClassLoader> class_loader,
-                                   CompilerCallbacks* callbacks,
-                                   bool allow_soft_failures,
-                                   bool log_hard_failures,
-                                   bool need_precise_constants,
-                                   bool* hard_fail,
-                                   size_t* error_count,
-                                   std::string* error_string) {
+MethodVerifier::FailureData MethodVerifier::VerifyMethods(Thread* self,
+                                                          ClassLinker* linker,
+                                                          const DexFile* dex_file,
+                                                          const DexFile::ClassDef* class_def,
+                                                          ClassDataItemIterator* it,
+                                                          Handle<mirror::DexCache> dex_cache,
+                                                          Handle<mirror::ClassLoader> class_loader,
+                                                          CompilerCallbacks* callbacks,
+                                                          bool allow_soft_failures,
+                                                          bool log_hard_failures,
+                                                          bool need_precise_constants,
+                                                          std::string* error_string) {
   DCHECK(it != nullptr);
 
+  MethodVerifier::FailureData failure_data;
+
   int64_t previous_method_idx = -1;
   while (HasNextMethod<kDirect>(it)) {
     self->AllowThreadSuspension();
@@ -206,7 +225,7 @@
     }
     StackHandleScope<1> hs(self);
     std::string hard_failure_msg;
-    MethodVerifier::FailureKind result = VerifyMethod(self,
+    MethodVerifier::FailureData result = VerifyMethod(self,
                                                       method_idx,
                                                       dex_file,
                                                       dex_cache,
@@ -220,24 +239,24 @@
                                                       log_hard_failures,
                                                       need_precise_constants,
                                                       &hard_failure_msg);
-    if (result != kNoFailure) {
-      if (result == kHardFailure) {
-        if (*error_count > 0) {
-          *error_string += "\n";
-        }
-        if (!*hard_fail) {
-          *error_string += "Verifier rejected class ";
-          *error_string += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def));
-          *error_string += ":";
-        }
-        *error_string += " ";
-        *error_string += hard_failure_msg;
-        *hard_fail = true;
+    if (result.kind == kHardFailure) {
+      if (failure_data.kind == kHardFailure) {
+        // If we logged an error before, we need a newline.
+        *error_string += "\n";
+      } else {
+        // If we didn't log a hard failure before, print the header of the message.
+        *error_string += "Verifier rejected class ";
+        *error_string += PrettyDescriptor(dex_file->GetClassDescriptor(*class_def));
+        *error_string += ":";
       }
-      *error_count = *error_count + 1;
+      *error_string += " ";
+      *error_string += hard_failure_msg;
     }
+    failure_data.Merge(result);
     it->Next();
   }
+
+  return failure_data;
 }
 
 MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
@@ -268,44 +287,53 @@
   while (it.HasNextStaticField() || it.HasNextInstanceField()) {
     it.Next();
   }
-  size_t error_count = 0;
-  bool hard_fail = false;
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   // Direct methods.
-  VerifyMethods<true>(self,
-                      linker,
-                      dex_file,
-                      class_def,
-                      &it,
-                      dex_cache,
-                      class_loader,
-                      callbacks,
-                      allow_soft_failures,
-                      log_hard_failures,
-                      false /* need precise constants */,
-                      &hard_fail,
-                      &error_count,
-                      error);
+  MethodVerifier::FailureData data1 = VerifyMethods<true>(self,
+                                                          linker,
+                                                          dex_file,
+                                                          class_def,
+                                                          &it,
+                                                          dex_cache,
+                                                          class_loader,
+                                                          callbacks,
+                                                          allow_soft_failures,
+                                                          log_hard_failures,
+                                                          false /* need precise constants */,
+                                                          error);
   // Virtual methods.
-  VerifyMethods<false>(self,
-                      linker,
-                      dex_file,
-                      class_def,
-                      &it,
-                      dex_cache,
-                      class_loader,
-                      callbacks,
-                      allow_soft_failures,
-                      log_hard_failures,
-                      false /* need precise constants */,
-                      &hard_fail,
-                      &error_count,
-                      error);
+  MethodVerifier::FailureData data2 = VerifyMethods<false>(self,
+                                                           linker,
+                                                           dex_file,
+                                                           class_def,
+                                                           &it,
+                                                           dex_cache,
+                                                           class_loader,
+                                                           callbacks,
+                                                           allow_soft_failures,
+                                                           log_hard_failures,
+                                                           false /* need precise constants */,
+                                                           error);
 
-  if (error_count == 0) {
+  data1.Merge(data2);
+
+  if (data1.kind == kNoFailure) {
     return kNoFailure;
   } else {
-    return hard_fail ? kHardFailure : kSoftFailure;
+    if ((data1.types & VERIFY_ERROR_LOCKING) != 0) {
+      // Print a warning about expected slow-down. Use a string temporary to print one contiguous
+      // warning.
+      std::string tmp =
+          StringPrintf("Class %s failed lock verification and will run slower.",
+                       PrettyDescriptor(dex_file->GetClassDescriptor(*class_def)).c_str());
+      if (!gPrintedDxMonitorText) {
+        tmp = tmp + "\nCommon causes for lock verification issues are non-optimized dex code\n"
+                    "and incorrect proguard optimizations.";
+        gPrintedDxMonitorText = true;
+      }
+      LOG(WARNING) << tmp;
+    }
+    return data1.kind;
   }
 }
 
@@ -320,7 +348,7 @@
   return registers_size * insns_size > 4*1024*1024;
 }
 
-MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self,
+MethodVerifier::FailureData MethodVerifier::VerifyMethod(Thread* self,
                                                          uint32_t method_idx,
                                                          const DexFile* dex_file,
                                                          Handle<mirror::DexCache> dex_cache,
@@ -334,7 +362,7 @@
                                                          bool log_hard_failures,
                                                          bool need_precise_constants,
                                                          std::string* hard_failure_msg) {
-  MethodVerifier::FailureKind result = kNoFailure;
+  MethodVerifier::FailureData result;
   uint64_t start_ns = kTimeVerifyMethod ? NanoTime() : 0;
 
   MethodVerifier verifier(self, dex_file, dex_cache, class_loader, class_def, code_item,
@@ -355,7 +383,7 @@
         verifier.DumpFailures(VLOG_STREAM(verifier) << "Soft verification failures in "
                                                     << PrettyMethod(method_idx, *dex_file) << "\n");
       }
-      result = kSoftFailure;
+      result.kind = kSoftFailure;
     }
   } else {
     // Bad method data.
@@ -364,7 +392,7 @@
     if (UNLIKELY(verifier.have_pending_experimental_failure_)) {
       // Failed due to being forced into interpreter. This is ok because
       // we just want to skip verification.
-      result = kSoftFailure;
+      result.kind = kSoftFailure;
     } else {
       CHECK(verifier.have_pending_hard_failure_);
       if (VLOG_IS_ON(verifier) || log_hard_failures) {
@@ -376,7 +404,7 @@
         *hard_failure_msg =
             verifier.failure_messages_[verifier.failure_messages_.size() - 1]->str();
       }
-      result = kHardFailure;
+      result.kind = kHardFailure;
 
       if (callbacks != nullptr) {
         // Let the interested party know that we failed the class.
@@ -397,6 +425,7 @@
                    << (IsLargeMethod(code_item) ? " (large method)" : "");
     }
   }
+  result.types = verifier.encountered_failure_types_;
   return result;
 }
 
@@ -2382,6 +2411,8 @@
       if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(res_type)) {
         if (res_type.IsUninitializedTypes()) {
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown exception not initialized";
+        } else if (!res_type.IsReferenceTypes()) {
+          Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "thrown value of non-reference type " << res_type;
         } else {
           Fail(res_type.IsUnresolvedTypes() ? VERIFY_ERROR_NO_CLASS : VERIFY_ERROR_BAD_CLASS_SOFT)
                 << "thrown class " << res_type << " not instanceof Throwable";
@@ -4495,6 +4526,19 @@
     if (UNLIKELY(have_pending_hard_failure_)) {
       return;
     }
+    if (should_adjust) {
+      if (field == nullptr) {
+        Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Might be accessing a superclass instance field prior "
+                                          << "to the superclass being initialized in "
+                                          << PrettyMethod(dex_method_idx_, *dex_file_);
+      } else if (field->GetDeclaringClass() != GetDeclaringClass().GetClass()) {
+        Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "cannot access superclass instance field "
+                                          << PrettyField(field) << " of a not fully initialized "
+                                          << "object within the context of "
+                                          << PrettyMethod(dex_method_idx_, *dex_file_);
+        return;
+      }
+    }
   }
   const RegType* field_type = nullptr;
   if (field != nullptr) {
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 613d5af..c7d1e6b 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -25,6 +25,7 @@
 #include "base/macros.h"
 #include "base/scoped_arena_containers.h"
 #include "base/stl_util.h"
+#include "base/value_object.h"
 #include "dex_file.h"
 #include "handle.h"
 #include "instruction_flags.h"
@@ -344,23 +345,31 @@
   // Adds the given string to the end of the last failure message.
   void AppendToLastFailMessage(std::string);
 
+  // Verification result for method(s). Includes a (maximum) failure kind, and (the union of)
+  // all failure types.
+  struct FailureData : ValueObject {
+    FailureKind kind = kNoFailure;
+    uint32_t types = 0U;
+
+    // Merge src into this. Uses the most severe failure kind, and the union of types.
+    void Merge(const FailureData& src);
+  };
+
   // Verify all direct or virtual methods of a class. The method assumes that the iterator is
   // positioned correctly, and the iterator will be updated.
   template <bool kDirect>
-  static void VerifyMethods(Thread* self,
-                            ClassLinker* linker,
-                            const DexFile* dex_file,
-                            const DexFile::ClassDef* class_def,
-                            ClassDataItemIterator* it,
-                            Handle<mirror::DexCache> dex_cache,
-                            Handle<mirror::ClassLoader> class_loader,
-                            CompilerCallbacks* callbacks,
-                            bool allow_soft_failures,
-                            bool log_hard_failures,
-                            bool need_precise_constants,
-                            bool* hard_fail,
-                            size_t* error_count,
-                            std::string* error_string)
+  static FailureData VerifyMethods(Thread* self,
+                                   ClassLinker* linker,
+                                   const DexFile* dex_file,
+                                   const DexFile::ClassDef* class_def,
+                                   ClassDataItemIterator* it,
+                                   Handle<mirror::DexCache> dex_cache,
+                                   Handle<mirror::ClassLoader> class_loader,
+                                   CompilerCallbacks* callbacks,
+                                   bool allow_soft_failures,
+                                   bool log_hard_failures,
+                                   bool need_precise_constants,
+                                   std::string* error_string)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
   /*
@@ -374,7 +383,7 @@
    *  (3) Iterate through the method, checking type safety and looking
    *      for code flow problems.
    */
-  static FailureKind VerifyMethod(Thread* self, uint32_t method_idx,
+  static FailureData VerifyMethod(Thread* self, uint32_t method_idx,
                                   const DexFile* dex_file,
                                   Handle<mirror::DexCache> dex_cache,
                                   Handle<mirror::ClassLoader> class_loader,
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 08f85b3..330c06a 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -178,9 +178,9 @@
   if (MonitorStackDepth() != 0) {
     verifier->Fail(VERIFY_ERROR_LOCKING);
     if (kDumpLockFailures) {
-      LOG(WARNING) << "expected empty monitor stack in "
-                   << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                   *verifier->GetMethodReference().dex_file);
+      VLOG(verifier) << "expected empty monitor stack in "
+                     << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                     *verifier->GetMethodReference().dex_file);
     }
   }
 }
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 37343b5..b7cde99 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -348,9 +348,9 @@
   } else if (monitors_.size() >= 32) {
     verifier->Fail(VERIFY_ERROR_LOCKING);
     if (kDumpLockFailures) {
-      LOG(WARNING) << "monitor-enter stack overflow while verifying "
-                   << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                   *verifier->GetMethodReference().dex_file);
+      VLOG(verifier) << "monitor-enter stack overflow while verifying "
+                     << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                     *verifier->GetMethodReference().dex_file);
     }
   } else {
     if (SetRegToLockDepth(reg_idx, monitors_.size())) {
@@ -364,9 +364,9 @@
     } else {
       verifier->Fail(VERIFY_ERROR_LOCKING);
       if (kDumpLockFailures) {
-        LOG(WARNING) << "unexpected monitor-enter on register v" <<  reg_idx << " in "
-                     << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                     *verifier->GetMethodReference().dex_file);
+        VLOG(verifier) << "unexpected monitor-enter on register v" <<  reg_idx << " in "
+                       << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                       *verifier->GetMethodReference().dex_file);
       }
     }
   }
@@ -379,9 +379,9 @@
   } else if (monitors_.empty()) {
     verifier->Fail(VERIFY_ERROR_LOCKING);
     if (kDumpLockFailures) {
-      LOG(WARNING) << "monitor-exit stack underflow while verifying "
-                   << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                   *verifier->GetMethodReference().dex_file);
+      VLOG(verifier) << "monitor-exit stack underflow while verifying "
+                     << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                     *verifier->GetMethodReference().dex_file);
     }
   } else {
     monitors_.pop_back();
@@ -400,9 +400,9 @@
     if (!success) {
       verifier->Fail(VERIFY_ERROR_LOCKING);
       if (kDumpLockFailures) {
-        LOG(WARNING) << "monitor-exit not unlocking the top of the monitor stack while verifying "
-                     << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                     *verifier->GetMethodReference().dex_file);
+        VLOG(verifier) << "monitor-exit not unlocking the top of the monitor stack while verifying "
+                       << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                       *verifier->GetMethodReference().dex_file);
       }
     } else {
       // Record the register was unlocked. This clears all aliases, thus it will also clear the
@@ -453,10 +453,10 @@
     if (monitors_.size() != incoming_line->monitors_.size()) {
       verifier->Fail(VERIFY_ERROR_LOCKING);
       if (kDumpLockFailures) {
-        LOG(WARNING) << "mismatched stack depths (depth=" << MonitorStackDepth()
-                     << ", incoming depth=" << incoming_line->MonitorStackDepth() << ") in "
-                     << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                     *verifier->GetMethodReference().dex_file);
+        VLOG(verifier) << "mismatched stack depths (depth=" << MonitorStackDepth()
+                       << ", incoming depth=" << incoming_line->MonitorStackDepth() << ") in "
+                       << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                       *verifier->GetMethodReference().dex_file);
       }
     } else if (reg_to_lock_depths_ != incoming_line->reg_to_lock_depths_) {
       for (uint32_t idx = 0; idx < num_regs_; idx++) {
@@ -488,10 +488,10 @@
                                        reg_to_lock_depths_)) {
             verifier->Fail(VERIFY_ERROR_LOCKING);
             if (kDumpLockFailures) {
-              LOG(WARNING) << "mismatched stack depths for register v" << idx
-                           << ": " << depths  << " != " << incoming_depths << " in "
-                           << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                           *verifier->GetMethodReference().dex_file);
+              VLOG(verifier) << "mismatched stack depths for register v" << idx
+                             << ": " << depths  << " != " << incoming_depths << " in "
+                             << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                             *verifier->GetMethodReference().dex_file);
             }
             break;
           }
@@ -530,11 +530,11 @@
               // No aliases for both current and incoming, we'll lose information.
               verifier->Fail(VERIFY_ERROR_LOCKING);
               if (kDumpLockFailures) {
-                LOG(WARNING) << "mismatched lock levels for register v" << idx << ": "
-                    << std::hex << locked_levels << std::dec  << " != "
-                    << std::hex << incoming_locked_levels << std::dec << " in "
-                    << PrettyMethod(verifier->GetMethodReference().dex_method_index,
-                                    *verifier->GetMethodReference().dex_file);
+                VLOG(verifier) << "mismatched lock levels for register v" << idx << ": "
+                               << std::hex << locked_levels << std::dec  << " != "
+                               << std::hex << incoming_locked_levels << std::dec << " in "
+                               << PrettyMethod(verifier->GetMethodReference().dex_method_index,
+                                               *verifier->GetMethodReference().dex_file);
               }
               break;
             }
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index faa2983..56e8784 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -23,8 +23,8 @@
 ${JAVAC} -d classes `find src2 -name '*.java'`
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JILL} classes --output classes.jack
-  ${JACK} --import classes.jack --output-dex .
+  jar cf classes.jill.jar -C classes .
+  ${JACK} --import classes.jill.jar --output-dex .
 else
   ${DX} -JXmx256m --debug --dex --output=classes.dex classes
   fi
diff --git a/test/005-annotations/build b/test/005-annotations/build
index 057b351..93bee50 100644
--- a/test/005-annotations/build
+++ b/test/005-annotations/build
@@ -29,8 +29,8 @@
 rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class'
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JILL} classes --output classes.jack
-  ${JACK} --import classes.jack --output-dex .
+  jar cf classes.jill.jar -C classes .
+  ${JACK} --import classes.jill.jar --output-dex .
 else
   ${DX} -JXmx256m --debug --dex --output=classes.dex classes
 fi
diff --git a/test/022-interface/build b/test/022-interface/build
index 3f8915c..5cfc7f2 100644
--- a/test/022-interface/build
+++ b/test/022-interface/build
@@ -20,8 +20,8 @@
 # Use classes that are compiled with ecj that exposes an invokeinterface
 # issue when interfaces override methods in Object
 if [ ${USE_JACK} = "true" ]; then
-  ${JILL} classes --output classes.jack
-  ${JACK} --import classes.jack --output-dex .
+  jar cf classes.jill.jar -C classes .
+  ${JACK} --import classes.jill.jar --output-dex .
 else
   ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
 fi
diff --git a/test/048-reflect-v8/expected.txt b/test/048-reflect-v8/expected.txt
index 2d0b4cc..54aede9 100644
--- a/test/048-reflect-v8/expected.txt
+++ b/test/048-reflect-v8/expected.txt
@@ -1,4 +1,104 @@
-Main$DefaultInterface is default = yes
-Main$RegularInterface is default = no
-Main$ImplementsWithDefault is default = yes
-Main$ImplementsWithRegular is default = no
+==============================
+Are These Methods Default:
+==============================
+IsDefaultTest$DefaultInterface is default = yes
+IsDefaultTest$RegularInterface is default = no
+IsDefaultTest$ImplementsWithDefault is default = yes
+IsDefaultTest$ImplementsWithRegular is default = no
+==============================
+Are These Methods found by getDeclaredMethod:
+==============================
+No error thrown for class interface DefaultDeclared$DefaultInterface
+No error thrown for class interface DefaultDeclared$RegularInterface
+NoSuchMethodException thrown for class class DefaultDeclared$ImplementsWithDefault
+No error thrown for class class DefaultDeclared$ImplementsWithDeclared
+No error thrown for class class DefaultDeclared$ImplementsWithRegular
+NoSuchMethodException thrown for class class DefaultDeclared$UnimplementedWithRegular
+==============================
+Class annotations by type:
+==============================
+Annotations by type, defined by class SingleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23)
+Annotations by type, defined by class SingleUser with annotation Calendars: <empty>
+Annotations by type, defined by class User with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)
+Annotations by type, defined by class User with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+Annotations by type, defined by class User2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)
+Annotations by type, defined by class User2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)])
+Annotations by type, defined by class UserComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)
+Annotations by type, defined by class UserComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)])
+Annotations by type, defined by class UserSub with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)
+Annotations by type, defined by class UserSub with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+Annotations by type, defined by class UserSub2 with annotation Calendar: @Calendar(dayOfMonth=sub2, dayOfWeek=unspecified_week, hour=6)
+Annotations by type, defined by class UserSub2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+-----------------------------
+-----------------------------
+==============================
+Class declared annotation:
+==============================
+Declared annotations by class class SingleUser, annotation interface Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23)
+Declared annotations by class class SingleUser, annotation interface Calendars: <null>
+Declared annotations by class class User, annotation interface Calendar: <null>
+Declared annotations by class class User, annotation interface Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+Declared annotations by class class UserComplex, annotation interface Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6)
+Declared annotations by class class UserComplex, annotation interface Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)])
+Declared annotations by class class UserSub, annotation interface Calendar: <null>
+Declared annotations by class class UserSub, annotation interface Calendars: <null>
+Declared annotations by class class UserSub2, annotation interface Calendar: @Calendar(dayOfMonth=sub2, dayOfWeek=unspecified_week, hour=6)
+Declared annotations by class class UserSub2, annotation interface Calendars: <null>
+-----------------------------
+-----------------------------
+==============================
+Declared class annotations by type:
+==============================
+Declared annnotations by type, defined by class SingleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23)
+Declared annnotations by type, defined by class SingleUser with annotation Calendars: <empty>
+Declared annnotations by type, defined by class User with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)
+Declared annnotations by type, defined by class User with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+Declared annnotations by type, defined by class User2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)
+Declared annnotations by type, defined by class User2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)])
+Declared annnotations by type, defined by class UserComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)
+Declared annnotations by type, defined by class UserComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)])
+Declared annnotations by type, defined by class UserSub with annotation Calendar: <empty>
+Declared annnotations by type, defined by class UserSub with annotation Calendars: <empty>
+Declared annnotations by type, defined by class UserSub2 with annotation Calendar: @Calendar(dayOfMonth=sub2, dayOfWeek=unspecified_week, hour=6)
+Declared annnotations by type, defined by class UserSub2 with annotation Calendars: <empty>
+-----------------------------
+-----------------------------
+==============================
+Method annotations by type:
+==============================
+Annotations by type, defined by method singleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23)
+Annotations by type, defined by method singleUser with annotation Calendars: <empty>
+Annotations by type, defined by method user with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)
+Annotations by type, defined by method user with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+Annotations by type, defined by method user2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)
+Annotations by type, defined by method user2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)])
+Annotations by type, defined by method userComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)
+Annotations by type, defined by method userComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)])
+-----------------------------
+-----------------------------
+==============================
+Declared method annotations:
+==============================
+Annotations declared by method singleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23)
+Annotations declared by method singleUser with annotation Calendars: <null>
+Annotations declared by method user with annotation Calendar: <null>
+Annotations declared by method user with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+Annotations declared by method user2 with annotation Calendar: <null>
+Annotations declared by method user2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)])
+Annotations declared by method userComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6)
+Annotations declared by method userComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)])
+-----------------------------
+-----------------------------
+==============================
+Declared method annotations by type:
+==============================
+Annotations by type, defined by method singleUser with annotation Calendar: @Calendar(dayOfMonth=unspecified_month, dayOfWeek=single, hour=23)
+Annotations by type, defined by method singleUser with annotation Calendars: <empty>
+Annotations by type, defined by method user with annotation Calendar: @Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)
+Annotations by type, defined by method user with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=last, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=unspecified_month, dayOfWeek=Fri, hour=23)])
+Annotations by type, defined by method user2 with annotation Calendar: @Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)
+Annotations by type, defined by method user2 with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=z, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=x, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=y, dayOfWeek=unspecified_week, hour=6)])
+Annotations by type, defined by method userComplex with annotation Calendar: @Calendar(dayOfMonth=afirst, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)
+Annotations by type, defined by method userComplex with annotation Calendars: @Calendars(value=[@Calendar(dayOfMonth=zsecond, dayOfWeek=unspecified_week, hour=6), @Calendar(dayOfMonth=athird, dayOfWeek=unspecified_week, hour=23)])
+-----------------------------
+-----------------------------
diff --git a/test/048-reflect-v8/src/AnnotationTest.java b/test/048-reflect-v8/src/AnnotationTest.java
new file mode 100644
index 0000000..75e6845
--- /dev/null
+++ b/test/048-reflect-v8/src/AnnotationTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2016 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.annotation.Annotation;
+import java.lang.reflect.Method;
+
+public class AnnotationTest extends AnnotationTestHelpers {
+  public static void testAnnotationsByType() {
+    System.out.println("==============================");
+    System.out.println("Class annotations by type:");
+    System.out.println("==============================");
+
+    // Print associated annotations:
+    // * A is directly present or repeatably present on an element E;
+    // * No annotation of A is directly/repeatably present on an element
+    //   AND E is a class AND A's type is inheritable, AND A is associated with its superclass.
+    // (Looks through subtypes recursively only if there's 0 result at each level,
+    // and the annotation is @Inheritable).
+    printAnnotationsByType(Calendar.class, SingleUser.class);
+    printAnnotationsByType(Calendars.class, SingleUser.class);
+
+    printAnnotationsByType(Calendar.class, User.class);
+    printAnnotationsByType(Calendars.class, User.class);
+
+    printAnnotationsByType(Calendar.class, User2.class);  // Enforce ordering 'z,x,y'
+    printAnnotationsByType(Calendars.class, User2.class);
+
+    // NOTE:
+    //    Order of outer-most annotations Calendars[C,C],S vs C,Calendars[C,C] is unspecified.
+    //    In particular it's the order of #getDeclaredAnnotations which is completely unmentioned.
+    //    The only requirement for #getAnnotationsByType is to have same ordering as
+    //    #getDeclaredAnnotations.
+    //    (Calendars[] itself has to maintain value() order).
+    printAnnotationsByType(Calendar.class, UserComplex.class);  // Cs(C,C),C collapses into C,C,C.
+    printAnnotationsByType(Calendars.class, UserComplex.class);
+
+    printAnnotationsByType(Calendar.class, UserSub.class);
+    printAnnotationsByType(Calendars.class, UserSub.class);
+
+    printAnnotationsByType(Calendar.class, UserSub2.class);
+    // The directly present "Calendar" annotation masks all the repeatably present
+    // "Calendar" annotations coming from User.
+    printAnnotationsByType(Calendars.class, UserSub2.class);
+    // Edge case: UserSub2 doesn't directly have a Calendars annotation,
+    // so it doesn't mask the "User" Calendars annotation.
+
+    System.out.println("-----------------------------");
+    System.out.println("-----------------------------");
+
+  }
+
+  public static void testDeclaredAnnotation() {
+    System.out.println("==============================");
+    System.out.println("Class declared annotation:");
+    System.out.println("==============================");
+
+    // Print directly present annotations:
+    //
+    // The element E has an annotation_item for it (accessible through an
+    // annotations_directory_item) corresponding to an annotation A,
+    // and A's type_idx must match that on the encoded_annotation (from the annotation_item).
+    // (Does not look through the subtypes recursively)
+    printDeclaredAnnotation(SingleUser.class, Calendar.class);
+    printDeclaredAnnotation(SingleUser.class, Calendars.class);
+
+    printDeclaredAnnotation(User.class, Calendar.class);
+    printDeclaredAnnotation(User.class, Calendars.class);
+
+    printDeclaredAnnotation(UserComplex.class, Calendar.class);
+    printDeclaredAnnotation(UserComplex.class, Calendars.class);
+
+    printDeclaredAnnotation(UserSub.class, Calendar.class);
+    printDeclaredAnnotation(UserSub.class, Calendars.class);
+
+    printDeclaredAnnotation(UserSub2.class, Calendar.class);
+    printDeclaredAnnotation(UserSub2.class, Calendars.class);
+
+    System.out.println("-----------------------------");
+    System.out.println("-----------------------------");
+  }
+
+  public static void testDeclaredAnnotationsByType() {
+    System.out.println("==============================");
+    System.out.println("Declared class annotations by type:");
+    System.out.println("==============================");
+
+    // A is directly present or repeatably present on an element E;
+    // -- (does not do any recursion for classes regardless of @Inherited)
+    printDeclaredAnnotationsByType(Calendar.class, SingleUser.class);
+    printDeclaredAnnotationsByType(Calendars.class, SingleUser.class);
+
+    printDeclaredAnnotationsByType(Calendar.class, User.class);
+    printDeclaredAnnotationsByType(Calendars.class, User.class);
+
+    printDeclaredAnnotationsByType(Calendar.class, User2.class);  // Enforce ordering 'z,x,y'
+    printDeclaredAnnotationsByType(Calendars.class, User2.class);
+
+    printDeclaredAnnotationsByType(Calendar.class, UserComplex.class);
+    printDeclaredAnnotationsByType(Calendars.class, UserComplex.class);
+
+    printDeclaredAnnotationsByType(Calendar.class, UserSub.class);
+    printDeclaredAnnotationsByType(Calendars.class, UserSub.class);
+
+    printDeclaredAnnotationsByType(Calendar.class, UserSub2.class);
+    // The directly present "Calendar" annotation masks all the repeatably present "Calendar"
+    // annotations coming from User.
+    printDeclaredAnnotationsByType(Calendars.class, UserSub2.class);
+    // Edge case: UserSub2 doesn't directly have a Calendars annotation,
+    // so it doesn't mask the "User" Calendars annotation.
+
+    System.out.println("-----------------------------");
+    System.out.println("-----------------------------");
+  }
+
+  // Print the annotation "annotationClass" that is associated with an element denoted by
+  // "annotationUseClass."
+  private static <A extends Annotation> void printAnnotationsByType(Class<A> annotationClass,
+      Class<?> annotationUseClass) {
+    A[] annotationsByType = annotationUseClass.getAnnotationsByType(annotationClass);
+
+    String msg = "Annotations by type, defined by class "
+        + annotationUseClass.getName() + " with annotation " + annotationClass.getName() + ": "
+        + asString(annotationsByType);
+
+
+    System.out.println(msg);
+  }
+
+  private static <A extends Annotation> void printDeclaredAnnotation(Class<?> annotationUseClass,
+      Class<A> annotationDefClass) {
+    A anno = annotationUseClass.getDeclaredAnnotation(annotationDefClass);
+
+    String msg = asString(anno);
+
+    System.out.println("Declared annotations by class " + annotationUseClass
+        + ", annotation " + annotationDefClass + ": " + msg);
+  }
+
+  // Print the annotation "annotationClass" that is directly/indirectly present with an element
+  // denoted by "annotationUseClass."
+  private static <A extends Annotation> void printDeclaredAnnotationsByType(
+      Class<A> annotationClass, Class<?> annotationUseClass) {
+    A[] annotationsByType = annotationUseClass.getDeclaredAnnotationsByType(annotationClass);
+
+    String msg = "Declared annnotations by type, defined by class " + annotationUseClass.getName()
+        + " with annotation " + annotationClass.getName() + ": "
+        + asString(annotationsByType);
+
+    System.out.println(msg);
+  }
+
+  public static void testMethodAnnotationsByType() {
+    System.out.println("==============================");
+    System.out.println("Method annotations by type:");
+    System.out.println("==============================");
+
+    // Print associated annotations:
+    // * A is directly present or repeatably present on an element E;
+    // * No annotation of A is directly/repeatably present on an element AND E is a class
+    //   AND A's type is inheritable, AND A is associated with its superclass.
+    // (Looks through subtypes recursively only if there's 0 result at each level,
+    // and the annotation is @Inheritable).
+    printMethodAnnotationsByType(Calendar.class, "singleUser", AnnotationTestFixture.class);
+    printMethodAnnotationsByType(Calendars.class, "singleUser", AnnotationTestFixture.class);
+
+    printMethodAnnotationsByType(Calendar.class, "user", AnnotationTestFixture.class);
+    printMethodAnnotationsByType(Calendars.class, "user", AnnotationTestFixture.class);
+
+    printMethodAnnotationsByType(Calendar.class, "user2", AnnotationTestFixture.class);
+    printMethodAnnotationsByType(Calendars.class, "user2", AnnotationTestFixture.class);
+
+    printMethodAnnotationsByType(Calendar.class, "userComplex", AnnotationTestFixture.class);
+    printMethodAnnotationsByType(Calendars.class, "userComplex", AnnotationTestFixture.class);
+
+    System.out.println("-----------------------------");
+    System.out.println("-----------------------------");
+  }
+
+  // Print the annotation "annotationClass" that is associated with an element denoted by
+  // "annotationUseClass" method methodName.
+  private static <A extends Annotation> void printMethodAnnotationsByType(Class<A> annotationClass,
+      String methodName, Class<?> annotationUseClass) {
+    Method m = null;
+    try {
+      m = annotationUseClass.getDeclaredMethod(methodName);
+    } catch (Throwable t) {
+      throw new AssertionError(t);
+    }
+    A[] annotationsByType = m.getAnnotationsByType(annotationClass);
+
+    String msg = "Annotations by type, defined by method " + m.getName() + " with annotation " +
+      annotationClass.getName() + ": " +
+      asString(annotationsByType);
+
+    System.out.println(msg);
+  }
+
+  public static void testMethodDeclaredAnnotations() {
+    System.out.println("==============================");
+    System.out.println("Declared method annotations:");
+    System.out.println("==============================");
+
+    printMethodDeclaredAnnotation(Calendar.class, "singleUser", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotation(Calendars.class, "singleUser", AnnotationTestFixture.class);
+
+    printMethodDeclaredAnnotation(Calendar.class, "user", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotation(Calendars.class, "user", AnnotationTestFixture.class);
+
+    printMethodDeclaredAnnotation(Calendar.class, "user2", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotation(Calendars.class, "user2", AnnotationTestFixture.class);
+
+    printMethodDeclaredAnnotation(Calendar.class, "userComplex", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotation(Calendars.class, "userComplex", AnnotationTestFixture.class);
+
+    System.out.println("-----------------------------");
+    System.out.println("-----------------------------");
+  }
+
+  // Print the annotation "annotationClass" that is associated with an element denoted by
+  // methodName in annotationUseClass.
+  private static <A extends Annotation> void printMethodDeclaredAnnotation(Class<A> annotationClass,
+      String methodName, Class<?> annotationUseClass) {
+    Method m = null;
+    try {
+      m = annotationUseClass.getDeclaredMethod(methodName);
+    } catch (Throwable t) {
+      throw new AssertionError(t);
+    }
+    Annotation annotationsByType = m.getDeclaredAnnotation(annotationClass);
+
+    String msg = "Annotations declared by method " + m.getName() + " with annotation "
+        + annotationClass.getName() + ": "
+        + asString(annotationsByType);
+
+    System.out.println(msg);
+  }
+
+  public static void testMethodDeclaredAnnotationsByType() {
+    System.out.println("==============================");
+    System.out.println("Declared method annotations by type:");
+    System.out.println("==============================");
+
+    printMethodDeclaredAnnotationByType(Calendar.class, "singleUser", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotationByType(Calendars.class, "singleUser", AnnotationTestFixture.class);
+
+    printMethodDeclaredAnnotationByType(Calendar.class, "user", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotationByType(Calendars.class, "user", AnnotationTestFixture.class);
+
+    printMethodDeclaredAnnotationByType(Calendar.class, "user2", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotationByType(Calendars.class, "user2", AnnotationTestFixture.class);
+
+    printMethodDeclaredAnnotationByType(Calendar.class, "userComplex", AnnotationTestFixture.class);
+    printMethodDeclaredAnnotationByType(Calendars.class, "userComplex",
+        AnnotationTestFixture.class);
+
+    System.out.println("-----------------------------");
+    System.out.println("-----------------------------");
+  }
+
+  // Print the annotation "annotationClass" that is associated with an element denoted by
+  // methodName in annotationUseClass.
+  private static <A extends Annotation> void printMethodDeclaredAnnotationByType(
+      Class<A> annotationClass, String methodName, Class<?> annotationUseClass) {
+    Method m = null;
+    try {
+      m = annotationUseClass.getDeclaredMethod(methodName);
+    } catch (Throwable t) {
+      throw new AssertionError(t);
+    }
+    A[] annotationsByType = m.getDeclaredAnnotationsByType(annotationClass);
+
+    String msg = "Annotations by type, defined by method " + m.getName() + " with annotation "
+        + annotationClass.getName() + ": "
+        + asString(annotationsByType);
+
+    System.out.println(msg);
+  }
+}
diff --git a/test/048-reflect-v8/src/AnnotationTestFixture.java b/test/048-reflect-v8/src/AnnotationTestFixture.java
new file mode 100644
index 0000000..248dfac
--- /dev/null
+++ b/test/048-reflect-v8/src/AnnotationTestFixture.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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 AnnotationTestFixture {
+
+  @Calendar(dayOfWeek="single", hour=23)
+  public static void singleUser() {
+
+  }
+  @Calendars ({
+    @Calendar(dayOfMonth="last"),
+    @Calendar(dayOfWeek="Fri", hour=23)
+  })
+  public static void user() {
+
+  }
+
+  @Calendars ({
+    @Calendar(dayOfMonth="z"),
+    @Calendar(dayOfMonth="x"),
+    @Calendar(dayOfMonth="y")
+  })
+  public static void user2() {
+
+  }
+
+  @Calendar(dayOfMonth="afirst")
+  @Calendars ({
+    @Calendar(dayOfMonth="zsecond"),
+    @Calendar(dayOfMonth="athird", hour=23)
+  })
+  public static void userComplex() {
+
+  }
+}
diff --git a/test/048-reflect-v8/src/AnnotationTestHelpers.java b/test/048-reflect-v8/src/AnnotationTestHelpers.java
new file mode 100644
index 0000000..6b5bea2
--- /dev/null
+++ b/test/048-reflect-v8/src/AnnotationTestHelpers.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 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.annotation.Annotation;
+
+public class AnnotationTestHelpers {
+  // Provide custom print function that print a deterministic output.
+  // Note that Annotation#toString has unspecified order: it prints out the
+  // fields, which is why we can't rely on it.
+
+  public static String asString(Annotation anno) {
+    if (anno instanceof Calendar) {
+      return asString((Calendar)anno);
+    } else if (anno instanceof Calendars) {
+      return asString((Calendars)anno);
+    } else {
+      if (anno == null) {
+        return "<null>";
+      }
+      // Fall-back, usually would only go here in a test failure.
+      return anno.toString();
+    }
+  }
+
+  public static String asString(Annotation[] annos) {
+    String msg = "";
+
+    if (annos == null) {
+      msg += "<null>";
+    } else if (annos.length == 0) {
+      msg += "<empty>";
+    } else {
+      for (int i = 0; i < annos.length; ++i) {
+        msg += asString(annos[i]);
+
+        if (i != annos.length - 1) {
+          msg += ", ";
+        }
+      }
+    }
+
+    return msg;
+  }
+
+  public static String asString(Calendar calendar) {
+    if (calendar == null) {
+      return "<null>";
+    }
+
+    return "@Calendar(dayOfMonth=" + calendar.dayOfMonth() + ", dayOfWeek=" +
+      calendar.dayOfWeek() + ", hour=" + calendar.hour() + ")";
+  }
+
+  public static String asString(Calendars calendars) {
+    if (calendars == null) {
+      return "<null>";
+    }
+
+    String s = "@Calendars(value=[";
+
+    Calendar[] allValues = calendars.value();
+    for (int i = 0; i < allValues.length; ++i) {
+      s += asString(allValues[i]);
+      if (i != allValues.length - 1) {
+        s += ", ";
+      }
+    }
+
+    s += "])";
+
+    return s;
+  }
+}
diff --git a/test/048-reflect-v8/src/Calendar.java b/test/048-reflect-v8/src/Calendar.java
new file mode 100644
index 0000000..4a16573
--- /dev/null
+++ b/test/048-reflect-v8/src/Calendar.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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.annotation.Inherited;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+// This is a plain old non-1.8 annotation. At runtime we can see that it has a
+// "Repeatable" annotation if we query with getDeclaredAnnotation(Repeatable.class)
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable(Calendars.class)
+@Inherited  // note: container must also be @Inherited by JLS.
+public @interface Calendar {
+    String dayOfMonth() default "unspecified_month";
+    String dayOfWeek() default "unspecified_week";
+    int hour() default 6;
+}
+
diff --git a/test/048-reflect-v8/src/Calendars.java b/test/048-reflect-v8/src/Calendars.java
new file mode 100644
index 0000000..caeda52
--- /dev/null
+++ b/test/048-reflect-v8/src/Calendars.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+// Plain old annotation, there's nothing 1.8 specific about it.
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited  // note: elements must also be @Inherited by JLS.
+public @interface Calendars {
+  Calendar[] value();
+}
diff --git a/test/048-reflect-v8/src/DefaultDeclared.java b/test/048-reflect-v8/src/DefaultDeclared.java
new file mode 100644
index 0000000..16e8a24
--- /dev/null
+++ b/test/048-reflect-v8/src/DefaultDeclared.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2016 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;
+
+public class DefaultDeclared {
+  interface DefaultInterface {
+    default void sayHi() {
+      System.out.println("hi default");
+    }
+  }
+
+  interface RegularInterface {
+    void sayHi();
+  }
+
+  class ImplementsWithDefault implements DefaultInterface {}
+
+  class ImplementsWithDeclared implements DefaultInterface {
+    public void sayHi() {
+      System.out.println("hello specific from default");
+    }
+  }
+
+  abstract class UnimplementedWithRegular implements RegularInterface { }
+
+  class ImplementsWithRegular implements RegularInterface {
+    public void sayHi() {
+      System.out.println("hello specific");
+    }
+  }
+
+  private static void printGetMethod(Class<?> klass) {
+    Method m;
+    try {
+      m = klass.getDeclaredMethod("sayHi");
+      System.out.println("No error thrown for class " + klass.toString());
+    } catch (NoSuchMethodException e) {
+      System.out.println("NoSuchMethodException thrown for class " + klass.toString());
+    } catch (Throwable t) {
+      System.out.println("Unknown error thrown for class " + klass.toString());
+      t.printStackTrace();
+    }
+  }
+
+  public static void test() {
+    System.out.println("==============================");
+    System.out.println("Are These Methods found by getDeclaredMethod:");
+    System.out.println("==============================");
+
+    printGetMethod(DefaultInterface.class);
+    printGetMethod(RegularInterface.class);
+    printGetMethod(ImplementsWithDefault.class);
+    printGetMethod(ImplementsWithDeclared.class);
+    printGetMethod(ImplementsWithRegular.class);
+    printGetMethod(UnimplementedWithRegular.class);
+  }
+}
diff --git a/test/048-reflect-v8/src/IFaceA.java b/test/048-reflect-v8/src/IFaceA.java
new file mode 100644
index 0000000..9b1f610
--- /dev/null
+++ b/test/048-reflect-v8/src/IFaceA.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Stored as a complex annotation Calendars(Calendar,Calendar)
+// in the binary.
+@Calendars ({
+  @Calendar(dayOfMonth="if_a_first"),
+  @Calendar(dayOfMonth="if_b_last")
+})
+public interface IFaceA {
+}
diff --git a/test/048-reflect-v8/src/IFaceSimple.java b/test/048-reflect-v8/src/IFaceSimple.java
new file mode 100644
index 0000000..93cf610
--- /dev/null
+++ b/test/048-reflect-v8/src/IFaceSimple.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Simple annotation, no container.
+@Calendar(dayOfMonth="if_simple_first")
+public interface IFaceSimple {
+
+}
diff --git a/test/048-reflect-v8/src/IsDefaultTest.java b/test/048-reflect-v8/src/IsDefaultTest.java
new file mode 100644
index 0000000..177dcf1
--- /dev/null
+++ b/test/048-reflect-v8/src/IsDefaultTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 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;
+
+public class IsDefaultTest {
+  interface DefaultInterface {
+    default void sayHi() {
+      System.out.println("hi default");
+    }
+  }
+
+  interface RegularInterface {
+    void sayHi();
+  }
+
+  class ImplementsWithDefault implements DefaultInterface {}
+  class ImplementsWithRegular implements RegularInterface {
+    public void sayHi() {
+      System.out.println("hello specific");
+    }
+  }
+
+  private static void printIsDefault(Class<?> klass) {
+    Method m;
+    try {
+      m = klass.getMethod("sayHi");
+    } catch (Throwable t) {
+      System.out.println(t);
+      return;
+    }
+
+    boolean isDefault = m.isDefault();
+    System.out.println(klass.getName() + " is default = " + (isDefault ? "yes" : "no"));
+  }
+
+  public static void test() {
+    System.out.println("==============================");
+    System.out.println("Are These Methods Default:");
+    System.out.println("==============================");
+
+    printIsDefault(DefaultInterface.class);
+    printIsDefault(RegularInterface.class);
+    printIsDefault(ImplementsWithDefault.class);
+    printIsDefault(ImplementsWithRegular.class);
+  }
+}
diff --git a/test/048-reflect-v8/src/Main.java b/test/048-reflect-v8/src/Main.java
index 7fa2a92..b270e68 100644
--- a/test/048-reflect-v8/src/Main.java
+++ b/test/048-reflect-v8/src/Main.java
@@ -14,43 +14,15 @@
  * limitations under the License.
  */
 
-import java.lang.reflect.Method;
-
 public class Main {
-  interface DefaultInterface {
-    default void sayHi() {
-      System.out.println("hi default");
-    }
-  }
-
-  interface RegularInterface {
-    void sayHi();
-  }
-
-  class ImplementsWithDefault implements DefaultInterface {}
-  class ImplementsWithRegular implements RegularInterface {
-    public void sayHi() {
-      System.out.println("hello specific");
-    }
-  }
-
-  private static void printIsDefault(Class<?> klass) {
-    Method m;
-    try {
-      m = klass.getMethod("sayHi");
-    } catch (Throwable t) {
-      System.out.println(t);
-      return;
-    }
-
-    boolean isDefault = m.isDefault();
-    System.out.println(klass.getName() + " is default = " + (isDefault ? "yes" : "no"));
-  }
-
   public static void main(String[] args) {
-    printIsDefault(DefaultInterface.class);
-    printIsDefault(RegularInterface.class);
-    printIsDefault(ImplementsWithDefault.class);
-    printIsDefault(ImplementsWithRegular.class);
+    IsDefaultTest.test();
+    DefaultDeclared.test();
+    AnnotationTest.testAnnotationsByType();
+    AnnotationTest.testDeclaredAnnotation();
+    AnnotationTest.testDeclaredAnnotationsByType();
+    AnnotationTest.testMethodAnnotationsByType();
+    AnnotationTest.testMethodDeclaredAnnotations();
+    AnnotationTest.testMethodDeclaredAnnotationsByType();
   }
 }
diff --git a/test/048-reflect-v8/src/SingleUser.java b/test/048-reflect-v8/src/SingleUser.java
new file mode 100644
index 0000000..0f9c430
--- /dev/null
+++ b/test/048-reflect-v8/src/SingleUser.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Stored as a single "Calendar" annotation in the binary.
+@Calendar(dayOfWeek="single", hour=23)
+public class SingleUser {
+
+}
diff --git a/test/048-reflect-v8/src/User.java b/test/048-reflect-v8/src/User.java
new file mode 100644
index 0000000..003ceeb
--- /dev/null
+++ b/test/048-reflect-v8/src/User.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Stored as a complex annotation Calendars(Calendar,Calendar)
+// in the binary.
+//
+/* FIXME: Use this code instead, when Jack supports repeatable annotations properly.
+ *
+ * @Calendar(dayOfMonth="last")
+ * @Calendar(dayOfWeek="Fri", hour=23)
+ */
+@Calendars ({
+  @Calendar(dayOfMonth="last"),
+  @Calendar(dayOfWeek="Fri", hour=23)
+})
+public class User {
+
+}
diff --git a/test/048-reflect-v8/src/User2.java b/test/048-reflect-v8/src/User2.java
new file mode 100644
index 0000000..1a6049f
--- /dev/null
+++ b/test/048-reflect-v8/src/User2.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Stored as a complex annotation Calendars(Calendar,Calendar,Calendar)
+// in the binary.
+// (Check for order, should be z,x,y)
+@Calendars ({
+  @Calendar(dayOfMonth="z"),
+  @Calendar(dayOfMonth="x"),
+  @Calendar(dayOfMonth="y")
+})
+public class User2 {
+
+}
diff --git a/test/048-reflect-v8/src/UserComplex.java b/test/048-reflect-v8/src/UserComplex.java
new file mode 100644
index 0000000..e262349
--- /dev/null
+++ b/test/048-reflect-v8/src/UserComplex.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+// Stored as a complex annotation Calendars(Calendar,Calendar)
+// followed by a Calendar in the binary.
+// In other words { Calendars([C,C]), C }
+//
+// Note that trying to do {C,Calendars,C} or similar
+// is illegal by the JLS.
+@Calendar(dayOfMonth="afirst")
+@Calendars ({
+  @Calendar(dayOfMonth="zsecond"),
+  @Calendar(dayOfMonth="athird", hour=23)
+})
+// @Calendar(dayOfMonth="zlast")  // Leave for future ordering test
+public class UserComplex {
+
+}
diff --git a/test/048-reflect-v8/src/UserSub.java b/test/048-reflect-v8/src/UserSub.java
new file mode 100644
index 0000000..d60aa6a
--- /dev/null
+++ b/test/048-reflect-v8/src/UserSub.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016 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 UserSub
+  extends User
+  implements IFaceA, IFaceSimple {
+
+}
diff --git a/test/048-reflect-v8/src/UserSub2.java b/test/048-reflect-v8/src/UserSub2.java
new file mode 100644
index 0000000..13e2eb0
--- /dev/null
+++ b/test/048-reflect-v8/src/UserSub2.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2016 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 calendar subsumes anything else we would've normally gotten from the subclass.
+@Calendar(dayOfMonth="sub2")
+public class UserSub2
+  extends User
+  implements IFaceA, IFaceSimple {
+
+}
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index 6f50a76..21dc662 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -23,8 +23,8 @@
 ${JAVAC} -source 1.4 -target 1.4 -d classes `find src -name '*.java'`
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JILL} classes --output classes.jack
-  ${JACK} --import classes.jack --output-dex .
+  jar cf classes.jill.jar -C classes .
+  ${JACK} --import classes.jill.jar --output-dex .
 else
   # Suppress stderr to keep the inner class warnings out of the expected output.
   ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
diff --git a/test/091-override-package-private-method/build b/test/091-override-package-private-method/build
index 5a340dc..073a4ba 100755
--- a/test/091-override-package-private-method/build
+++ b/test/091-override-package-private-method/build
@@ -24,14 +24,12 @@
 mv classes/OverridePackagePrivateMethodSuper.class classes-ex
 
 if [ ${USE_JACK} = "true" ]; then
-  # Create .jack files from classes generated with javac.
-  ${JILL} classes --output classes.jack
-  ${JILL} classes-ex --output classes-ex.jack
+  jar cf classes.jill.jar -C classes .
+  jar cf classes-ex.jill.jar -C classes-ex .
 
-  # Create DEX files from .jack files.
-  ${JACK} --import classes.jack --output-dex .
+  ${JACK} --import classes.jill.jar --output-dex .
   zip $TEST_NAME.jar classes.dex
-  ${JACK} --import classes-ex.jack --output-dex .
+  ${JACK} --import classes-ex.jill.jar --output-dex .
   zip ${TEST_NAME}-ex.jar classes.dex
 else
   if [ ${NEED_DEX} = "true" ]; then
diff --git a/test/097-duplicate-method/build b/test/097-duplicate-method/build
index a855873..4525549 100644
--- a/test/097-duplicate-method/build
+++ b/test/097-duplicate-method/build
@@ -23,10 +23,10 @@
   ${JACK} --output-jack src.jack src
 
   ${JASMIN} -d classes src/*.j
-  ${JILL} classes --output jasmin.jack
+  jar cf jasmin.jill.jar -C classes .
 
   # We set jack.import.type.policy=keep-first to consider class definitions from jasmin first.
-  ${JACK} --import jasmin.jack --import src.jack -D jack.import.type.policy=keep-first --output-dex .
+  ${JACK} --import jasmin.jill.jar --import src.jack -D jack.import.type.policy=keep-first --output-dex .
 else
   ${JAVAC} -d classes src/*.java
   ${JASMIN} -d classes src/*.j
diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build
index e772fb8..58ac26d 100644
--- a/test/111-unresolvable-exception/build
+++ b/test/111-unresolvable-exception/build
@@ -22,8 +22,8 @@
 rm classes/TestException.class
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JILL} classes --output classes.jack
-  ${JACK} --import classes.jack --output-dex .
+  jar cf classes.jill.jar -C classes .
+  ${JACK} --import classes.jill.jar --output-dex .
 else
   ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 fi
diff --git a/test/113-multidex/build b/test/113-multidex/build
index 8ef5c0e..4557ccd 100644
--- a/test/113-multidex/build
+++ b/test/113-multidex/build
@@ -28,14 +28,12 @@
 rm classes2/Second.class classes2/FillerA.class classes2/FillerB.class classes2/Inf*.class
 
 if [ ${USE_JACK} = "true" ]; then
-  # Create .jack files from classes generated with javac.
-  ${JILL} classes --output classes.jack
-  ${JILL} classes2 --output classes2.jack
+  jar cf classes.jill.jar -C classes .
+  jar cf classes2.jill.jar -C classes2 .
 
-  # Create DEX files from .jack files.
-  ${JACK} --import classes.jack --output-dex .
+  ${JACK} --import classes.jill.jar --output-dex .
   mv classes.dex classes-1.dex
-  ${JACK} --import classes2.jack --output-dex .
+  ${JACK} --import classes2.jill.jar --output-dex .
   mv classes.dex classes2.dex
   mv classes-1.dex classes.dex
 else
diff --git a/test/115-native-bridge/expected.txt b/test/115-native-bridge/expected.txt
index b003307..852ec2e 100644
--- a/test/115-native-bridge/expected.txt
+++ b/test/115-native-bridge/expected.txt
@@ -1,4 +1,3 @@
-Code cache exists: './code_cache'.
 Native bridge initialized.
 Checking for getEnvValues.
 Ready for native bridge tests.
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index b70ca4f..aca356b 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -269,16 +269,12 @@
   struct stat st;
   if (app_code_cache_dir != nullptr) {
     if (stat(app_code_cache_dir, &st) == 0) {
-      if (S_ISDIR(st.st_mode)) {
-        printf("Code cache exists: '%s'.\n", app_code_cache_dir);
-      } else {
+      if (!S_ISDIR(st.st_mode)) {
         printf("Code cache is not a directory.\n");
       }
     } else {
       perror("Error when stat-ing the code_cache:");
     }
-  } else {
-    printf("app_code_cache_dir is null.\n");
   }
 
   if (art_cbs != nullptr) {
diff --git a/test/115-native-bridge/run b/test/115-native-bridge/run
index ea2045b..aeb5721 100644
--- a/test/115-native-bridge/run
+++ b/test/115-native-bridge/run
@@ -28,4 +28,4 @@
 LEFT=$(echo ${ARGS} | sed -r 's/-Djava.library.path.*//')
 RIGHT=$(echo ${ARGS} | sed -r 's/.*Djava.library.path[^ ]* //')
 MODARGS="${LEFT} -Djava.library.path=`pwd` ${RIGHT}"
-exec ${RUN} --runtime-option -XX:NativeBridge=libnativebridgetest.so ${MODARGS} NativeBridgeMain
+exec ${RUN} --runtime-option -Xforce-nb-testing --runtime-option -XX:NativeBridge=libnativebridgetest.so ${MODARGS} NativeBridgeMain
diff --git a/test/121-modifiers/build b/test/121-modifiers/build
index 85b69e9..771dd51 100644
--- a/test/121-modifiers/build
+++ b/test/121-modifiers/build
@@ -31,9 +31,9 @@
 # mv Main.class A.class A\$B.class A\$C.class classes/
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JILL} classes --output classes.jack
+  jar cf classes.jill.jar -C classes .
   # Workaround b/19561685: disable sanity checks to produce a DEX file with invalid modifiers.
-  ${JACK} --sanity-checks off --import classes.jack --output-dex .
+  ${JACK} --sanity-checks off --import classes.jill.jar --output-dex .
 else
   ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
 fi
diff --git a/test/124-missing-classes/build b/test/124-missing-classes/build
index b92ecf9..0a340a2 100644
--- a/test/124-missing-classes/build
+++ b/test/124-missing-classes/build
@@ -27,8 +27,8 @@
 rm 'classes/Main$MissingInnerClass.class'
 
 if [ ${USE_JACK} = "true" ]; then
-  ${JILL} classes --output classes.jack
-  ${JACK} --import classes.jack --output-dex .
+  jar cf classes.jill.jar -C classes .
+  ${JACK} --import classes.jill.jar --output-dex .
 else
   ${DX} -JXmx256m --debug --dex --output=classes.dex classes
 fi
diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build
index b7f2118..00b9ba0 100644
--- a/test/126-miranda-multidex/build
+++ b/test/126-miranda-multidex/build
@@ -28,14 +28,12 @@
 rm classes2/Main.class classes2/MirandaAbstract.class classes2/MirandaClass*.class classes2/MirandaInterface2*.class
 
 if [ ${USE_JACK} = "true" ]; then
-  # Create .jack files from classes generated with javac.
-  ${JILL} classes --output classes.jack
-  ${JILL} classes2 --output classes2.jack
+  jar cf classes.jill.jar -C classes .
+  jar cf classes2.jill.jar -C classes2 .
 
-  # Create DEX files from .jack files.
-  ${JACK} --import classes.jack --output-dex .
+  ${JACK} --import classes.jill.jar --output-dex .
   mv classes.dex classes-1.dex
-  ${JACK} --import classes2.jack --output-dex .
+  ${JACK} --import classes2.jill.jar --output-dex .
   mv classes.dex classes2.dex
   mv classes-1.dex classes.dex
 else
diff --git a/test/127-checker-secondarydex/build b/test/127-checker-secondarydex/build
index 0d9f4d6..7ce46ac 100755
--- a/test/127-checker-secondarydex/build
+++ b/test/127-checker-secondarydex/build
@@ -24,14 +24,12 @@
 mv classes/Super.class classes-ex
 
 if [ ${USE_JACK} = "true" ]; then
-  # Create .jack files from classes generated with javac.
-  ${JILL} classes --output classes.jack
-  ${JILL} classes-ex --output classes-ex.jack
+  jar cf classes.jill.jar -C classes .
+  jar cf classes-ex.jill.jar -C classes-ex .
 
-  # Create DEX files from .jack files.
-  ${JACK} --import classes.jack --output-dex .
+  ${JACK} --import classes.jill.jar --output-dex .
   zip $TEST_NAME.jar classes.dex
-  ${JACK} --import classes-ex.jack --output-dex .
+  ${JACK} --import classes-ex.jill.jar --output-dex .
   zip ${TEST_NAME}-ex.jar classes.dex
 else
   if [ ${NEED_DEX} = "true" ]; then
diff --git a/test/127-checker-secondarydex/src/Test.java b/test/127-checker-secondarydex/src/Test.java
index 266ed19..438e854 100644
--- a/test/127-checker-secondarydex/src/Test.java
+++ b/test/127-checker-secondarydex/src/Test.java
@@ -23,7 +23,7 @@
         System.out.println("Test");
     }
 
-    /// CHECK-START: java.lang.Integer Test.toInteger() ssa_builder (after)
+    /// CHECK-START: java.lang.Integer Test.toInteger() builder (after)
     /// CHECK:         LoadClass needs_access_check:false klass:java.lang.Integer
 
     public Integer toInteger() {
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 87656bc..45251b8 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -53,6 +53,7 @@
 
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_sleep(JNIEnv*, jobject, jint, jboolean, jdouble) {
   // Keep pausing.
+  printf("Going to sleep\n");
   for (;;) {
     pause();
   }
diff --git a/test/137-cfi/expected.txt b/test/137-cfi/expected.txt
index 8db7853..6a5618e 100644
--- a/test/137-cfi/expected.txt
+++ b/test/137-cfi/expected.txt
@@ -1,2 +1 @@
 JNI_OnLoad called
-JNI_OnLoad called
diff --git a/test/137-cfi/run b/test/137-cfi/run
index 6f4bcfe..8ec98c1 100755
--- a/test/137-cfi/run
+++ b/test/137-cfi/run
@@ -20,4 +20,5 @@
 
 # Test with minimal compressed debugging information.
 # Check only method names (parameters are omitted to save space).
-${RUN} "$@" -Xcompiler-option --generate-mini-debug-info
+# Temporarily disable due to bug 27172087 (leak/race in libunwind).
+# ${RUN} "$@" -Xcompiler-option --generate-mini-debug-info
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 7755338..d60a4eb 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -16,10 +16,7 @@
 
 import java.io.BufferedReader;
 import java.io.FileReader;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.io.InputStreamReader;
 import java.util.Arrays;
 import java.util.Comparator;
 
@@ -98,9 +95,12 @@
               throw new RuntimeException("Couldn't parse process");
           }
 
-          // Wait a bit, so the forked process has time to run until its sleep phase.
+          // Wait until the forked process had time to run until its sleep phase.
           try {
-              Thread.sleep(5000);
+              InputStreamReader stdout = new InputStreamReader(p.getInputStream(), "UTF-8");
+              BufferedReader lineReader = new BufferedReader(stdout);
+              while (!lineReader.readLine().contains("Going to sleep")) {
+              }
           } catch (Exception e) {
               throw new RuntimeException(e);
           }
diff --git a/test/444-checker-nce/src/Main.java b/test/444-checker-nce/src/Main.java
index 865355c..c96b18c 100644
--- a/test/444-checker-nce/src/Main.java
+++ b/test/444-checker-nce/src/Main.java
@@ -27,7 +27,7 @@
     return m.g();
   }
 
-  /// CHECK-START: Main Main.thisTest() ssa_builder (after)
+  /// CHECK-START: Main Main.thisTest() builder (after)
   /// CHECK:         NullCheck
   /// CHECK:         InvokeStaticOrDirect
 
@@ -38,7 +38,7 @@
     return g();
   }
 
-  /// CHECK-START: Main Main.newInstanceRemoveTest() ssa_builder (after)
+  /// CHECK-START: Main Main.newInstanceRemoveTest() builder (after)
   /// CHECK:         NewInstance
   /// CHECK:         NullCheck
   /// CHECK:         InvokeStaticOrDirect
@@ -52,7 +52,7 @@
     return m.g();
   }
 
-  /// CHECK-START: Main Main.newArrayRemoveTest() ssa_builder (after)
+  /// CHECK-START: Main Main.newArrayRemoveTest() builder (after)
   /// CHECK:         NewArray
   /// CHECK:         NullCheck
   /// CHECK:         ArrayGet
@@ -178,7 +178,7 @@
     return n.g();
   }
 
-  /// CHECK-START: Main Main.scopeRemoveTest(int, Main) ssa_builder (after)
+  /// CHECK-START: Main Main.scopeRemoveTest(int, Main) builder (after)
   /// CHECK:         NullCheck
 
   /// CHECK-START: Main Main.scopeRemoveTest(int, Main) instruction_simplifier (after)
diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java
index 8f9a32a..31bb94c 100644
--- a/test/449-checker-bce/src/Main.java
+++ b/test/449-checker-bce/src/Main.java
@@ -122,8 +122,9 @@
   /// CHECK: ArraySet
 
   static void constantIndexing1(int[] array) {
-    array[5] = 1;
-    array[4] = 1;
+    // Decreasing order: bc for 5 but not for 4.
+    array[5] = 11;
+    array[4] = 11;
   }
 
 
@@ -136,17 +137,18 @@
   /// CHECK: ArraySet
   /// CHECK: BoundsCheck
   /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
 
   /// CHECK-START: void Main.$opt$noinline$constantIndexing2(int[]) BCE (after)
-  /// CHECK: LessThanOrEqual
-  /// CHECK: Deoptimize
-  /// CHECK-NOT: BoundsCheck
+  /// CHECK-NOT: Deoptimize
+  /// CHECK: BoundsCheck
   /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK: ArraySet
-  /// CHECK-NOT: BoundsCheck
+  /// CHECK: BoundsCheck
   /// CHECK: ArraySet
   /// CHECK: BoundsCheck
   /// CHECK: ArraySet
@@ -156,12 +158,39 @@
     array[2] = 1;
     array[3] = 1;
     array[4] = 1;
-    array[-1] = 1;
+    array[-1] = 1;  // prevents the whole opt on [-1:4]
     if (array[1] == 1) {
       throw new Error("");
     }
   }
 
+  /// CHECK-START: void Main.constantIndexing2b(int[]) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+
+  /// CHECK-START: void Main.constantIndexing2b(int[]) BCE (after)
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+
+  static void constantIndexing2b(int[] array) {
+    array[0] = 7;
+    array[1] = 7;
+    array[2] = 7;
+    array[3] = 7;
+  }
 
   /// CHECK-START: int[] Main.constantIndexing3(int[], int[], boolean) BCE (before)
   /// CHECK: BoundsCheck
@@ -182,11 +211,9 @@
   /// 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
@@ -220,14 +247,14 @@
   /// CHECK: ArraySet
 
   /// CHECK-START: void Main.constantIndexing4(int[]) BCE (after)
-  /// CHECK-NOT: LessThanOrEqual
+  /// CHECK-NOT: Deoptimize
   /// CHECK: BoundsCheck
   /// CHECK: ArraySet
 
   // There is only one array access. It's not beneficial
   // to create a compare with deoptimization instruction.
   static void constantIndexing4(int[] array) {
-    array[0] = 1;
+    array[0] = -1;
   }
 
 
@@ -260,10 +287,221 @@
 
   /// CHECK-START: void Main.constantIndexing6(int[]) BCE (after)
   /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
 
   static void constantIndexing6(int[] array) {
-    array[3] = 1;
-    array[4] = 1;
+    array[3] = 111;
+    array[4] = 111;
+  }
+
+  /// CHECK-START: void Main.constantIndexing7(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+
+  /// CHECK-START: void Main.constantIndexing7(int[], int) BCE (after)
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+
+  static void constantIndexing7(int[] array, int base) {
+    // With constant offsets to symbolic base.
+    array[base]     = 10;
+    array[base + 1] = 20;
+    array[base + 2] = 30;
+    array[base + 3] = 40;
+  }
+
+  /// CHECK-START: void Main.constantIndexing8(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+
+  /// CHECK-START: void Main.constantIndexing8(int[], int) BCE (after)
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+
+  static void constantIndexing8(int[] array, int base) {
+    // With constant offsets "both ways" to symbolic base.
+    array[base - 1] = 100;
+    array[base]     = 200;
+    array[base + 1] = 300;
+    array[base + 2] = 400;
+  }
+
+  /// CHECK-START: void Main.constantIndexing9(int[], int) BCE (before)
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK: BoundsCheck
+  /// CHECK: ArraySet
+
+  /// CHECK-START: void Main.constantIndexing9(int[], int) BCE (after)
+  /// CHECK: Deoptimize
+  /// CHECK: Deoptimize
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+  /// CHECK: ArraySet
+  /// CHECK-NOT: BoundsCheck
+
+  static void constantIndexing9(int[] array, int base) {
+    // Final range is base..base+3 so conditional
+    // references may be included in the end.
+    array[base] = 0;
+    if (base != 12345)
+      array[base + 2] = 2;
+    array[base + 3] = 3;
+    if (base != 67890)
+      array[base + 1] = 1;
+  }
+
+  static void runAllConstantIndices() {
+    int[] a1 = { 0 };
+    int[] a6 = { 0, 0, 0, 0, 0, 0 };
+
+    boolean caught = false;
+    try {
+      constantIndexing1(a1);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      caught = true;
+    }
+    if (!caught) {
+      System.out.println("constant indices 1 failed!");
+    }
+
+    constantIndexing1(a6);
+    if (a6[4] != 11 || a6[5] != 11) {
+      System.out.println("constant indices 1 failed!");
+    }
+
+    caught = false;
+    try {
+      $opt$noinline$constantIndexing2(a6);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      caught = true;
+    }
+    if (!caught || a6[0] != 0 || a6[1] != 1 || a6[2] != 1 ||
+                   a6[3] != 1 || a6[4] != 1 || a6[5] != 11) {
+      System.out.println("constant indices 2 failed!");
+    }
+
+    caught = false;
+    try {
+      constantIndexing2b(a1);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      caught = true;
+    }
+    if (!caught || a1[0] != 7) {
+      System.out.println("constant indices 2b failed!");
+    }
+
+    constantIndexing2b(a6);
+    if (a6[0] != 7 || a6[1] != 7 || a6[2] != 7 ||
+        a6[3] != 7 || a6[4] != 1 || a6[5] != 11) {
+      System.out.println("constant indices 2b failed!");
+    }
+
+    int[] b4 = new int[4];
+    constantIndexing3(a6, b4, true);
+    if (b4[0] != 7 || b4[1] != 7 || b4[2] != 7 || b4[3] != 7) {
+      System.out.println("constant indices 3 failed!");
+    }
+
+    constantIndexing4(a1);
+    if (a1[0] != -1) {
+      System.out.println("constant indices 4 failed!");
+    }
+
+    caught = false;
+    try {
+      constantIndexing5(a6);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      caught = true;
+    }
+    if (!caught) {
+      System.out.println("constant indices 5 failed!");
+    }
+
+    constantIndexing6(a6);
+    if (a6[0] != 7   || a6[1] != 7   || a6[2] != 7 ||
+        a6[3] != 111 || a6[4] != 111 || a6[5] != 11) {
+      System.out.println("constant indices 6 failed!");
+    }
+
+    constantIndexing7(a6, 1);
+    if (a6[0] != 7  || a6[1] != 10 || a6[2] != 20 ||
+        a6[3] != 30 || a6[4] != 40 || a6[5] != 11) {
+      System.out.println("constant indices 7 failed!");
+    }
+
+    caught = false;
+    try {
+      constantIndexing7(a6, 5);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      caught = true;
+    }
+    if (!caught || a6[0] != 7  || a6[1] != 10 || a6[2] != 20 ||
+                   a6[3] != 30 || a6[4] != 40 || a6[5] != 10) {
+      System.out.println("constant indices 7 failed!");
+    }
+
+    constantIndexing8(a6, 1);
+    if (a6[0] != 100 || a6[1] != 200 || a6[2] != 300 ||
+        a6[3] != 400 || a6[4] != 40  || a6[5] != 10) {
+      System.out.println("constant indices 8 failed!");
+    }
+
+    caught = false;
+    try {
+      constantIndexing8(a6, 0);
+    } catch (ArrayIndexOutOfBoundsException e) {
+      caught = true;
+    }
+    if (!caught || a6[0] != 100) {
+      System.out.println("constant indices 8 failed!");
+    }
+
+    constantIndexing9(a6, 0);
+    if (a6[0] != 0 || a6[1] != 1  || a6[2] != 2  ||
+        a6[3] != 3 || a6[4] != 40 || a6[5] != 10) {
+      System.out.println("constant indices 9 failed!");
+    }
   }
 
   // A helper into which the actual throwing function should be inlined.
@@ -1102,6 +1340,9 @@
 
   static void testUnknownBounds() {
     boolean caught = false;
+
+    runAllConstantIndices();
+
     Main main = new Main();
     main.foo1(new int[10], 0, 10, false);
     if (main.sum != 10) {
diff --git a/test/450-checker-types/src/Main.java b/test/450-checker-types/src/Main.java
index d48b30e..027a9d9 100644
--- a/test/450-checker-types/src/Main.java
+++ b/test/450-checker-types/src/Main.java
@@ -205,7 +205,7 @@
   public static boolean $inline$InstanceofSubclassB(Object o) { return o instanceof SubclassB; }
   public static boolean $inline$InstanceofSubclassC(Object o) { return o instanceof SubclassC; }
 
-  /// CHECK-START: void Main.testInstanceOf_NotInlined(java.lang.Object) ssa_builder (after)
+  /// CHECK-START: void Main.testInstanceOf_NotInlined(java.lang.Object) builder (after)
   /// CHECK-DAG:     <<Cst0:i\d+>> IntConstant 0
   /// CHECK-DAG:     <<Cst1:i\d+>> IntConstant 1
   /// CHECK-DAG:     <<IOf1:z\d+>> InstanceOf
@@ -229,7 +229,7 @@
     }
   }
 
-  /// CHECK-START: void Main.testNotInstanceOf_NotInlined(java.lang.Object) ssa_builder (after)
+  /// CHECK-START: void Main.testNotInstanceOf_NotInlined(java.lang.Object) builder (after)
   /// CHECK-DAG:     <<Cst0:i\d+>> IntConstant 0
   /// CHECK-DAG:     <<Cst1:i\d+>> IntConstant 1
   /// CHECK-DAG:     <<IOf1:z\d+>> InstanceOf
@@ -487,7 +487,7 @@
     ((SubclassA)a[0]).$noinline$g();
   }
 
-  /// CHECK-START: int Main.testLoadExceptionInCatchNonExact(int, int) ssa_builder (after)
+  /// CHECK-START: int Main.testLoadExceptionInCatchNonExact(int, int) builder (after)
   /// CHECK:         LoadException klass:java.lang.ArithmeticException can_be_null:false exact:false
   public int testLoadExceptionInCatchNonExact(int x, int y) {
     try {
@@ -497,7 +497,7 @@
     }
   }
 
-  /// CHECK-START: int Main.testLoadExceptionInCatchExact(int) ssa_builder (after)
+  /// CHECK-START: int Main.testLoadExceptionInCatchExact(int) builder (after)
   /// CHECK:         LoadException klass:FinalException can_be_null:false exact:true
   public int testLoadExceptionInCatchExact(int x) {
     try {
@@ -511,7 +511,7 @@
     }
   }
 
-  /// CHECK-START: int Main.testLoadExceptionInCatchAll(int, int) ssa_builder (after)
+  /// CHECK-START: int Main.testLoadExceptionInCatchAll(int, int) builder (after)
   /// CHECK:         LoadException klass:java.lang.Throwable can_be_null:false exact:false
   public int testLoadExceptionInCatchAll(int x, int y) {
     try {
@@ -532,7 +532,7 @@
     return genericFinal.get();
   }
 
-  /// CHECK-START: SubclassC Main.inlineGenerics() ssa_builder (after)
+  /// CHECK-START: SubclassC Main.inlineGenerics() builder (after)
   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:SubclassC exact:false
   /// CHECK-NEXT:                    Return [<<Invoke>>]
 
@@ -544,7 +544,7 @@
     return c;
   }
 
-  /// CHECK-START: Final Main.inlineGenericsFinal() ssa_builder (after)
+  /// CHECK-START: Final Main.inlineGenericsFinal() builder (after)
   /// CHECK:      <<Invoke:l\d+>>    InvokeStaticOrDirect klass:Final exact:true
   /// CHECK-NEXT:                    Return [<<Invoke>>]
 
@@ -586,7 +586,7 @@
     return new SubclassA();
   }
 
-  /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) ssa_builder (after)
+  /// CHECK-START: void Main.updateNodesInTheSameBlockAsPhi(boolean) builder (after)
   /// CHECK:      <<Phi:l\d+>> Phi klass:Super
   /// CHECK:                   NullCheck [<<Phi>>] klass:Super
 
@@ -620,7 +620,7 @@
   }
 
 
-  /// CHECK-START: void Main.argumentCheck(Super, double, SubclassA, Final) ssa_builder (after)
+  /// CHECK-START: void Main.argumentCheck(Super, double, SubclassA, Final) builder (after)
   /// CHECK:      ParameterValue klass:Main can_be_null:false exact:false
   /// CHECK:      ParameterValue klass:Super can_be_null:true exact:false
   /// CHECK:      ParameterValue
@@ -636,7 +636,7 @@
 
   private int mainField = 0;
 
-  /// CHECK-START: SuperInterface Main.getWiderType(boolean, Interface, OtherInterface) ssa_builder (after)
+  /// CHECK-START: SuperInterface Main.getWiderType(boolean, Interface, OtherInterface) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
   /// CHECK:                         Return [<<Phi>>]
   private SuperInterface getWiderType(boolean cond, Interface a, OtherInterface b) {
@@ -692,7 +692,7 @@
     getSuper();
   }
 
-  /// CHECK-START: void Main.testLoopPhiWithNullFirstInput(boolean) ssa_builder (after)
+  /// CHECK-START: void Main.testLoopPhiWithNullFirstInput(boolean) builder (after)
   /// CHECK-DAG:  <<Null:l\d+>>      NullConstant
   /// CHECK-DAG:  <<Main:l\d+>>      NewInstance klass:Main exact:true
   /// CHECK-DAG:  <<LoopPhi:l\d+>>   Phi [<<Null>>,<<LoopPhi>>,<<Main>>] klass:Main exact:true
@@ -705,7 +705,7 @@
     }
   }
 
-  /// CHECK-START: java.lang.Object[] Main.testInstructionsWithUntypedParent() ssa_builder (after)
+  /// CHECK-START: java.lang.Object[] Main.testInstructionsWithUntypedParent() builder (after)
   /// CHECK-DAG:  <<Null:l\d+>>      NullConstant
   /// CHECK-DAG:  <<LoopPhi:l\d+>>   Phi [<<Null>>,<<Phi:l\d+>>] klass:java.lang.Object[] exact:true
   /// CHECK-DAG:  <<Array:l\d+>>     NewArray klass:java.lang.Object[] exact:true
diff --git a/test/458-checker-instruction-simplification/src/Main.java b/test/458-checker-instruction-simplification/src/Main.java
index 3c8abeb..8d6bb65 100644
--- a/test/458-checker-instruction-simplification/src/Main.java
+++ b/test/458-checker-instruction-simplification/src/Main.java
@@ -46,6 +46,12 @@
     }
   }
 
+  public static void assertStringEquals(String expected, String result) {
+    if (expected == null ? result != null : !expected.equals(result)) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+
   /**
    * Tiny programs exercising optimizations of arithmetic identities.
    */
@@ -1401,10 +1407,10 @@
 
   // Test that conditions on float/double are not flipped.
 
-  /// CHECK-START: int Main.floatConditionNotEqualOne(float) ssa_builder (after)
+  /// CHECK-START: int Main.floatConditionNotEqualOne(float) builder (after)
   /// CHECK:                            LessThanOrEqual
 
-  /// CHECK-START: int Main.floatConditionNotEqualOne(float) register (before)
+  /// CHECK-START: int Main.floatConditionNotEqualOne(float) instruction_simplifier_before_codegen (after)
   /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
   /// CHECK-DAG:      <<Const13:i\d+>>  IntConstant 13
   /// CHECK-DAG:      <<Const54:i\d+>>  IntConstant 54
@@ -1417,10 +1423,10 @@
     return ((f > 42.0f) == true) ? 13 : 54;
   }
 
-  /// CHECK-START: int Main.doubleConditionEqualZero(double) ssa_builder (after)
+  /// CHECK-START: int Main.doubleConditionEqualZero(double) builder (after)
   /// CHECK:                            LessThanOrEqual
 
-  /// CHECK-START: int Main.doubleConditionEqualZero(double) register (before)
+  /// CHECK-START: int Main.doubleConditionEqualZero(double) instruction_simplifier_before_codegen (after)
   /// CHECK-DAG:      <<Arg:d\d+>>      ParameterValue
   /// CHECK-DAG:      <<Const13:i\d+>>  IntConstant 13
   /// CHECK-DAG:      <<Const54:i\d+>>  IntConstant 54
@@ -1433,6 +1439,337 @@
     return ((d > 42.0) != false) ? 13 : 54;
   }
 
+  /// CHECK-START: int Main.intToDoubleToInt(int) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Double>>]
+  /// CHECK-DAG:                        Return [<<Int>>]
+
+  /// CHECK-START: int Main.intToDoubleToInt(int) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:                        Return [<<Arg>>]
+
+  /// CHECK-START: int Main.intToDoubleToInt(int) instruction_simplifier (after)
+  /// CHECK-NOT:                        TypeConversion
+
+  public static int intToDoubleToInt(int value) {
+    // Lossless conversion followed by a conversion back.
+    return (int) (double) value;
+  }
+
+  /// CHECK-START: java.lang.String Main.intToDoubleToIntPrint(int) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      {{i\d+}}          TypeConversion [<<Double>>]
+
+  /// CHECK-START: java.lang.String Main.intToDoubleToIntPrint(int) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      {{d\d+}}          TypeConversion [<<Arg>>]
+
+  /// CHECK-START: java.lang.String Main.intToDoubleToIntPrint(int) instruction_simplifier (after)
+  /// CHECK-DAG:                        TypeConversion
+  /// CHECK-NOT:                        TypeConversion
+
+  public static String intToDoubleToIntPrint(int value) {
+    // Lossless conversion followed by a conversion back
+    // with another use of the intermediate result.
+    double d = (double) value;
+    int i = (int) d;
+    return "d=" + d + ", i=" + i;
+  }
+
+  /// CHECK-START: int Main.byteToDoubleToInt(byte) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:b\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Double>>]
+  /// CHECK-DAG:                        Return [<<Int>>]
+
+  /// CHECK-START: int Main.byteToDoubleToInt(byte) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:b\d+>>      ParameterValue
+  /// CHECK-DAG:                        Return [<<Arg>>]
+
+  /// CHECK-START: int Main.byteToDoubleToInt(byte) instruction_simplifier (after)
+  /// CHECK-NOT:                        TypeConversion
+
+  public static int byteToDoubleToInt(byte value) {
+    // Lossless conversion followed by another conversion, use implicit conversion.
+    return (int) (double) value;
+  }
+
+  /// CHECK-START: int Main.floatToDoubleToInt(float) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Double>>]
+  /// CHECK-DAG:                        Return [<<Int>>]
+
+  /// CHECK-START: int Main.floatToDoubleToInt(float) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Int>>]
+
+  /// CHECK-START: int Main.floatToDoubleToInt(float) instruction_simplifier (after)
+  /// CHECK-DAG:                        TypeConversion
+  /// CHECK-NOT:                        TypeConversion
+
+  public static int floatToDoubleToInt(float value) {
+    // Lossless conversion followed by another conversion.
+    return (int) (double) value;
+  }
+
+  /// CHECK-START: java.lang.String Main.floatToDoubleToIntPrint(float) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      {{i\d+}}          TypeConversion [<<Double>>]
+
+  /// CHECK-START: java.lang.String Main.floatToDoubleToIntPrint(float) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      {{i\d+}}          TypeConversion [<<Double>>]
+
+  public static String floatToDoubleToIntPrint(float value) {
+    // Lossless conversion followed by another conversion with
+    // an extra use of the intermediate result.
+    double d = (double) value;
+    int i = (int) d;
+    return "d=" + d + ", i=" + i;
+  }
+
+  /// CHECK-START: short Main.byteToDoubleToShort(byte) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:b\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Double>>]
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  /// CHECK-START: short Main.byteToDoubleToShort(byte) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:b\d+>>      ParameterValue
+  /// CHECK-DAG:                        Return [<<Arg>>]
+
+  /// CHECK-START: short Main.byteToDoubleToShort(byte) instruction_simplifier (after)
+  /// CHECK-NOT:                        TypeConversion
+
+  public static short byteToDoubleToShort(byte value) {
+    // Originally, this is byte->double->int->short. The first conversion is lossless,
+    // so we merge this with the second one to byte->int which we omit as it's an implicit
+    // conversion. Then we eliminate the resulting byte->short as an implicit conversion.
+    return (short) (double) value;
+  }
+
+  /// CHECK-START: short Main.charToDoubleToShort(char) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:c\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Double>>]
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  /// CHECK-START: short Main.charToDoubleToShort(char) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:c\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  /// CHECK-START: short Main.charToDoubleToShort(char) instruction_simplifier (after)
+  /// CHECK-DAG:                        TypeConversion
+  /// CHECK-NOT:                        TypeConversion
+
+  public static short charToDoubleToShort(char value) {
+    // Originally, this is char->double->int->short. The first conversion is lossless,
+    // so we merge this with the second one to char->int which we omit as it's an implicit
+    // conversion. Then we are left with the resulting char->short conversion.
+    return (short) (double) value;
+  }
+
+  /// CHECK-START: short Main.floatToIntToShort(float) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  /// CHECK-START: short Main.floatToIntToShort(float) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:f\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  public static short floatToIntToShort(float value) {
+    // Lossy FP to integral conversion followed by another conversion: no simplification.
+    return (short) value;
+  }
+
+  /// CHECK-START: int Main.intToFloatToInt(int) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Float:f\d+>>    TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Float>>]
+  /// CHECK-DAG:                        Return [<<Int>>]
+
+  /// CHECK-START: int Main.intToFloatToInt(int) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Float:f\d+>>    TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Float>>]
+  /// CHECK-DAG:                        Return [<<Int>>]
+
+  public static int intToFloatToInt(int value) {
+    // Lossy integral to FP conversion followed another conversion: no simplification.
+    return (int) (float) value;
+  }
+
+  /// CHECK-START: double Main.longToIntToDouble(long) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Double>>]
+
+  /// CHECK-START: double Main.longToIntToDouble(long) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Double:d\d+>>   TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Double>>]
+
+  public static double longToIntToDouble(long value) {
+    // Lossy long-to-int conversion followed an integral to FP conversion: no simplification.
+    return (double) (int) value;
+  }
+
+  /// CHECK-START: long Main.longToIntToLong(long) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Long:j\d+>>     TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Long>>]
+
+  /// CHECK-START: long Main.longToIntToLong(long) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Long:j\d+>>     TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Long>>]
+
+  public static long longToIntToLong(long value) {
+    // Lossy long-to-int conversion followed an int-to-long conversion: no simplification.
+    return (long) (int) value;
+  }
+
+  /// CHECK-START: short Main.shortToCharToShort(short) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Char:c\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<Char>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  /// CHECK-START: short Main.shortToCharToShort(short) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:                        Return [<<Arg>>]
+
+  public static short shortToCharToShort(short value) {
+    // Integral conversion followed by non-widening integral conversion to original type.
+    return (short) (char) value;
+  }
+
+  /// CHECK-START: int Main.shortToLongToInt(short) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Long:j\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<Long>>]
+  /// CHECK-DAG:                        Return [<<Int>>]
+
+  /// CHECK-START: int Main.shortToLongToInt(short) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:                        Return [<<Arg>>]
+
+  public static int shortToLongToInt(short value) {
+    // Integral conversion followed by non-widening integral conversion, use implicit conversion.
+    return (int) (long) value;
+  }
+
+  /// CHECK-START: byte Main.shortToCharToByte(short) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Char:c\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      <<Byte:b\d+>>     TypeConversion [<<Char>>]
+  /// CHECK-DAG:                        Return [<<Byte>>]
+
+  /// CHECK-START: byte Main.shortToCharToByte(short) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Byte:b\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Byte>>]
+
+  public static byte shortToCharToByte(short value) {
+    // Integral conversion followed by non-widening integral conversion losing bits
+    // from the original type. Simplify to use only one conversion.
+    return (byte) (char) value;
+  }
+
+  /// CHECK-START: java.lang.String Main.shortToCharToBytePrint(short) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Char:c\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      {{b\d+}}          TypeConversion [<<Char>>]
+
+  /// CHECK-START: java.lang.String Main.shortToCharToBytePrint(short) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:s\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Char:c\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:      {{b\d+}}          TypeConversion [<<Char>>]
+
+  public static String shortToCharToBytePrint(short value) {
+    // Integral conversion followed by non-widening integral conversion losing bits
+    // from the original type with an extra use of the intermediate result.
+    char c = (char) value;
+    byte b = (byte) c;
+    return "c=" + ((int) c) + ", b=" + ((int) b);  // implicit conversions.
+  }
+
+  /// CHECK-START: byte Main.longAnd0xffToByte(long) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Mask:j\d+>>     LongConstant 255
+  /// CHECK-DAG:      <<And:j\d+>>      And [<<Mask>>,<<Arg>>]
+  /// CHECK-DAG:      <<Int:i\d+>>      TypeConversion [<<And>>]
+  /// CHECK-DAG:      <<Byte:b\d+>>     TypeConversion [<<Int>>]
+  /// CHECK-DAG:                        Return [<<Byte>>]
+
+  /// CHECK-START: byte Main.longAnd0xffToByte(long) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:j\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Byte:b\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Byte>>]
+
+  /// CHECK-START: byte Main.longAnd0xffToByte(long) instruction_simplifier (after)
+  /// CHECK-NOT:                        And
+
+  public static byte longAnd0xffToByte(long value) {
+    return (byte) (value & 0xff);
+  }
+
+  /// CHECK-START: char Main.intAnd0x1ffffToChar(int) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Mask:i\d+>>     IntConstant 131071
+  /// CHECK-DAG:      <<And:i\d+>>      And [<<Mask>>,<<Arg>>]
+  /// CHECK-DAG:      <<Char:c\d+>>     TypeConversion [<<And>>]
+  /// CHECK-DAG:                        Return [<<Char>>]
+
+  /// CHECK-START: char Main.intAnd0x1ffffToChar(int) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Char:c\d+>>     TypeConversion [<<Arg>>]
+  /// CHECK-DAG:                        Return [<<Char>>]
+
+  /// CHECK-START: char Main.intAnd0x1ffffToChar(int) instruction_simplifier (after)
+  /// CHECK-NOT:                        And
+
+  public static char intAnd0x1ffffToChar(int value) {
+    // Keeping all significant bits and one more.
+    return (char) (value & 0x1ffff);
+  }
+
+  /// CHECK-START: short Main.intAnd0x17fffToShort(int) instruction_simplifier (before)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Mask:i\d+>>     IntConstant 98303
+  /// CHECK-DAG:      <<And:i\d+>>      And [<<Mask>>,<<Arg>>]
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<And>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  /// CHECK-START: short Main.intAnd0x17fffToShort(int) instruction_simplifier (after)
+  /// CHECK-DAG:      <<Arg:i\d+>>      ParameterValue
+  /// CHECK-DAG:      <<Mask:i\d+>>     IntConstant 98303
+  /// CHECK-DAG:      <<And:i\d+>>      And [<<Mask>>,<<Arg>>]
+  /// CHECK-DAG:      <<Short:s\d+>>    TypeConversion [<<And>>]
+  /// CHECK-DAG:                        Return [<<Short>>]
+
+  public static short intAnd0x17fffToShort(int value) {
+    // No simplification: clearing a significant bit.
+    return (short) (value & 0x17fff);
+  }
+
   public static void main(String[] args) {
     int arg = 123456;
 
@@ -1518,6 +1855,57 @@
     assertIntEquals(floatConditionNotEqualOne(43.0f), 13);
     assertIntEquals(doubleConditionEqualZero(6.0), 54);
     assertIntEquals(doubleConditionEqualZero(43.0), 13);
+
+    assertIntEquals(intToDoubleToInt(1234567), 1234567);
+    assertIntEquals(intToDoubleToInt(Integer.MIN_VALUE), Integer.MIN_VALUE);
+    assertIntEquals(intToDoubleToInt(Integer.MAX_VALUE), Integer.MAX_VALUE);
+    assertStringEquals(intToDoubleToIntPrint(7654321), "d=7654321.0, i=7654321");
+    assertIntEquals(byteToDoubleToInt((byte) 12), 12);
+    assertIntEquals(byteToDoubleToInt(Byte.MIN_VALUE), Byte.MIN_VALUE);
+    assertIntEquals(byteToDoubleToInt(Byte.MAX_VALUE), Byte.MAX_VALUE);
+    assertIntEquals(floatToDoubleToInt(11.3f), 11);
+    assertStringEquals(floatToDoubleToIntPrint(12.25f), "d=12.25, i=12");
+    assertIntEquals(byteToDoubleToShort((byte) 123), 123);
+    assertIntEquals(byteToDoubleToShort(Byte.MIN_VALUE), Byte.MIN_VALUE);
+    assertIntEquals(byteToDoubleToShort(Byte.MAX_VALUE), Byte.MAX_VALUE);
+    assertIntEquals(charToDoubleToShort((char) 1234), 1234);
+    assertIntEquals(charToDoubleToShort(Character.MIN_VALUE), Character.MIN_VALUE);
+    assertIntEquals(charToDoubleToShort(Character.MAX_VALUE), /* sign-extended */ -1);
+    assertIntEquals(floatToIntToShort(12345.75f), 12345);
+    assertIntEquals(floatToIntToShort((float)(Short.MIN_VALUE - 1)), Short.MAX_VALUE);
+    assertIntEquals(floatToIntToShort((float)(Short.MAX_VALUE + 1)), Short.MIN_VALUE);
+    assertIntEquals(intToFloatToInt(-54321), -54321);
+    assertDoubleEquals(longToIntToDouble(0x1234567812345678L), (double) 0x12345678);
+    assertDoubleEquals(longToIntToDouble(Long.MIN_VALUE), 0.0);
+    assertDoubleEquals(longToIntToDouble(Long.MAX_VALUE), -1.0);
+    assertLongEquals(longToIntToLong(0x1234567812345678L), 0x0000000012345678L);
+    assertLongEquals(longToIntToLong(0x1234567887654321L), 0xffffffff87654321L);
+    assertLongEquals(longToIntToLong(Long.MIN_VALUE), 0L);
+    assertLongEquals(longToIntToLong(Long.MAX_VALUE), -1L);
+    assertIntEquals(shortToCharToShort((short) -5678), (short) -5678);
+    assertIntEquals(shortToCharToShort(Short.MIN_VALUE), Short.MIN_VALUE);
+    assertIntEquals(shortToCharToShort(Short.MAX_VALUE), Short.MAX_VALUE);
+    assertIntEquals(shortToLongToInt((short) 5678), 5678);
+    assertIntEquals(shortToLongToInt(Short.MIN_VALUE), Short.MIN_VALUE);
+    assertIntEquals(shortToLongToInt(Short.MAX_VALUE), Short.MAX_VALUE);
+    assertIntEquals(shortToCharToByte((short) 0x1234), 0x34);
+    assertIntEquals(shortToCharToByte((short) 0x12f0), -0x10);
+    assertIntEquals(shortToCharToByte(Short.MIN_VALUE), 0);
+    assertIntEquals(shortToCharToByte(Short.MAX_VALUE), -1);
+    assertStringEquals(shortToCharToBytePrint((short) 1025), "c=1025, b=1");
+    assertStringEquals(shortToCharToBytePrint((short) 1023), "c=1023, b=-1");
+    assertStringEquals(shortToCharToBytePrint((short) -1), "c=65535, b=-1");
+
+    assertIntEquals(longAnd0xffToByte(0x1234432112344321L), 0x21);
+    assertIntEquals(longAnd0xffToByte(Long.MIN_VALUE), 0);
+    assertIntEquals(longAnd0xffToByte(Long.MAX_VALUE), -1);
+    assertIntEquals(intAnd0x1ffffToChar(0x43211234), 0x1234);
+    assertIntEquals(intAnd0x1ffffToChar(Integer.MIN_VALUE), 0);
+    assertIntEquals(intAnd0x1ffffToChar(Integer.MAX_VALUE), Character.MAX_VALUE);
+    assertIntEquals(intAnd0x17fffToShort(0x87654321), 0x4321);
+    assertIntEquals(intAnd0x17fffToShort(0x88888888), 0x0888);
+    assertIntEquals(intAnd0x17fffToShort(Integer.MIN_VALUE), 0);
+    assertIntEquals(intAnd0x17fffToShort(Integer.MAX_VALUE), Short.MAX_VALUE);
   }
 
   public static boolean booleanField;
diff --git a/test/464-checker-inline-sharpen-calls/src/Main.java b/test/464-checker-inline-sharpen-calls/src/Main.java
index 2222e0f..3f25635 100644
--- a/test/464-checker-inline-sharpen-calls/src/Main.java
+++ b/test/464-checker-inline-sharpen-calls/src/Main.java
@@ -39,7 +39,7 @@
     m.invokeVirtual();
   }
 
-  /// CHECK-START: int Main.inlineSharpenHelperInvoke() ssa_builder (after)
+  /// CHECK-START: int Main.inlineSharpenHelperInvoke() builder (after)
   /// CHECK-DAG:     <<Invoke:i\d+>>  InvokeVirtual {{.*\.getFoo.*}}
   /// CHECK-DAG:                      Return [<<Invoke>>]
 
diff --git a/test/477-checker-bound-type/src/Main.java b/test/477-checker-bound-type/src/Main.java
index 0f65e44..2504ab2 100644
--- a/test/477-checker-bound-type/src/Main.java
+++ b/test/477-checker-bound-type/src/Main.java
@@ -17,7 +17,7 @@
 
 public class Main {
 
-  /// CHECK-START: java.lang.Object Main.boundTypeForIf(java.lang.Object) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.boundTypeForIf(java.lang.Object) builder (after)
   /// CHECK:     BoundType
   public static Object boundTypeForIf(Object a) {
     if (a != null) {
@@ -27,7 +27,7 @@
     }
   }
 
-  /// CHECK-START: java.lang.Object Main.boundTypeForInstanceOf(java.lang.Object) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.boundTypeForInstanceOf(java.lang.Object) builder (after)
   /// CHECK:     BoundType
   public static Object boundTypeForInstanceOf(Object a) {
     if (a instanceof Main) {
@@ -37,7 +37,7 @@
     }
   }
 
-  /// CHECK-START: java.lang.Object Main.noBoundTypeForIf(java.lang.Object) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.noBoundTypeForIf(java.lang.Object) builder (after)
   /// CHECK-NOT: BoundType
   public static Object noBoundTypeForIf(Object a) {
     if (a == null) {
@@ -47,7 +47,7 @@
     }
   }
 
-  /// CHECK-START: java.lang.Object Main.noBoundTypeForInstanceOf(java.lang.Object) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.noBoundTypeForInstanceOf(java.lang.Object) builder (after)
   /// CHECK-NOT: BoundType
   public static Object noBoundTypeForInstanceOf(Object a) {
     if (a instanceof Main) {
diff --git a/test/492-checker-inline-invoke-interface/src/Main.java b/test/492-checker-inline-invoke-interface/src/Main.java
index 3106ce4..a919690 100644
--- a/test/492-checker-inline-invoke-interface/src/Main.java
+++ b/test/492-checker-inline-invoke-interface/src/Main.java
@@ -31,7 +31,7 @@
     int a = ForceStatic.field;
   }
 
-  /// CHECK-START: void Main.main(java.lang.String[]) ssa_builder (after)
+  /// CHECK-START: void Main.main(java.lang.String[]) builder (after)
   /// CHECK:           InvokeStaticOrDirect {{.*Main.<init>.*}}
   /// CHECK:           InvokeInterface
 
diff --git a/test/510-checker-try-catch/smali/Builder.smali b/test/510-checker-try-catch/smali/Builder.smali
index 1fde5ed..8ec840d 100644
--- a/test/510-checker-try-catch/smali/Builder.smali
+++ b/test/510-checker-try-catch/smali/Builder.smali
@@ -41,28 +41,35 @@
 ## CHECK:  predecessors     "<<BEnterTry2>>"
 ## CHECK:  successors       "<<BExitTry2:B\d+>>"
 ## CHECK:  DivZeroCheck
+## CHECK:  <<Div:i\d+>> Div
 
-## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExitTry2>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>" "<<BCatch3:B\d+>>"
+## CHECK:  name             "<<BAfterTry2:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn:B\d+>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BReturn>>"
+## CHECK:  predecessors     "<<BAfterTry2>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>" "<<BCatch3:B\d+>>"
+## CHECK:  Phi [<<Div>>,<<Minus1>>,<<Minus2>>,<<Minus3>>]
 ## CHECK:  Return
 
 ## CHECK:  name             "<<BCatch1>>"
 ## CHECK:  predecessors     "<<BEnterTry1>>" "<<BExitTry1>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BCatch2>>"
 ## CHECK:  predecessors     "<<BEnterTry2>>" "<<BExitTry2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus2>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BCatch3>>"
 ## CHECK:  predecessors     "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry1>>" "<<BExitTry2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus3>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "B0"
@@ -84,7 +91,7 @@
 
 ## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
-## CHECK:  successors       "<<BReturn>>"
+## CHECK:  successors       "<<BAfterTry2>>"
 ## CHECK:  xhandlers        "<<BCatch2>>" "<<BCatch3>>"
 ## CHECK:  TryBoundary      kind:exit
 
@@ -105,6 +112,8 @@
     .catch Ljava/lang/OutOfMemoryError; {:try_start_2 .. :try_end_2} :catch_mem
     .catchall {:try_start_2 .. :try_end_2} :catch_other
 
+    nop
+
     :return
     return p0
 
@@ -131,7 +140,7 @@
 
 ## CHECK:  name             "<<BIf>>"
 ## CHECK:  predecessors     "B0"
-## CHECK:  successors       "<<BEnterTry2:B\d+>>" "<<BThen:B\d+>>"
+## CHECK:  successors       "<<BSplit1:B\d+>>" "<<BThen:B\d+>>"
 ## CHECK:  If
 
 ## CHECK:  name             "<<BThen>>"
@@ -145,19 +154,19 @@
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BTry2:B\d+>>"
-## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BEnterTry2:B\d+>>"
 ## CHECK:  successors       "<<BExitTry2:B\d+>>"
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExitTry2>>" "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BSplit3:B\d+>>" "<<BCatch:B\d+>>"
 ## CHECK:  Return
 
 ## CHECK:  name             "<<BCatch>>"
 ## CHECK:  predecessors     "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry1>>" "<<BExitTry2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "<<BThen>>"
@@ -166,23 +175,38 @@
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BEnterTry2>>"
-## CHECK:  predecessors     "<<BIf>>" "<<BExitTry1>>"
+## CHECK:  predecessors     "<<BSplit1>>" "<<BSplit2:B\d+>>"
 ## CHECK:  successors       "<<BTry2>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BExitTry1>>"
 ## CHECK:  predecessors     "<<BTry1>>"
-## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  successors       "<<BSplit2>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
 ## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
-## CHECK:  successors       "<<BReturn>>"
+## CHECK:  successors       "<<BSplit3>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit1>>"
+## CHECK:  predecessors     "<<BIf>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit2>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit3>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  Goto
+
 .method public static testMultipleEntries(IIII)I
     .registers 4
 
@@ -220,23 +244,24 @@
 ## CHECK:  name             "<<BTry:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry>>"
 ## CHECK:  successors       "<<BExitTry1:B\d+>>" "<<BExitTry2:B\d+>>"
-## CHECK:  Div
+## CHECK:  <<Div:i\d+>> Div
 ## CHECK:  If
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExitTry2>>" "<<BThen:B\d+>>" "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BSplit:B\d+>>" "<<BThen:B\d+>>" "<<BCatch:B\d+>>"
+## CHECK:  Phi [<<Div>>,<<Minus1>>,<<Minus2>>]
 ## CHECK:  Return
 
 ## CHECK:  name             "<<BThen>>"
 ## CHECK:  predecessors     "<<BExitTry1>>"
 ## CHECK:  successors       "<<BReturn>>"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BCatch>>"
 ## CHECK:  predecessors     "<<BEnterTry>>" "<<BExitTry1>>" "<<BExitTry2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus2>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnterTry>>"
 ## CHECK:  predecessors     "B0"
@@ -252,10 +277,15 @@
 
 ## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry>>"
-## CHECK:  successors       "<<BReturn>>"
+## CHECK:  successors       "<<BSplit>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  Goto
+
 .method public static testMultipleExits(II)I
     .registers 2
 
@@ -295,23 +325,25 @@
 ## CHECK:  name             "<<BTry2:B\d+>>"
 ## CHECK:  predecessors     "<<BEnter2:B\d+>>"
 ## CHECK:  successors       "<<BExit2:B\d+>>"
-## CHECK:  Div
+## CHECK:  <<Div:i\d+>> Div
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExit2>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
+## CHECK:  predecessors     "<<BSplit:B\d+>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
+## CHECK:  Phi [<<Div>>,<<Minus1>>,<<Minus2>>]
 ## CHECK:  Return
 
 ## CHECK:  name             "<<BCatch1>>"
 ## CHECK:  predecessors     "<<BEnter1>>" "<<BExit1>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BCatch2>>"
 ## CHECK:  predecessors     "<<BEnter2>>" "<<BExit2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus2>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnter1>>"
 ## CHECK:  predecessors     "B0"
@@ -333,10 +365,15 @@
 
 ## CHECK:  name             "<<BExit2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
-## CHECK:  successors       "<<BReturn>>"
+## CHECK:  successors       "<<BSplit>>"
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit>>"
+## CHECK:  predecessors     "<<BExit2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  Goto
+
 .method public static testSharedBoundary(III)I
     .registers 3
 
@@ -378,28 +415,31 @@
 ## CHECK:  name             "<<BTry1:B\d+>>"
 ## CHECK:  predecessors     "<<BEnter1:B\d+>>"
 ## CHECK:  successors       "<<BExit1:B\d+>>"
-## CHECK:  Div
+## CHECK:  <<Div:i\d+>> Div
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BTry2:B\d+>>"
 ## CHECK:  predecessors     "<<BEnter2>>"
 ## CHECK:  successors       "<<BExit2:B\d+>>"
 ## CHECK:  Div
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExit1>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
+## CHECK:  predecessors     "<<BSplit:B\d+>>" "<<BCatch1:B\d+>>" "<<BCatch2:B\d+>>"
+## CHECK:  Phi [<<Div>>,<<Minus1>>,<<Minus2>>]
 ## CHECK:  Return
 
 ## CHECK:  name             "<<BCatch1>>"
 ## CHECK:  predecessors     "<<BEnter1>>" "<<BExit1>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BCatch2>>"
 ## CHECK:  predecessors     "<<BEnter2>>" "<<BExit2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus2>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnter1>>"
 ## CHECK:  predecessors     "<<BExit2>>"
@@ -415,7 +455,7 @@
 
 ## CHECK:  name             "<<BExit1>>"
 ## CHECK:  predecessors     "<<BTry1>>"
-## CHECK:  successors       "<<BReturn>>"
+## CHECK:  successors       "<<BSplit>>"
 ## CHECK:  xhandlers        "<<BCatch1>>"
 ## CHECK:  TryBoundary      kind:exit
 
@@ -425,6 +465,11 @@
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit>>"
+## CHECK:  predecessors     "<<BExit1>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  Goto
+
 .method public static testSharedBoundary_Reverse(III)I
     .registers 3
 
@@ -472,26 +517,30 @@
 ## CHECK:  predecessors     "<<BEnter2:B\d+>>"
 ## CHECK:  successors       "<<BExit2:B\d+>>"
 ## CHECK:  Div
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BTry3:B\d+>>"
 ## CHECK:  predecessors     "<<BEnter3:B\d+>>"
 ## CHECK:  successors       "<<BExit3:B\d+>>"
-## CHECK:  Div
+## CHECK:  <<Div:i\d+>> Div
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExit3>>" "<<BCatchArith:B\d+>>" "<<BCatchAll:B\d+>>"
+## CHECK:  predecessors     "<<BSplit:B\d+>>" "<<BCatchArith:B\d+>>" "<<BCatchAll:B\d+>>"
+## CHECK:  Phi [<<Div>>,<<Minus1>>,<<Minus2>>]
+## CHECK:  Return
 
 ## CHECK:  name             "<<BCatchArith>>"
 ## CHECK:  predecessors     "<<BEnter2>>" "<<BExit2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BCatchAll>>"
 ## CHECK:  predecessors     "<<BEnter1>>" "<<BEnter2>>" "<<BEnter3>>" "<<BExit1>>" "<<BExit2>>" "<<BExit3>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus2>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnter1>>"
 ## CHECK:  predecessors     "B0"
@@ -525,10 +574,15 @@
 
 ## CHECK:  name             "<<BExit3>>"
 ## CHECK:  predecessors     "<<BTry3>>"
-## CHECK:  successors       "<<BReturn>>"
+## CHECK:  successors       "<<BSplit>>"
 ## CHECK:  xhandlers        "<<BCatchAll>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit>>"
+## CHECK:  predecessors     "<<BExit3>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  Goto
+
 .method public static testNestedTry(IIII)I
     .registers 4
 
@@ -567,14 +621,18 @@
 ## CHECK:  predecessors     "<<BEnterTry1:B\d+>>"
 ## CHECK:  successors       "<<BExitTry1:B\d+>>"
 ## CHECK:  Div
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BTry2:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry2:B\d+>>"
 ## CHECK:  successors       "<<BExitTry2:B\d+>>"
-## CHECK:  Div
+## CHECK:  <<Div:i\d+>> Div
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExitTry2>>" "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BSplit:B\d+>>" "<<BCatch:B\d+>>"
+## CHECK:  Phi [<<Div>>,<<Minus1>>]
+## CHECK:  Return
 
 ## CHECK:  name             "<<BOutside:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry1>>"
@@ -585,7 +643,7 @@
 ## CHECK:  predecessors     "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry1>>" "<<BExitTry2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "B0"
@@ -607,10 +665,15 @@
 
 ## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
-## CHECK:  successors       "<<BReturn>>"
+## CHECK:  successors       "<<BSplit>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
+## CHECK:  Goto
+
 .method public static testIncontinuousTry(IIII)I
     .registers 4
 
@@ -642,12 +705,12 @@
 
 ## CHECK:  name             "<<BPSwitch0>>"
 ## CHECK:  predecessors     "B0"
-## CHECK:  successors       "<<BEnterTry2:B\d+>>" "<<BPSwitch1:B\d+>>"
+## CHECK:  successors       "<<BSplit1:B\d+>>" "<<BPSwitch1:B\d+>>"
 ## CHECK:  If
 
 ## CHECK:  name             "<<BPSwitch1>>"
 ## CHECK:  predecessors     "<<BPSwitch0>>"
-## CHECK:  successors       "<<BOutside:B\d+>>" "<<BEnterTry1:B\d+>>"
+## CHECK:  successors       "<<BSplit2:B\d+>>" "<<BEnterTry1:B\d+>>"
 ## CHECK:  If
 
 ## CHECK:  name             "<<BTry1:B\d+>>"
@@ -656,44 +719,68 @@
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BTry2:B\d+>>"
-## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BEnterTry2:B\d+>>"
 ## CHECK:  successors       "<<BExitTry2:B\d+>>"
 ## CHECK:  Div
 
-## CHECK:  name             "<<BOutside>>"
-## CHECK:  predecessors     "<<BPSwitch1>>" "<<BExitTry2>>"
-## CHECK:  successors       "<<BCatchReturn:B\d+>>"
+## CHECK:  name             "<<BOutside:B\d+>>"
+## CHECK:  predecessors     "<<BSplit2>>" "<<BSplit4:B\d+>>"
+## CHECK:  successors       "<<BReturn:B\d+>>"
 ## CHECK:  Div
 
-## CHECK:  name             "<<BCatchReturn>>"
-## CHECK:  predecessors     "<<BOutside>>" "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry1>>" "<<BExitTry2>>"
+## CHECK:  name             "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry1>>" "<<BExitTry2>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  Return
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "<<BPSwitch1>>"
 ## CHECK:  successors       "<<BTry1>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BEnterTry2>>"
-## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  predecessors     "<<BSplit1>>" "<<BSplit3:B\d+>>"
 ## CHECK:  successors       "<<BTry2>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BExitTry1>>"
 ## CHECK:  predecessors     "<<BTry1>>"
-## CHECK:  successors       "<<BEnterTry2>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  successors       "<<BSplit3>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
 ## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
-## CHECK:  successors       "<<BOutside>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  successors       "<<BSplit4>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BReturn>>"
+## CHECK:  predecessors     "<<BCatch>>" "<<BOutside>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BSplit1>>"
+## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit2>>"
+## CHECK:  predecessors     "<<BPSwitch1>>"
+## CHECK:  successors       "<<BOutside>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit3>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit4>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BOutside>>"
+## CHECK:  Goto
+
 .method public static testSwitchTryEnter(IIII)I
     .registers 4
 
@@ -728,58 +815,78 @@
 
 ## CHECK:  name             "<<BPSwitch0:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry1>>"
-## CHECK:  successors       "<<BTry2:B\d+>>" "<<BExitTry1:B\d+>>"
+## CHECK:  successors       "<<BSplit1:B\d+>>" "<<BExitTry1:B\d+>>"
 ## CHECK:  If
 
 ## CHECK:  name             "<<BPSwitch1:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry1>>"
-## CHECK:  successors       "<<BOutside:B\d+>>" "<<BEnterTry2:B\d+>>"
+## CHECK:  successors       "<<BSplit2:B\d+>>" "<<BEnterTry2:B\d+>>"
 ## CHECK:  If
 
 ## CHECK:  name             "<<BTry1:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry2>>"
-## CHECK:  successors       "<<BTry2>>"
+## CHECK:  successors       "<<BTry2:B\d+>>"
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BTry2>>"
-## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  predecessors     "<<BSplit1>>" "<<BTry1>>"
 ## CHECK:  successors       "<<BExitTry2:B\d+>>"
 ## CHECK:  Div
 
-## CHECK:  name             "<<BOutside>>"
-## CHECK:  predecessors     "<<BPSwitch1>>" "<<BExitTry2>>"
-## CHECK:  successors       "<<BCatchReturn:B\d+>>"
+## CHECK:  name             "<<BOutside:B\d+>>"
+## CHECK:  predecessors     "<<BSplit2>>" "<<BSplit3:B\d+>>"
+## CHECK:  successors       "<<BReturn:B\d+>>"
 ## CHECK:  Div
 
-## CHECK:  name             "<<BCatchReturn>>"
-## CHECK:  predecessors     "<<BOutside>>" "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry1>>" "<<BExitTry2>>"
+## CHECK:  name             "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>" "<<BEnterTry2>>" "<<BExitTry1>>" "<<BExitTry2>>"
+## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  Return
+## CHECK:  Goto
 
 ## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "B0"
 ## CHECK:  successors       "<<BPSwitch0>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BEnterTry2>>"
 ## CHECK:  predecessors     "<<BPSwitch1>>"
 ## CHECK:  successors       "<<BTry1>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BExitTry1>>"
 ## CHECK:  predecessors     "<<BPSwitch0>>"
 ## CHECK:  successors       "<<BPSwitch1>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
 ## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
-## CHECK:  successors       "<<BOutside>>"
-## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  successors       "<<BSplit3>>"
+## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BReturn>>"
+## CHECK:  predecessors     "<<BCatch>>" "<<BOutside>>"
+## CHECK:  Return
+
+## CHECK:  name             "<<BSplit1>>"
+## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  successors       "<<BTry2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit2>>"
+## CHECK:  predecessors     "<<BPSwitch1>>"
+## CHECK:  successors       "<<BOutside>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit3>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BOutside>>"
+## CHECK:  Goto
+
 .method public static testSwitchTryExit(IIII)I
     .registers 4
 
@@ -825,7 +932,7 @@
 ## CHECK:  predecessors     "<<BEnterTry>>" "<<BExitTry>>"
 ## CHECK:  successors       "<<BExit:B\d+>>"
 ## CHECK:  flags            "catch_block"
-## CHECK:  StoreLocal       [v0,<<Minus1>>]
+## CHECK:  Return [<<Minus1>>]
 
 ## CHECK:  name             "<<BExit>>"
 ## CHECK:  predecessors     "<<BExitTry>>" "<<BCatch>>"
@@ -861,18 +968,21 @@
 ## CHECK-START: int Builder.testCatchLoop(int, int, int) builder (after)
 
 ## CHECK:  name             "B0"
-## CHECK:  successors       "<<BCatch:B\d+>>"
+## CHECK:  successors       "<<BSplit2:B\d+>>"
 
-## CHECK:  name             "<<BCatch>>"
-## CHECK:  predecessors     "B0" "<<BEnterTry:B\d+>>" "<<BExitTry:B\d+>>"
-## CHECK:  successors       "<<BEnterTry>>"
+## CHECK:  name             "<<BCatch:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry:B\d+>>" "<<BExitTry:B\d+>>"
+## CHECK:  successors       "<<BSplit1:B\d+>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry>>"
 ## CHECK:  successors       "<<BExit:B\d+>>"
+## CHECK:  Return
 
 ## CHECK:  name             "<<BExit>>"
+## CHECK:  predecessors     "<<BReturn>>"
+## CHECK:  Exit
 
 ## CHECK:  name             "<<BTry:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry>>"
@@ -880,7 +990,7 @@
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BEnterTry>>"
-## CHECK:  predecessors     "<<BCatch>>"
+## CHECK:  predecessors     "<<BSplit1>>"
 ## CHECK:  successors       "<<BTry>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
@@ -891,6 +1001,16 @@
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit1>>"
+## CHECK:  predecessors     "<<BSplit2>>" "<<BCatch>>"
+## CHECK:  successors       "<<BEnterTry>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit2>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BSplit1>>"
+## CHECK:  Goto
+
 .method public static testCatchLoop(III)I
     .registers 4
 
@@ -918,14 +1038,16 @@
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BCatch:B\d+>>"
-## CHECK:  predecessors     "<<BExitTry1>>" "<<BEnterTry1>>" "<<BEnterTry2:B\d+>>" "<<BExitTry1>>" "<<BExitTry2:B\d+>>"
-## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BEnterTry1>>" "<<BEnterTry2:B\d+>>" "<<BExitTry1>>" "<<BExitTry2:B\d+>>"
+## CHECK:  successors       "<<BSplit1:B\d+>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
 
-## CHECK:  name             "{{B\d+}}"
+## CHECK:  name             "<<BExit>>"
+## CHECK:  predecessors     "<<BReturn>>"
 ## CHECK:  Exit
 
 ## CHECK:  name             "<<BTry2:B\d+>>"
@@ -940,14 +1062,14 @@
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BEnterTry2>>"
-## CHECK:  predecessors     "<<BCatch>>"
+## CHECK:  predecessors     "<<BSplit1>>"
 ## CHECK:  successors       "<<BTry2>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BExitTry1>>"
 ## CHECK:  predecessors     "<<BTry1>>"
-## CHECK:  successors       "<<BCatch>>"
+## CHECK:  successors       "<<BSplit2:B\d+>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
@@ -957,6 +1079,16 @@
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit1>>"
+## CHECK:  predecessors     "<<BSplit2>>" "<<BCatch>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit2>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BSplit1>>"
+## CHECK:  Goto
+
 .method public static testHandlerEdge1(III)I
     .registers 4
 
@@ -977,16 +1109,16 @@
 ## CHECK-START: int Builder.testHandlerEdge2(int, int, int) builder (after)
 
 ## CHECK:  name             "B0"
-## CHECK:  successors       "<<BCatch1:B\d+>>"
+## CHECK:  successors       "<<BSplit4:B\d+>>"
 
-## CHECK:  name             "<<BCatch1>>"
-## CHECK:  predecessors     "B0" "<<BEnterTry2:B\d+>>" "<<BExitTry2:B\d+>>"
-## CHECK:  successors       "<<BEnterTry1:B\d+>>"
+## CHECK:  name             "<<BCatch1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2:B\d+>>" "<<BExitTry2:B\d+>>"
+## CHECK:  successors       "<<BSplit1:B\d+>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BCatch2:B\d+>>"
-## CHECK:  predecessors     "<<BExitTry1:B\d+>>" "<<BEnterTry1>>" "<<BExitTry1>>"
-## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BEnterTry1:B\d+>>" "<<BExitTry1:B\d+>>"
+## CHECK:  successors       "<<BSplit2:B\d+>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
@@ -995,6 +1127,7 @@
 ## CHECK:  Return
 
 ## CHECK:  name             "<<BExit>>"
+## CHECK:  Exit
 
 ## CHECK:  name             "<<BTry1:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry1>>"
@@ -1007,20 +1140,20 @@
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BEnterTry1>>"
-## CHECK:  predecessors     "<<BCatch1>>"
+## CHECK:  predecessors     "<<BSplit1>>"
 ## CHECK:  successors       "<<BTry1>>"
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BEnterTry2>>"
-## CHECK:  predecessors     "<<BCatch2>>"
+## CHECK:  predecessors     "<<BSplit2>>"
 ## CHECK:  successors       "<<BTry2>>"
 ## CHECK:  xhandlers        "<<BCatch1>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BExitTry1>>"
 ## CHECK:  predecessors     "<<BTry1>>"
-## CHECK:  successors       "<<BCatch2>>"
+## CHECK:  successors       "<<BSplit3:B\d+>>"
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:exit
 
@@ -1030,6 +1163,26 @@
 ## CHECK:  xhandlers        "<<BCatch1>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit1>>"
+## CHECK:  predecessors     "<<BSplit4>>" "<<BCatch1>>"
+## CHECK:  successors       "<<BEnterTry1>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit2>>"
+## CHECK:  predecessors     "<<BCatch2>>" "<<BSplit3>>"
+## CHECK:  successors       "<<BEnterTry2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit3>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BSplit2>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit4>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BSplit1>>"
+## CHECK:  Goto
+
 .method public static testHandlerEdge2(III)I
     .registers 4
 
@@ -1053,10 +1206,10 @@
 ## CHECK-START: int Builder.testTryInLoop(int, int) builder (after)
 
 ## CHECK:  name             "B0"
-## CHECK:  successors       "<<BEnterTry:B\d+>>"
+## CHECK:  successors       "<<BSplit1:B\d+>>"
 
 ## CHECK:  name             "<<BTry:B\d+>>"
-## CHECK:  predecessors     "<<BEnterTry>>"
+## CHECK:  predecessors     "<<BEnterTry:B\d+>>"
 ## CHECK:  successors       "<<BExitTry:B\d+>>"
 ## CHECK:  Div
 
@@ -1065,22 +1218,28 @@
 ## CHECK:  successors       "<<BEnterTry>>"
 ## CHECK:  flags            "catch_block"
 
-## CHECK:  name             "<<BExit:B\d+>>"
-## CHECK-NOT: predecessors  "{{B\d+}}"
-## CHECK:  end_block
-
 ## CHECK:  name             "<<BEnterTry>>"
-## CHECK:  predecessors     "B0"
+## CHECK:  predecessors     "<<BSplit1>>"
 ## CHECK:  successors       "<<BTry>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BExitTry>>"
 ## CHECK:  predecessors     "<<BTry>>"
-## CHECK:  successors       "<<BEnterTry>>"
+## CHECK:  successors       "<<BSplit2:B\d+>>"
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BSplit1>>"
+## CHECK:  predecessors     "B0"
+## CHECK:  successors       "<<BEnterTry>>"
+## CHECK:  Goto
+
+## CHECK:  name             "<<BSplit2>>"
+## CHECK:  predecessors     "<<BExitTry>>"
+## CHECK:  successors       "<<BEnterTry>>"
+## CHECK:  Goto
+
 .method public static testTryInLoop(II)I
     .registers 3
 
@@ -1098,9 +1257,10 @@
 # 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>>]
+## CHECK-DAG:     <<M1:i\d+>>  IntConstant -1
+## CHECK-DAG:     <<Res:i\d+>> InvokeStaticOrDirect
+## CHECK-DAG:     <<Phi:i\d+>> Phi [<<Res>>,<<M1>>]
+## CHECK-DAG:                  Return [<<Phi>>]
 
 .method public static testMoveResult_Invoke(III)I
     .registers 3
@@ -1124,16 +1284,16 @@
 # 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>>]
+## CHECK-DAG:     <<Arg1:i\d+>> ParameterValue
+## CHECK-DAG:     <<Arg2:i\d+>> ParameterValue
+## CHECK-DAG:     <<Arg3:i\d+>> ParameterValue
+## CHECK-DAG:     <<Null:l\d+>> NullConstant
+## CHECK-DAG:     <<Res:l\d+>>  NewArray
+## CHECK-DAG:                   ArraySet   [<<Res>>,{{i\d+}},<<Arg1>>]
+## CHECK-DAG:                   ArraySet   [<<Res>>,{{i\d+}},<<Arg2>>]
+## CHECK-DAG:                   ArraySet   [<<Res>>,{{i\d+}},<<Arg3>>]
+## CHECK-DAG:     <<Phi:l\d+>>  Phi [<<Res>>,<<Null>>]
+## CHECK-DAG:                   Return [<<Phi>>]
 
 .method public static testMoveResult_FilledNewArray(III)[I
     .registers 3
diff --git a/test/510-checker-try-catch/smali/SsaBuilder.smali b/test/510-checker-try-catch/smali/SsaBuilder.smali
index a6a5bfe..1fd5fb2 100644
--- a/test/510-checker-try-catch/smali/SsaBuilder.smali
+++ b/test/510-checker-try-catch/smali/SsaBuilder.smali
@@ -19,7 +19,7 @@
 # Tests that catch blocks with both normal and exceptional predecessors are
 # split in two.
 
-## CHECK-START: int SsaBuilder.testSimplifyCatchBlock(int, int, int) ssa_builder (after)
+## CHECK-START: int SsaBuilder.testSimplifyCatchBlock(int, int, int) builder (after)
 
 ## CHECK:      name             "B1"
 ## CHECK-NEXT: from_bci
@@ -62,7 +62,7 @@
 
 # Should be rejected because :catch_all is a loop header.
 
-## CHECK-START: int SsaBuilder.testCatchLoopHeader(int, int, int) ssa_builder (after, bad_state)
+## CHECK-START: int SsaBuilder.testCatchLoopHeader(int, int, int) builder (after, bad_state)
 
 .method public static testCatchLoopHeader(III)I
     .registers 4
@@ -84,7 +84,7 @@
 
 # Tests creation of catch Phis.
 
-## CHECK-START: int SsaBuilder.testPhiCreation(int, int, int) ssa_builder (after)
+## CHECK-START: int SsaBuilder.testPhiCreation(int, int, int) builder (after)
 ## CHECK-DAG:     <<P0:i\d+>>   ParameterValue
 ## CHECK-DAG:     <<P1:i\d+>>   ParameterValue
 ## CHECK-DAG:     <<P2:i\d+>>   ParameterValue
@@ -127,7 +127,7 @@
 # Tests that phi elimination does not remove catch phis where the value does
 # not dominate the phi.
 
-## CHECK-START: int SsaBuilder.testPhiElimination_Domination(int, int) ssa_builder (after)
+## CHECK-START: int SsaBuilder.testPhiElimination_Domination(int, int) builder (after)
 ## CHECK-DAG:     <<P0:i\d+>>   ParameterValue
 ## CHECK-DAG:     <<P1:i\d+>>   ParameterValue
 ## CHECK-DAG:     <<Cst5:i\d+>> IntConstant 5
@@ -168,7 +168,7 @@
 
 # Tests that phi elimination loops until no more phis can be removed.
 
-## CHECK-START: int SsaBuilder.testPhiElimination_Dependencies(int, int, int) ssa_builder (after)
+## CHECK-START: int SsaBuilder.testPhiElimination_Dependencies(int, int, int) builder (after)
 ## CHECK-NOT:     Phi
 
 .method public static testPhiElimination_Dependencies(III)I
@@ -200,10 +200,7 @@
 
 # Tests that dead catch blocks are removed.
 
-## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) ssa_builder (before)
-## CHECK:                       Mul
-
-## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) ssa_builder (after)
+## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) builder (after)
 ## CHECK-DAG:     <<P0:i\d+>>   ParameterValue
 ## CHECK-DAG:     <<P1:i\d+>>   ParameterValue
 ## CHECK-DAG:     <<P2:i\d+>>   ParameterValue
@@ -211,7 +208,7 @@
 ## CHECK-DAG:     <<Add2:i\d+>> Add [<<Add1>>,<<P2>>]
 ## CHECK-DAG:                   Return [<<Add2>>]
 
-## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) ssa_builder (after)
+## CHECK-START: int SsaBuilder.testDeadCatchBlock(int, int, int) builder (after)
 ## CHECK-NOT:                   flags "catch_block"
 ## CHECK-NOT:                   Mul
 
diff --git a/test/517-checker-builder-fallthrough/smali/TestCase.smali b/test/517-checker-builder-fallthrough/smali/TestCase.smali
index bc9502b..946f169 100644
--- a/test/517-checker-builder-fallthrough/smali/TestCase.smali
+++ b/test/517-checker-builder-fallthrough/smali/TestCase.smali
@@ -25,8 +25,8 @@
 
 ## CHECK:  name            "B1"
 ## CHECK:  successors      "B5" "B2"
-## CHECK:  StoreLocal      [v0,<<Const0>>]
-## CHECK:  If
+## CHECK:  <<Cond:z\d+>>   Equal [<<Const0>>,<<Const0>>]
+## CHECK:  If [<<Cond>>]
 
 ## CHECK:  name            "B2"
 ## CHECK:  successors      "B4"
diff --git a/test/523-checker-can-throw-regression/smali/Test.smali b/test/523-checker-can-throw-regression/smali/Test.smali
index 87192ea..4b737a9 100644
--- a/test/523-checker-can-throw-regression/smali/Test.smali
+++ b/test/523-checker-can-throw-regression/smali/Test.smali
@@ -46,8 +46,10 @@
   div-int/2addr p0, p1
   :else
   div-int/2addr p0, p2
-  return p0
   :try_end_2
-  .catchall {:try_start_2 .. :try_end_2} :catchall
+  .catchall {:try_start_2 .. :try_end_2} :catchall2
+
+  :catchall2
+  return p0
 
 .end method
diff --git a/test/529-checker-unresolved/build b/test/529-checker-unresolved/build
index 8c3c4f8..d85035b 100644
--- a/test/529-checker-unresolved/build
+++ b/test/529-checker-unresolved/build
@@ -29,14 +29,12 @@
 mv classes/UnresolvedSuperClass.class classes-ex
 
 if [ ${USE_JACK} = "true" ]; then
-  # Create .jack files from classes generated with javac.
-  ${JILL} classes --output classes.jack
-  ${JILL} classes-ex --output classes-ex.jack
+  jar cf classes.jill.jar -C classes .
+  jar cf classes-ex.jill.jar -C classes-ex .
 
-  # Create DEX files from .jack files.
-  ${JACK} --import classes.jack --output-dex .
+  ${JACK} --import classes.jill.jar --output-dex .
   zip $TEST_NAME.jar classes.dex
-  ${JACK} --import classes-ex.jack --output-dex .
+  ${JACK} --import classes-ex.jill.jar --output-dex .
   zip ${TEST_NAME}-ex.jar classes.dex
 else
   if [ ${NEED_DEX} = "true" ]; then
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index d647683..4d6ea06 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -664,28 +664,19 @@
     System.out.println("testFinalizableByForcingGc() failed to force gc.");
   }
 
-  /// CHECK-START: int Main.testHSelect(boolean) load_store_elimination (before)
+  /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (before)
   /// CHECK: InstanceFieldSet
   /// CHECK: Select
 
-  /// CHECK-START: int Main.testHSelect(boolean) load_store_elimination (after)
+  /// CHECK-START: int Main.$noinline$testHSelect(boolean) load_store_elimination (after)
   /// CHECK: InstanceFieldSet
   /// CHECK: Select
 
   // Test that HSelect creates alias.
-  public static int testHSelect(boolean b) {
-    // Disable inlining.
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-
+  public static int $noinline$testHSelect(boolean b) {
+    if (sFlag) {
+      throw new Error();
+    }
     TestClass obj = new TestClass();
     TestClass obj2 = null;
     obj.i = 0xdead;
@@ -754,6 +745,8 @@
     assertIntEquals(test23(false), 5);
     assertFloatEquals(test24(), 8.0f);
     testFinalizableByForcingGc();
-    assertIntEquals(testHSelect(true), 0xdead);
+    assertIntEquals($noinline$testHSelect(true), 0xdead);
   }
+
+  static boolean sFlag;
 }
diff --git a/test/537-checker-debuggable/smali/TestCase.smali b/test/537-checker-debuggable/smali/TestCase.smali
index 8e6c7ef..5714d3a 100644
--- a/test/537-checker-debuggable/smali/TestCase.smali
+++ b/test/537-checker-debuggable/smali/TestCase.smali
@@ -20,10 +20,10 @@
 # be eliminated in normal mode but kept live in debuggable mode. Test that
 # Checker runs the correct test for each compilation mode.
 
-## CHECK-START: int TestCase.deadPhi(int, int, int) ssa_builder (after)
+## CHECK-START: int TestCase.deadPhi(int, int, int) builder (after)
 ## CHECK-NOT:         Phi
 
-## CHECK-START-DEBUGGABLE: int TestCase.deadPhi(int, int, int) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: int TestCase.deadPhi(int, int, int) builder (after)
 ## CHECK:             Phi
 
 .method public static deadPhi(III)I
diff --git a/test/540-checker-rtp-bug/src/Main.java b/test/540-checker-rtp-bug/src/Main.java
index 9a9f0b6..17b11db 100644
--- a/test/540-checker-rtp-bug/src/Main.java
+++ b/test/540-checker-rtp-bug/src/Main.java
@@ -21,7 +21,7 @@
 }
 
 public class Main {
-  /// CHECK-START: Final Main.testKeepCheckCast(java.lang.Object, boolean) ssa_builder (after)
+  /// CHECK-START: Final Main.testKeepCheckCast(java.lang.Object, boolean) builder (after)
   /// CHECK:    <<Phi:l\d+>>     Phi klass:java.lang.Object
   /// CHECK:    <<Class:l\d+>>   LoadClass
   /// CHECK:                     CheckCast [<<Phi>>,<<Class>>]
@@ -43,7 +43,7 @@
     return (Final) x;
   }
 
-  /// CHECK-START: void Main.testKeepInstanceOf(java.lang.Object, boolean) ssa_builder (after)
+  /// CHECK-START: void Main.testKeepInstanceOf(java.lang.Object, boolean) builder (after)
   /// CHECK:    <<Phi:l\d+>>     Phi klass:java.lang.Object
   /// CHECK:    <<Class:l\d+>>   LoadClass
   /// CHECK:                     InstanceOf [<<Phi>>,<<Class>>]
@@ -65,7 +65,7 @@
     }
   }
 
-  /// CHECK-START: java.lang.String Main.testNoInline(java.lang.Object, boolean) ssa_builder (after)
+  /// CHECK-START: java.lang.String Main.testNoInline(java.lang.Object, boolean) builder (after)
   /// CHECK:    <<Phi:l\d+>>     Phi klass:java.lang.Object
   /// CHECK:    <<NC:l\d+>>      NullCheck [<<Phi>>]
   /// CHECK:    <<Ret:l\d+>>     InvokeVirtual [<<NC>>] method_name:java.lang.Object.toString
diff --git a/test/549-checker-types-merge/src/Main.java b/test/549-checker-types-merge/src/Main.java
index 917073b..51af3cf 100644
--- a/test/549-checker-types-merge/src/Main.java
+++ b/test/549-checker-types-merge/src/Main.java
@@ -38,14 +38,14 @@
 
 public class Main {
 
-  /// CHECK-START: java.lang.Object Main.testMergeNullContant(boolean) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeNullContant(boolean) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:Main
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeNullContant(boolean cond) {
     return cond ? null : new Main();
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassExtendsB) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassExtendsB) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:ClassSuper
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeClasses(boolean cond, ClassExtendsA a, ClassExtendsB b) {
@@ -53,7 +53,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassSuper) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassExtendsA, ClassSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:ClassSuper
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeClasses(boolean cond, ClassExtendsA a, ClassSuper b) {
@@ -61,7 +61,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassSuper, ClassSuper) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassSuper, ClassSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:ClassSuper
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeClasses(boolean cond, ClassSuper a, ClassSuper b) {
@@ -69,7 +69,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassOtherSuper, ClassSuper) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeClasses(boolean, ClassOtherSuper, ClassSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeClasses(boolean cond, ClassOtherSuper a, ClassSuper b) {
@@ -77,7 +77,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassImplementsInterfaceA, InterfaceSuper) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassImplementsInterfaceA, InterfaceSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:InterfaceSuper
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeClassWithInterface(boolean cond, ClassImplementsInterfaceA a, InterfaceSuper b) {
@@ -85,7 +85,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassSuper, InterfaceSuper) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeClassWithInterface(boolean, ClassSuper, InterfaceSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeClassWithInterface(boolean cond, ClassSuper a, InterfaceSuper b) {
@@ -93,7 +93,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceSuper) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:InterfaceSuper
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeInterfaces(boolean cond, InterfaceExtendsA a, InterfaceSuper b) {
@@ -101,7 +101,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceSuper) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:InterfaceSuper
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeInterfaces(boolean cond, InterfaceSuper a, InterfaceSuper b) {
@@ -109,7 +109,7 @@
     return cond ? a : b;
   }
 
-  /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceExtendsB) ssa_builder (after)
+  /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceExtendsA, InterfaceExtendsB) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeInterfaces(boolean cond, InterfaceExtendsA a, InterfaceExtendsB b) {
@@ -117,7 +117,7 @@
     return cond ? a : b;
   }
 
-    /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceOtherSuper) ssa_builder (after)
+    /// CHECK-START: java.lang.Object Main.testMergeInterfaces(boolean, InterfaceSuper, InterfaceOtherSuper) builder (after)
   /// CHECK:      <<Phi:l\d+>>       Phi klass:java.lang.Object
   /// CHECK:                         Return [<<Phi>>]
   private Object testMergeInterfaces(boolean cond, InterfaceSuper a, InterfaceOtherSuper b) {
diff --git a/test/550-checker-regression-wide-store/smali/TestCase.smali b/test/550-checker-regression-wide-store/smali/TestCase.smali
index 7974d56..9133c82 100644
--- a/test/550-checker-regression-wide-store/smali/TestCase.smali
+++ b/test/550-checker-regression-wide-store/smali/TestCase.smali
@@ -25,7 +25,7 @@
 # Test storing into the high vreg of a wide pair. This scenario has runtime
 # behaviour implications so we run it from Main.main.
 
-## CHECK-START: int TestCase.invalidateLow(long) ssa_builder (after)
+## CHECK-START: int TestCase.invalidateLow(long) builder (after)
 ## CHECK-DAG: <<Cst0:i\d+>> IntConstant 0
 ## CHECK-DAG: <<Arg:j\d+>>  ParameterValue
 ## CHECK-DAG: <<Cast:i\d+>> TypeConversion [<<Arg>>]
@@ -53,7 +53,7 @@
 # Test that storing a wide invalidates the value in the high vreg. This
 # cannot be detected from runtime so we only test the environment with Checker.
 
-## CHECK-START: void TestCase.invalidateHigh1(long) ssa_builder (after)
+## CHECK-START: void TestCase.invalidateHigh1(long) builder (after)
 ## CHECK-DAG: <<Arg:j\d+>>  ParameterValue
 ## CHECK-DAG: InvokeStaticOrDirect method_name:java.lang.System.nanoTime env:[[<<Arg>>,_,<<Arg>>,_]]
 
@@ -67,7 +67,7 @@
 
 .end method
 
-## CHECK-START: void TestCase.invalidateHigh2(long) ssa_builder (after)
+## CHECK-START: void TestCase.invalidateHigh2(long) builder (after)
 ## CHECK-DAG: <<Arg:j\d+>>  ParameterValue
 ## CHECK-DAG: InvokeStaticOrDirect method_name:java.lang.System.nanoTime env:[[<<Arg>>,_,_,<<Arg>>,_]]
 
diff --git a/test/551-checker-shifter-operand/src/Main.java b/test/551-checker-shifter-operand/src/Main.java
index decdd1f..8d73d69 100644
--- a/test/551-checker-shifter-operand/src/Main.java
+++ b/test/551-checker-shifter-operand/src/Main.java
@@ -241,13 +241,14 @@
 
   /// CHECK-START-ARM64: void Main.$opt$validateExtendByteInt1(int, byte) instruction_simplifier_arm64 (after)
   /// CHECK:                            Arm64DataProcWithShifterOp
-  /// CHECK:                            Arm64DataProcWithShifterOp
+  /// CHECK-NOT:                        Arm64DataProcWithShifterOp
 
   /// CHECK-START-ARM64: void Main.$opt$validateExtendByteInt1(int, byte) instruction_simplifier_arm64 (after)
   /// CHECK-NOT:                        TypeConversion
 
   public static void $opt$validateExtendByteInt1(int a, byte b) {
     assertIntEquals(a + $noinline$byteToChar (b), a +  (char)b);
+    // Conversions byte->short and short->int are implicit; nothing to merge.
     assertIntEquals(a + $noinline$byteToShort(b), a + (short)b);
   }
 
@@ -266,17 +267,24 @@
   /// CHECK:                            Arm64DataProcWithShifterOp
   /// CHECK:                            Arm64DataProcWithShifterOp
   /// CHECK:                            Arm64DataProcWithShifterOp
+  /// CHECK:                            Arm64DataProcWithShifterOp
+  /// CHECK:                            Arm64DataProcWithShifterOp
+  /// CHECK-NOT:                        Arm64DataProcWithShifterOp
 
   /// CHECK-START-ARM64: void Main.$opt$validateExtendByteLong(long, byte) instruction_simplifier_arm64 (after)
   /// CHECK:                            TypeConversion
-  /// CHECK:                            TypeConversion
   /// CHECK-NOT:                        TypeConversion
 
   public static void $opt$validateExtendByteLong(long a, byte b) {
-    // The first two tests have a type conversion.
+    // In each of the following tests, there will be a merge on the LHS.
+
+    // The first test has an explicit byte->char conversion on RHS,
+    // followed by a conversion that is merged with the Add.
     assertLongEquals(a + $noinline$byteToChar (b), a +  (char)b);
+    // Since conversions byte->short and byte->int are implicit, the RHS
+    // for the two tests below is the same and one is eliminated by GVN.
+    // The other is then merged to a shifter operand instruction.
     assertLongEquals(a + $noinline$byteToShort(b), a + (short)b);
-    // This test does not because the conversion to `int` is optimized away.
     assertLongEquals(a + $noinline$byteToInt  (b), a +  (int)b);
   }
 
diff --git a/test/552-checker-primitive-typeprop/smali/ArrayGet.smali b/test/552-checker-primitive-typeprop/smali/ArrayGet.smali
index 042fa0c..de32290 100644
--- a/test/552-checker-primitive-typeprop/smali/ArrayGet.smali
+++ b/test/552-checker-primitive-typeprop/smali/ArrayGet.smali
@@ -19,10 +19,10 @@
 # Test phi with fixed-type ArrayGet as an input and a matching second input.
 # The phi should be typed accordingly.
 
-## CHECK-START: void ArrayGet.matchingFixedType(float[], float) ssa_builder (after)
+## CHECK-START: void ArrayGet.matchingFixedType(float[], float) builder (after)
 ## CHECK-NOT: Phi
 
-## CHECK-START-DEBUGGABLE: void ArrayGet.matchingFixedType(float[], float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void ArrayGet.matchingFixedType(float[], float) builder (after)
 ## CHECK-DAG:  <<Arg1:f\d+>> ParameterValue
 ## CHECK-DAG:  <<Aget:f\d+>> ArrayGet
 ## CHECK-DAG:  {{f\d+}}      Phi [<<Aget>>,<<Arg1>>] reg:0
@@ -49,10 +49,10 @@
 # Test phi with fixed-type ArrayGet as an input and a conflicting second input.
 # The phi should be eliminated due to the conflict.
 
-## CHECK-START: void ArrayGet.conflictingFixedType(float[], int) ssa_builder (after)
+## CHECK-START: void ArrayGet.conflictingFixedType(float[], int) builder (after)
 ## CHECK-NOT: Phi
 
-## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFixedType(float[], int) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFixedType(float[], int) builder (after)
 ## CHECK-NOT: Phi
 .method public static conflictingFixedType([FI)V
   .registers 8
@@ -76,13 +76,13 @@
 # Same test as the one above, only this time tests that type of ArrayGet is not
 # changed.
 
-## CHECK-START: void ArrayGet.conflictingFixedType2(int[], float) ssa_builder (after)
+## CHECK-START: void ArrayGet.conflictingFixedType2(int[], float) builder (after)
 ## CHECK-NOT: Phi
 
-## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFixedType2(int[], float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFixedType2(int[], float) builder (after)
 ## CHECK-NOT: Phi
 
-## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFixedType2(int[], float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFixedType2(int[], float) builder (after)
 ## CHECK:     {{i\d+}} ArrayGet
 .method public static conflictingFixedType2([IF)V
   .registers 8
@@ -107,10 +107,10 @@
 # Test phi with free-type ArrayGet as an input and a matching second input.
 # The phi should be typed accordingly.
 
-## CHECK-START: void ArrayGet.matchingFreeType(float[], float) ssa_builder (after)
+## CHECK-START: void ArrayGet.matchingFreeType(float[], float) builder (after)
 ## CHECK-NOT: Phi
 
-## CHECK-START-DEBUGGABLE: void ArrayGet.matchingFreeType(float[], float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void ArrayGet.matchingFreeType(float[], float) builder (after)
 ## CHECK-DAG:  <<Arg1:f\d+>> ParameterValue
 ## CHECK-DAG:  <<Aget:f\d+>> ArrayGet
 ## CHECK-DAG:                ArraySet [{{l\d+}},{{i\d+}},<<Aget>>]
@@ -139,10 +139,10 @@
 # The phi will be kept and typed according to the second input despite the
 # conflict.
 
-## CHECK-START: void ArrayGet.conflictingFreeType(int[], float) ssa_builder (after)
+## CHECK-START: void ArrayGet.conflictingFreeType(int[], float) builder (after)
 ## CHECK-NOT: Phi
 
-## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFreeType(int[], float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void ArrayGet.conflictingFreeType(int[], float) builder (after)
 ## CHECK-NOT: Phi
 
 .method public static conflictingFreeType([IF)V
@@ -169,7 +169,7 @@
 # case uses ArrayGet indirectly through two phis. It also creates an unused
 # conflicting phi which should not be preserved.
 
-## CHECK-START: void ArrayGet.conflictingPhiUses(int[], float, boolean, boolean, boolean) ssa_builder (after)
+## CHECK-START: void ArrayGet.conflictingPhiUses(int[], float, boolean, boolean, boolean) builder (after)
 ## CHECK:         InvokeStaticOrDirect env:[[{{i\d+}},{{i\d+}},_,{{i\d+}},{{.*}}
 
 .method public static conflictingPhiUses([IFZZZ)V
@@ -209,10 +209,10 @@
 # another. The situation needs to be resolved so that only one instruction
 # remains.
 
-## CHECK-START: void ArrayGet.typedVsUntypedPhiUse(float[], float, boolean, boolean) ssa_builder (after)
+## CHECK-START: void ArrayGet.typedVsUntypedPhiUse(float[], float, boolean, boolean) builder (after)
 ## CHECK:         {{f\d+}} ArrayGet
 
-## CHECK-START: void ArrayGet.typedVsUntypedPhiUse(float[], float, boolean, boolean) ssa_builder (after)
+## CHECK-START: void ArrayGet.typedVsUntypedPhiUse(float[], float, boolean, boolean) builder (after)
 ## CHECK-NOT:     {{i\d+}} ArrayGet
 
 .method public static typedVsUntypedPhiUse([FFZZ)V
diff --git a/test/552-checker-primitive-typeprop/smali/ArraySet.smali b/test/552-checker-primitive-typeprop/smali/ArraySet.smali
index 57d8606..087460a 100644
--- a/test/552-checker-primitive-typeprop/smali/ArraySet.smali
+++ b/test/552-checker-primitive-typeprop/smali/ArraySet.smali
@@ -19,7 +19,7 @@
 # Note that the input is a Phi to make sure primitive type propagation is re-run
 # on the replaced inputs.
 
-## CHECK-START: void ArraySet.ambiguousSet(int[], float[], boolean) ssa_builder (after)
+## CHECK-START: void ArraySet.ambiguousSet(int[], float[], boolean) builder (after)
 ## CHECK-DAG:     <<IntArray:l\d+>>    ParameterValue klass:int[]
 ## CHECK-DAG:     <<IntA:i\d+>>        IntConstant 0
 ## CHECK-DAG:     <<IntB:i\d+>>        IntConstant 1073741824
diff --git a/test/552-checker-primitive-typeprop/smali/SsaBuilder.smali b/test/552-checker-primitive-typeprop/smali/SsaBuilder.smali
index 395feaa..0d067ed 100644
--- a/test/552-checker-primitive-typeprop/smali/SsaBuilder.smali
+++ b/test/552-checker-primitive-typeprop/smali/SsaBuilder.smali
@@ -22,7 +22,7 @@
 # otherwise running the code with an array short enough to throw will crash at
 # runtime because v0 is undefined.
 
-## CHECK-START: int SsaBuilder.environmentPhi(boolean, int[]) ssa_builder (after)
+## CHECK-START: int SsaBuilder.environmentPhi(boolean, int[]) builder (after)
 ## CHECK-DAG:     <<Cst0:f\d+>>  FloatConstant 0
 ## CHECK-DAG:     <<Cst2:f\d+>>  FloatConstant 2
 ## CHECK-DAG:     <<Phi:f\d+>>   Phi [<<Cst0>>,<<Cst2>>]
diff --git a/test/552-checker-primitive-typeprop/smali/TypePropagation.smali b/test/552-checker-primitive-typeprop/smali/TypePropagation.smali
index 58682a1..d34e43e 100644
--- a/test/552-checker-primitive-typeprop/smali/TypePropagation.smali
+++ b/test/552-checker-primitive-typeprop/smali/TypePropagation.smali
@@ -15,7 +15,7 @@
 .class public LTypePropagation;
 .super Ljava/lang/Object;
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.mergeDeadPhi(boolean, boolean, int, float, float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.mergeDeadPhi(boolean, boolean, int, float, float) builder (after)
 ## CHECK-NOT: Phi
 .method public static mergeDeadPhi(ZZIFF)V
   .registers 8
@@ -34,7 +34,7 @@
   return-void
 .end method
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.mergeSameType(boolean, int, int) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.mergeSameType(boolean, int, int) builder (after)
 ## CHECK:     {{i\d+}} Phi
 ## CHECK-NOT:          Phi
 .method public static mergeSameType(ZII)V
@@ -47,7 +47,7 @@
   return-void
 .end method
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.mergeVoidInput(boolean, boolean, int, int) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.mergeVoidInput(boolean, boolean, int, int) builder (after)
 ## CHECK:     {{i\d+}} Phi
 ## CHECK:     {{i\d+}} Phi
 ## CHECK-NOT:          Phi
@@ -64,7 +64,7 @@
   return-void
 .end method
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.mergeDifferentSize(boolean, int, long) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.mergeDifferentSize(boolean, int, long) builder (after)
 ## CHECK-NOT: Phi
 .method public static mergeDifferentSize(ZIJ)V
   .registers 8
@@ -76,7 +76,7 @@
   return-void
 .end method
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.mergeRefFloat(boolean, float, java.lang.Object) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.mergeRefFloat(boolean, float, java.lang.Object) builder (after)
 ## CHECK-NOT: Phi
 .method public static mergeRefFloat(ZFLjava/lang/Object;)V
   .registers 8
@@ -88,7 +88,7 @@
   return-void
 .end method
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.mergeIntFloat_Success(boolean, float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.mergeIntFloat_Success(boolean, float) builder (after)
 ## CHECK:     {{f\d+}} Phi
 ## CHECK-NOT:          Phi
 .method public static mergeIntFloat_Success(ZF)V
@@ -101,7 +101,7 @@
   return-void
 .end method
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.mergeIntFloat_Fail(boolean, int, float) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.mergeIntFloat_Fail(boolean, int, float) builder (after)
 ## CHECK-NOT: Phi
 .method public static mergeIntFloat_Fail(ZIF)V
   .registers 8
@@ -113,7 +113,7 @@
   return-void
 .end method
 
-## CHECK-START-DEBUGGABLE: void TypePropagation.updateAllUsersOnConflict(boolean, boolean, int, float, int) ssa_builder (after)
+## CHECK-START-DEBUGGABLE: void TypePropagation.updateAllUsersOnConflict(boolean, boolean, int, float, int) builder (after)
 ## CHECK-NOT: Phi
 .method public static updateAllUsersOnConflict(ZZIFI)V
   .registers 8
diff --git a/test/554-checker-rtp-checkcast/src/Main.java b/test/554-checker-rtp-checkcast/src/Main.java
index 607f71a..5bf766f 100644
--- a/test/554-checker-rtp-checkcast/src/Main.java
+++ b/test/554-checker-rtp-checkcast/src/Main.java
@@ -19,7 +19,7 @@
 
   public static Object returnIntArray() { return new int[10]; }
 
-  /// CHECK-START: void Main.boundTypeForMergingPhi() ssa_builder (after)
+  /// CHECK-START: void Main.boundTypeForMergingPhi() builder (after)
   /// CHECK-DAG:              ArraySet [<<NC:l\d+>>,{{i\d+}},{{i\d+}}]
   /// CHECK-DAG:     <<NC>>   NullCheck [<<Phi:l\d+>>]
   /// CHECK-DAG:     <<Phi>>  Phi klass:int[]
@@ -32,7 +32,7 @@
     array[0] = 14;
   }
 
-  /// CHECK-START: void Main.boundTypeForLoopPhi() ssa_builder (after)
+  /// CHECK-START: void Main.boundTypeForLoopPhi() builder (after)
   /// CHECK-DAG:              ArraySet [<<NC:l\d+>>,{{i\d+}},{{i\d+}}]
   /// CHECK-DAG:     <<NC>>   NullCheck [<<Phi:l\d+>>]
   /// CHECK-DAG:     <<Phi>>  Phi klass:int[]
@@ -50,7 +50,7 @@
     array[0] = 14;
   }
 
-  /// CHECK-START: void Main.boundTypeForCatchPhi() ssa_builder (after)
+  /// CHECK-START: void Main.boundTypeForCatchPhi() builder (after)
   /// CHECK-DAG:              ArraySet [<<NC:l\d+>>,{{i\d+}},{{i\d+}}]
   /// CHECK-DAG:     <<NC>>   NullCheck [<<Phi:l\d+>>]
   /// CHECK-DAG:     <<Phi>>  Phi is_catch_phi:true klass:int[]
diff --git a/test/555-checker-regression-x86const/build b/test/555-checker-regression-x86const/build
new file mode 100644
index 0000000..09dcc36
--- /dev/null
+++ b/test/555-checker-regression-x86const/build
@@ -0,0 +1,46 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# We can't use src-ex testing infrastructure because src and src-ex are compiled
+# with javac independetely and can't share code (without reflection).
+
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+
+mkdir classes-ex
+mv classes/UnresolvedClass.class classes-ex
+
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes-ex --output classes-ex.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
+  zip $TEST_NAME.jar classes.dex
+  ${JACK} --import classes-ex.jack --output-dex .
+  zip ${TEST_NAME}-ex.jar classes.dex
+else
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+    zip $TEST_NAME.jar classes.dex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+    zip ${TEST_NAME}-ex.jar classes.dex
+  fi
+fi
diff --git a/test/555-checker-regression-x86const/expected.txt b/test/555-checker-regression-x86const/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/555-checker-regression-x86const/expected.txt
diff --git a/test/555-checker-regression-x86const/info.txt b/test/555-checker-regression-x86const/info.txt
new file mode 100644
index 0000000..c4037fa
--- /dev/null
+++ b/test/555-checker-regression-x86const/info.txt
@@ -0,0 +1,2 @@
+Check that X86 FP constant-area handling handles intrinsics with CurrentMethod
+on the call.
diff --git a/test/555-checker-regression-x86const/run b/test/555-checker-regression-x86const/run
new file mode 100644
index 0000000..63fdb8c
--- /dev/null
+++ b/test/555-checker-regression-x86const/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.
+
+# Use secondary switch to add secondary dex file to class path.
+exec ${RUN} "${@}" --secondary
diff --git a/test/555-checker-regression-x86const/src/Main.java b/test/555-checker-regression-x86const/src/Main.java
new file mode 100644
index 0000000..914cfde
--- /dev/null
+++ b/test/555-checker-regression-x86const/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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 extends UnresolvedClass {
+
+  /// CHECK-START: float Main.callAbs(float) register (before)
+  /// CHECK:       <<CurrentMethod:[ij]\d+>> CurrentMethod
+  /// CHECK:       <<ParamValue:f\d+>> ParameterValue
+  /// CHECK:       InvokeStaticOrDirect [<<ParamValue>>,<<CurrentMethod>>] method_name:java.lang.Math.abs
+  static public float callAbs(float f) {
+    // An intrinsic invoke in a method that has unresolved references will still
+    // have a CurrentMethod as an argument.  The X86 pc_relative_fixups_x86 pass
+    // must be able to handle Math.abs invokes that have a CurrentMethod, as both
+    // the CurrentMethod and the HX86LoadFromConstantTable (for the bitmask)
+    // expect to be in the 'SpecialInputIndex' input index.
+    return Math.abs(f);
+  }
+
+  static public void main(String[] args) {
+    expectEquals(callAbs(-6.5f), 6.5f);
+  }
+
+  public static void expectEquals(float expected, float result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
diff --git a/test/555-checker-regression-x86const/src/Unresolved.java b/test/555-checker-regression-x86const/src/Unresolved.java
new file mode 100644
index 0000000..e98bdbf
--- /dev/null
+++ b/test/555-checker-regression-x86const/src/Unresolved.java
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2016 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 UnresolvedClass {
+}
diff --git a/test/557-checker-ref-equivalent/smali/TestCase.smali b/test/557-checker-ref-equivalent/smali/TestCase.smali
index 2472957..1347554 100644
--- a/test/557-checker-ref-equivalent/smali/TestCase.smali
+++ b/test/557-checker-ref-equivalent/smali/TestCase.smali
@@ -16,7 +16,7 @@
 
 .super Ljava/lang/Object;
 
-## CHECK-START: void TestCase.testIntRefEquivalent() ssa_builder (after)
+## CHECK-START: void TestCase.testIntRefEquivalent() builder (after)
 ## CHECK-NOT: Phi
 .method public static testIntRefEquivalent()V
     .registers 4
diff --git a/test/557-checker-ref-equivalent/src/Main.java b/test/557-checker-ref-equivalent/src/Main.java
index a970af5..9323757 100644
--- a/test/557-checker-ref-equivalent/src/Main.java
+++ b/test/557-checker-ref-equivalent/src/Main.java
@@ -16,7 +16,7 @@
 
 public class Main {
 
-  /// CHECK-START: void Main.testRedundantPhiCycle(boolean) ssa_builder (after)
+  /// CHECK-START: void Main.testRedundantPhiCycle(boolean) builder (after)
   /// CHECK-NOT:  Phi
   private void testRedundantPhiCycle(boolean cond) {
     Object o = null;
@@ -28,7 +28,7 @@
     }
   }
 
-  /// CHECK-START: void Main.testLoopPhisWithNullAndCrossUses(boolean) ssa_builder (after)
+  /// CHECK-START: void Main.testLoopPhisWithNullAndCrossUses(boolean) builder (after)
   /// CHECK-NOT:  Phi
   private void testLoopPhisWithNullAndCrossUses(boolean cond) {
     Main a = null;
diff --git a/test/559-checker-irreducible-loop/smali/IrreducibleLoop.smali b/test/559-checker-irreducible-loop/smali/IrreducibleLoop.smali
index 971ad84..7ce60a3 100644
--- a/test/559-checker-irreducible-loop/smali/IrreducibleLoop.smali
+++ b/test/559-checker-irreducible-loop/smali/IrreducibleLoop.smali
@@ -323,7 +323,7 @@
 #      -       /                 \-
 # irreducible_loop_back_edge    loop_within_back_edge
 #
-## CHECK-START: void IrreducibleLoop.analyze1(int) ssa_builder (after)
+## CHECK-START: void IrreducibleLoop.analyze1(int) builder (after)
 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:false
 .method public static analyze1(I)V
@@ -371,7 +371,7 @@
 # exit          \-         /
 #          irreducible_loop_body
 #
-## CHECK-START: void IrreducibleLoop.analyze2(int) ssa_builder (after)
+## CHECK-START: void IrreducibleLoop.analyze2(int) builder (after)
 ## CHECK-DAG: Goto outer_loop:none irreducible:false
 ## CHECK-DAG: Goto outer_loop:none irreducible:true
 .method public static analyze2(I)V
@@ -418,7 +418,7 @@
 #             |
 #           exit
 #
-## CHECK-START: void IrreducibleLoop.analyze3(int) ssa_builder (after)
+## CHECK-START: void IrreducibleLoop.analyze3(int) builder (after)
 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true
 .method public static analyze3(I)V
@@ -467,7 +467,7 @@
 #             |
 #           exit
 #
-## CHECK-START: void IrreducibleLoop.analyze4(int) ssa_builder (after)
+## CHECK-START: void IrreducibleLoop.analyze4(int) builder (after)
 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true
 .method public static analyze4(I)V
@@ -519,7 +519,7 @@
 #                    |
 #                   exit
 #
-## CHECK-START: void IrreducibleLoop.analyze5(int) ssa_builder (after)
+## CHECK-START: void IrreducibleLoop.analyze5(int) builder (after)
 ## CHECK-DAG: Goto loop:<<OuterLoop:B\d+>> outer_loop:none irreducible:true
 ## CHECK-DAG: Goto outer_loop:<<OuterLoop>> irreducible:true
 .method public static analyze5(I)V
diff --git a/test/559-checker-rtp-ifnotnull/src/Main.java b/test/559-checker-rtp-ifnotnull/src/Main.java
index 8f40129..2dc5666 100644
--- a/test/559-checker-rtp-ifnotnull/src/Main.java
+++ b/test/559-checker-rtp-ifnotnull/src/Main.java
@@ -17,7 +17,7 @@
 
 public class Main {
 
-  /// CHECK-START: void Main.boundTypeForIfNotNull() ssa_builder (after)
+  /// CHECK-START: void Main.boundTypeForIfNotNull() builder (after)
   /// CHECK-DAG:     <<Method:(i|j)\d+>>  CurrentMethod
   /// CHECK-DAG:     <<Null:l\d+>>        NullConstant
   /// CHECK-DAG:     <<Cst5:i\d+>>        IntConstant 5
diff --git a/test/562-bce-preheader/src/Main.java b/test/562-bce-preheader/src/Main.java
index 8de0533..8b527b4 100644
--- a/test/562-bce-preheader/src/Main.java
+++ b/test/562-bce-preheader/src/Main.java
@@ -70,6 +70,26 @@
     return acc;
   }
 
+  /**
+   * An artificial example with an inconsistent phi structure during
+   * dynamic bce that is corrected afterwards. Note that only the last
+   * assignment is really live, but the other statements set up an
+   * interesting phi structure.
+   */
+  private static int doit(int[] z) {
+    int a = 0;
+    for (int i = 0; i < 10; ++i) {
+      for (int j = i; j < 10; ++j) {
+        a = z[i];
+        for (int k = 0; k < 10; ++k) {
+          a += z[k];
+          a = z[i];
+        }
+      }
+    }
+    return a;
+  }
+
   public static void main(String args[]) {
     int[][] x = new int[2][2];
     int y;
@@ -96,6 +116,9 @@
     expectEquals(26, foo(a, b,  2));
     expectEquals(38, foo(a, b,  3));
 
+    int[] z = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+    expectEquals(10, doit(z));
+
     System.out.println("passed");
   }
 
diff --git a/test/565-checker-condition-liveness/src/Main.java b/test/565-checker-condition-liveness/src/Main.java
index a811e5b..dc4cb76 100644
--- a/test/565-checker-condition-liveness/src/Main.java
+++ b/test/565-checker-condition-liveness/src/Main.java
@@ -16,6 +16,24 @@
 
 public class Main {
 
+  /// CHECK-START-X86: int Main.p(float) liveness (after)
+  /// CHECK:         <<Arg:f\d+>>  ParameterValue uses:[<<UseInput:\d+>>]
+  /// CHECK-DAG:     <<Five:f\d+>> FloatConstant 5 uses:[<<UseInput>>]
+  /// CHECK-DAG:     <<Zero:i\d+>> IntConstant 0
+  /// CHECK-DAG:     <<MinusOne:i\d+>> IntConstant -1 uses:[<<UseInput>>]
+  /// CHECK:         <<Base:i\d+>> X86ComputeBaseMethodAddress uses:[<<UseInput>>]
+  /// CHECK-NEXT:    <<Load:f\d+>> X86LoadFromConstantTable [<<Base>>,<<Five>>]
+  /// CHECK-NEXT:    <<Cond:z\d+>> LessThanOrEqual [<<Arg>>,<<Load>>]
+  /// CHECK-NEXT:                  Select [<<Zero>>,<<MinusOne>>,<<Cond>>] liveness:<<LivSel:\d+>>
+  /// CHECK-EVAL:    <<UseInput>> == <<LivSel>> + 1
+
+  public static int p(float arg) {
+    if (arg > 5.0f) {
+      return 0;
+    }
+    return -1;
+  }
+
   /// CHECK-START: void Main.main(java.lang.String[]) liveness (after)
   /// CHECK:         <<X:i\d+>>    ArrayLength uses:[<<UseInput:\d+>>]
   /// CHECK:         <<Y:i\d+>>    StaticFieldGet uses:[<<UseInput>>]
diff --git a/test/565-checker-doublenegbitwise/src/Main.java b/test/565-checker-doublenegbitwise/src/Main.java
index d681ad7..41af97b 100644
--- a/test/565-checker-doublenegbitwise/src/Main.java
+++ b/test/565-checker-doublenegbitwise/src/Main.java
@@ -37,7 +37,7 @@
 
   // Note: before the instruction_simplifier pass, Xor's are used instead of
   // Not's (the simplification happens during the same pass).
-  /// CHECK-START-ARM64: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (before)
+  /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (before)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK:       <<CstM1:i\d+>>       IntConstant -1
@@ -46,16 +46,18 @@
   /// CHECK:       <<And:i\d+>>         And [<<Not1>>,<<Not2>>]
   /// CHECK:                            Return [<<And>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK:       <<Or:i\d+>>          Or [<<P1>>,<<P2>>]
   /// CHECK:       <<Not:i\d+>>         Not [<<Or>>]
   /// CHECK:                            Return [<<Not>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
   /// CHECK:                            Not
   /// CHECK-NOT:                        Not
+
+  /// CHECK-START: int Main.$opt$noinline$andToOr(int, int) instruction_simplifier (after)
   /// CHECK-NOT:                        And
 
   public static int $opt$noinline$andToOr(int a, int b) {
@@ -64,12 +66,49 @@
   }
 
   /**
+   * Test transformation of Not/Not/And into Or/Not for boolean negations.
+   * Note that the graph before this instruction simplification pass does not
+   * contain `HBooleanNot` instructions. This is because this transformation
+   * follows the optimization of `HSelect` to `HBooleanNot` occurring in the
+   * same pass.
+   */
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (before)
+  /// CHECK:       <<P1:z\d+>>          ParameterValue
+  /// CHECK:       <<P2:z\d+>>          ParameterValue
+  /// CHECK-DAG:   <<Const0:i\d+>>      IntConstant 0
+  /// CHECK-DAG:   <<Const1:i\d+>>      IntConstant 1
+  /// CHECK:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
+  /// CHECK:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
+  /// CHECK:       <<And:i\d+>>         And [<<Select2>>,<<Select1>>]
+  /// CHECK:                            Return [<<And>>]
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK:       <<Cond1:z\d+>>       ParameterValue
+  /// CHECK:       <<Cond2:z\d+>>       ParameterValue
+  /// CHECK:       <<Or:i\d+>>          Or [<<Cond2>>,<<Cond1>>]
+  /// CHECK:       <<BooleanNot:z\d+>>  BooleanNot [<<Or>>]
+  /// CHECK:                            Return [<<BooleanNot>>]
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK:                            BooleanNot
+  /// CHECK-NOT:                        BooleanNot
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanAndToOr(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-NOT:                        And
+
+  public static boolean $opt$noinline$booleanAndToOr(boolean a, boolean b) {
+    if (doThrow) throw new Error();
+    return !a & !b;
+  }
+
+  /**
    * Test transformation of Not/Not/Or into And/Not.
    */
 
   // See note above.
   // The second Xor has its arguments reversed for no obvious reason.
-  /// CHECK-START-ARM64: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (before)
+  /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (before)
   /// CHECK:       <<P1:j\d+>>          ParameterValue
   /// CHECK:       <<P2:j\d+>>          ParameterValue
   /// CHECK:       <<CstM1:j\d+>>       LongConstant -1
@@ -78,16 +117,18 @@
   /// CHECK:       <<Or:j\d+>>          Or [<<Not1>>,<<Not2>>]
   /// CHECK:                            Return [<<Or>>]
 
-  /// CHECK-START-ARM64: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
+  /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
   /// CHECK:       <<P1:j\d+>>          ParameterValue
   /// CHECK:       <<P2:j\d+>>          ParameterValue
   /// CHECK:       <<And:j\d+>>         And [<<P1>>,<<P2>>]
   /// CHECK:       <<Not:j\d+>>         Not [<<And>>]
   /// CHECK:                            Return [<<Not>>]
 
-  /// CHECK-START-ARM64: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
+  /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
   /// CHECK:                            Not
   /// CHECK-NOT:                        Not
+
+  /// CHECK-START: long Main.$opt$noinline$orToAnd(long, long) instruction_simplifier (after)
   /// CHECK-NOT:                        Or
 
   public static long $opt$noinline$orToAnd(long a, long b) {
@@ -96,13 +137,50 @@
   }
 
   /**
+   * Test transformation of Not/Not/Or into Or/And for boolean negations.
+   * Note that the graph before this instruction simplification pass does not
+   * contain `HBooleanNot` instructions. This is because this transformation
+   * follows the optimization of `HSelect` to `HBooleanNot` occurring in the
+   * same pass.
+   */
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (before)
+  /// CHECK:       <<P1:z\d+>>          ParameterValue
+  /// CHECK:       <<P2:z\d+>>          ParameterValue
+  /// CHECK-DAG:   <<Const0:i\d+>>      IntConstant 0
+  /// CHECK-DAG:   <<Const1:i\d+>>      IntConstant 1
+  /// CHECK:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
+  /// CHECK:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
+  /// CHECK:       <<Or:i\d+>>          Or [<<Select2>>,<<Select1>>]
+  /// CHECK:                            Return [<<Or>>]
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK:       <<Cond1:z\d+>>       ParameterValue
+  /// CHECK:       <<Cond2:z\d+>>       ParameterValue
+  /// CHECK:       <<And:i\d+>>         And [<<Cond2>>,<<Cond1>>]
+  /// CHECK:       <<BooleanNot:z\d+>>  BooleanNot [<<And>>]
+  /// CHECK:                            Return [<<BooleanNot>>]
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK:                            BooleanNot
+  /// CHECK-NOT:                        BooleanNot
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanOrToAnd(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-NOT:                        Or
+
+  public static boolean $opt$noinline$booleanOrToAnd(boolean a, boolean b) {
+    if (doThrow) throw new Error();
+    return !a | !b;
+  }
+
+  /**
    * Test that the transformation copes with inputs being separated from the
    * bitwise operations.
    * This is a regression test. The initial logic was inserting the new bitwise
    * operation incorrectly.
    */
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (before)
+  /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (before)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK-DAG:   <<Cst1:i\d+>>        IntConstant 1
@@ -114,7 +192,7 @@
   /// CHECK:       <<Or:i\d+>>          Or [<<Not1>>,<<Not2>>]
   /// CHECK:                            Return [<<Or>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK:       <<Cst1:i\d+>>        IntConstant 1
@@ -124,9 +202,11 @@
   /// CHECK:       <<Not:i\d+>>         Not [<<And>>]
   /// CHECK:                            Return [<<Not>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
   /// CHECK:                            Not
   /// CHECK-NOT:                        Not
+
+  /// CHECK-START: int Main.$opt$noinline$regressInputsAway(int, int) instruction_simplifier (after)
   /// CHECK-NOT:                        Or
 
   public static int $opt$noinline$regressInputsAway(int a, int b) {
@@ -143,7 +223,7 @@
    */
 
   // See first note above.
-  /// CHECK-START-ARM64: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (before)
+  /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (before)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK:       <<CstM1:i\d+>>       IntConstant -1
@@ -152,13 +232,13 @@
   /// CHECK:       <<Xor:i\d+>>         Xor [<<Not1>>,<<Not2>>]
   /// CHECK:                            Return [<<Xor>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK:       <<Xor:i\d+>>         Xor [<<P1>>,<<P2>>]
   /// CHECK:                            Return [<<Xor>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$notXorToXor(int, int) instruction_simplifier (after)
   /// CHECK-NOT:                        Not
 
   public static int $opt$noinline$notXorToXor(int a, int b) {
@@ -167,10 +247,42 @@
   }
 
   /**
+   * Test transformation of Not/Not/Xor into Xor for boolean negations.
+   * Note that the graph before this instruction simplification pass does not
+   * contain `HBooleanNot` instructions. This is because this transformation
+   * follows the optimization of `HSelect` to `HBooleanNot` occurring in the
+   * same pass.
+   */
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (before)
+  /// CHECK:       <<P1:z\d+>>          ParameterValue
+  /// CHECK:       <<P2:z\d+>>          ParameterValue
+  /// CHECK-DAG:   <<Const0:i\d+>>      IntConstant 0
+  /// CHECK-DAG:   <<Const1:i\d+>>      IntConstant 1
+  /// CHECK:       <<Select1:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P1>>]
+  /// CHECK:       <<Select2:i\d+>>     Select [<<Const1>>,<<Const0>>,<<P2>>]
+  /// CHECK:       <<Xor:i\d+>>         Xor [<<Select2>>,<<Select1>>]
+  /// CHECK:                            Return [<<Xor>>]
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK:       <<Cond1:z\d+>>       ParameterValue
+  /// CHECK:       <<Cond2:z\d+>>       ParameterValue
+  /// CHECK:       <<Xor:i\d+>>         Xor [<<Cond2>>,<<Cond1>>]
+  /// CHECK:                            Return [<<Xor>>]
+
+  /// CHECK-START: boolean Main.$opt$noinline$booleanNotXorToXor(boolean, boolean) instruction_simplifier_after_bce (after)
+  /// CHECK-NOT:                        BooleanNot
+
+  public static boolean $opt$noinline$booleanNotXorToXor(boolean a, boolean b) {
+    if (doThrow) throw new Error();
+    return !a ^ !b;
+  }
+
+  /**
    * Check that no transformation is done when one Not has multiple uses.
    */
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (before)
+  /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (before)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK:       <<CstM1:i\d+>>       IntConstant -1
@@ -182,7 +294,7 @@
   /// CHECK:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
   /// CHECK:                            Return [<<Add>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
   /// CHECK:       <<P1:i\d+>>          ParameterValue
   /// CHECK:       <<P2:i\d+>>          ParameterValue
   /// CHECK:       <<One:i\d+>>         IntConstant 1
@@ -193,7 +305,7 @@
   /// CHECK:       <<Add:i\d+>>         Add [<<And2>>,<<And1>>]
   /// CHECK:                            Return [<<Add>>]
 
-  /// CHECK-START-ARM64: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
+  /// CHECK-START: int Main.$opt$noinline$notMultipleUses(int, int) instruction_simplifier (after)
   /// CHECK-NOT:                        Or
 
   public static int $opt$noinline$notMultipleUses(int a, int b) {
diff --git a/test/566-checker-codegen-select/src/Main.java b/test/566-checker-codegen-select/src/Main.java
index edb31e6..3a1b3fc 100644
--- a/test/566-checker-codegen-select/src/Main.java
+++ b/test/566-checker-codegen-select/src/Main.java
@@ -45,6 +45,13 @@
   /// CHECK:             LessThanOrEqual
   /// CHECK-NEXT:        Select
 
+  // Check that we generate CMOV for long on x86_64.
+  /// CHECK-START-X86_64: long Main.$noinline$longSelect_Constant(long) disassembly (after)
+  /// CHECK:             LessThanOrEqual
+  /// CHECK-NEXT:        Select
+  /// CHECK:             cmpq
+  /// CHECK:             cmovle/ngq
+
   public long $noinline$longSelect_Constant(long param) {
     if (doThrow) { throw new Error(); }
     long val_true = longB;
@@ -52,12 +59,34 @@
     return (param > 3L) ? val_true : val_false;
   }
 
+  // Check that we generate CMOV for int on x86_64.
+  /// CHECK-START-X86_64: int Main.$noinline$intSelect_Constant(int) disassembly (after)
+  /// CHECK:             LessThan
+  /// CHECK-NEXT:        Select
+  /// CHECK:             cmp
+  /// CHECK:             cmovl/nge
+
+  public int $noinline$intSelect_Constant(int param) {
+    if (doThrow) { throw new Error(); }
+    int val_true = intB;
+    int val_false = intC;
+    return (param >= 3) ? val_true : val_false;
+  }
+
   public static void main(String[] args) {
     Main m = new Main();
     assertLongEquals(5L, m.$noinline$longSelect(4L));
     assertLongEquals(7L, m.$noinline$longSelect(2L));
     assertLongEquals(5L, m.$noinline$longSelect_Constant(4L));
     assertLongEquals(7L, m.$noinline$longSelect_Constant(2L));
+    assertIntEquals(5, m.$noinline$intSelect_Constant(4));
+    assertIntEquals(7, m.$noinline$intSelect_Constant(2));
+  }
+
+  public static void assertIntEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new Error(expected + " != " + actual);
+    }
   }
 
   public static void assertLongEquals(long expected, long actual) {
@@ -71,4 +100,6 @@
   public long longA = 3L;
   public long longB = 5L;
   public long longC = 7L;
+  public int intB = 5;
+  public int intC = 7;
 }
diff --git a/test/566-checker-signum/src/Main.java b/test/566-checker-signum/src/Main.java
index cc4a984..0ad0042 100644
--- a/test/566-checker-signum/src/Main.java
+++ b/test/566-checker-signum/src/Main.java
@@ -54,6 +54,13 @@
     expectEquals(1, sign64(12345L));
     expectEquals(1, sign64(Long.MAX_VALUE));
 
+    expectEquals(-1, sign64(0x800000007FFFFFFFL));
+    expectEquals(-1, sign64(0x80000000FFFFFFFFL));
+    expectEquals(1, sign64(0x000000007FFFFFFFL));
+    expectEquals(1, sign64(0x00000000FFFFFFFFL));
+    expectEquals(1, sign64(0x7FFFFFFF7FFFFFFFL));
+    expectEquals(1, sign64(0x7FFFFFFFFFFFFFFFL));
+
     for (long i = -11L; i <= 11L; i++) {
       int expected = 0;
       if (i < 0) expected = -1;
@@ -61,6 +68,14 @@
       expectEquals(expected, sign64(i));
     }
 
+    for (long i = Long.MIN_VALUE; i <= Long.MIN_VALUE + 11L; i++) {
+      expectEquals(-1, sign64(i));
+    }
+
+    for (long i = Long.MAX_VALUE; i >= Long.MAX_VALUE - 11L; i--) {
+      expectEquals(1, sign64(i));
+    }
+
     System.out.println("passed");
   }
 
diff --git a/test/567-checker-compare/src/Main.java b/test/567-checker-compare/src/Main.java
index 52abb75..951d2c7 100644
--- a/test/567-checker-compare/src/Main.java
+++ b/test/567-checker-compare/src/Main.java
@@ -88,6 +88,10 @@
     expectEquals(1, compare64(Long.MAX_VALUE, 1L));
     expectEquals(1, compare64(Long.MAX_VALUE, Long.MAX_VALUE - 1L));
 
+    expectEquals(-1, compare64(0x111111117FFFFFFFL, 0x11111111FFFFFFFFL));
+    expectEquals(0, compare64(0x111111117FFFFFFFL, 0x111111117FFFFFFFL));
+    expectEquals(1, compare64(0x11111111FFFFFFFFL, 0x111111117FFFFFFFL));
+
     for (long i = -11L; i <= 11L; i++) {
       for (long j = -11L; j <= 11L; j++) {
         int expected = 0;
@@ -97,6 +101,14 @@
       }
     }
 
+    for (long i = Long.MIN_VALUE; i <= Long.MIN_VALUE + 11L; i++) {
+      expectEquals(-1, compare64(i, 0));
+    }
+
+    for (long i = Long.MAX_VALUE; i >= Long.MAX_VALUE - 11L; i--) {
+      expectEquals(1, compare64(i, 0));
+    }
+
     System.out.println("passed");
   }
 
diff --git a/test/569-checker-pattern-replacement/src-multidex/Base.java b/test/569-checker-pattern-replacement/src-multidex/Base.java
new file mode 100644
index 0000000..f4d59af
--- /dev/null
+++ b/test/569-checker-pattern-replacement/src-multidex/Base.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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 Base {
+  Base() {
+    intField = 0;               // Unnecessary IPUT.
+    doubleField = 0.0;          // Unnecessary IPUT.
+    objectField = null;         // Unnecessary IPUT.
+  }
+
+  Base(int intValue) {
+    intField = intValue;
+  }
+
+  Base(String stringValue) {
+    objectField = stringValue;  // Unnecessary IPUT.
+    stringField = stringValue;
+    objectField = null;         // Unnecessary IPUT.
+  }
+
+  Base(double doubleValue, Object objectValue) {
+    doubleField = doubleValue;
+    objectField = objectValue;
+  }
+
+  Base(int intValue, double doubleValue, Object objectValue) {
+    intField = intValue;
+    doubleField = doubleValue;
+    objectField = objectValue;
+  }
+
+  Base(int intValue, double doubleValue, Object objectValue, String stringValue) {
+    // Outside our limit of 3 IPUTs.
+    intField = intValue;
+    doubleField = doubleValue;
+    objectField = objectValue;
+    stringField = stringValue;
+  }
+
+  Base(double doubleValue) {
+    this(doubleValue, null);
+  }
+
+  Base(Object objectValue) {
+    // Unsupported forwarding of a value after a zero.
+    this(0.0, objectValue);
+  }
+
+  Base(int intValue, long dummy) {
+    this(intValue, 0.0, null);
+  }
+
+  public int intField;
+  public double doubleField;
+  public Object objectField;
+  public String stringField;
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/BaseWithFinalField.java b/test/569-checker-pattern-replacement/src-multidex/BaseWithFinalField.java
new file mode 100644
index 0000000..7a1d591
--- /dev/null
+++ b/test/569-checker-pattern-replacement/src-multidex/BaseWithFinalField.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2016 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 BaseWithFinalField {
+  BaseWithFinalField() {
+    intField = 0;
+  }
+
+  BaseWithFinalField(int intValue) {
+    intField = intValue;
+  }
+
+  public final int intField;
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/Derived.java b/test/569-checker-pattern-replacement/src-multidex/Derived.java
new file mode 100644
index 0000000..184563f
--- /dev/null
+++ b/test/569-checker-pattern-replacement/src-multidex/Derived.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2016 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 final class Derived extends Base {
+  public Derived() {
+    this(0);
+  }
+
+  public Derived(int intValue) {
+    super(intValue);
+  }
+
+  public Derived(String stringValue) {
+    super(stringValue);
+    stringField = null;   // Clear field set by Base.<init>(String).
+  }
+
+  public Derived(double doubleValue) {
+    super(doubleValue, null);
+  }
+
+  public Derived(int intValue, double doubleValue, Object objectValue) {
+    super(intValue, doubleValue, objectValue);
+    objectField = null;   // Clear field set by Base.<init>(int, double, Object).
+    intField = 0;         // Clear field set by Base.<init>(int, double, Object).
+  }
+
+  Derived(int intValue, double doubleValue, Object objectValue, String stringValue) {
+    super(intValue, doubleValue, objectValue, stringValue);
+    // Clearing fields here doesn't help because the superclass constructor must
+    // satisfy the pattern constraints on its own and it doesn't (it has 4 IPUTs).
+    intField = 0;
+    doubleField = 0.0;
+    objectField = null;
+    stringField = null;
+  }
+
+  public Derived(float floatValue) {
+    super();
+    floatField = floatValue;
+  }
+
+  public Derived(int intValue, double doubleValue, Object objectValue, float floatValue) {
+    super(intValue, doubleValue, objectValue);
+    objectField = null;   // Clear field set by Base.<init>(int, double, Object).
+    floatField = floatValue;
+  }
+
+  public float floatField;
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/DerivedInSecondDex.java b/test/569-checker-pattern-replacement/src-multidex/DerivedInSecondDex.java
new file mode 100644
index 0000000..50266e8
--- /dev/null
+++ b/test/569-checker-pattern-replacement/src-multidex/DerivedInSecondDex.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 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 final class DerivedInSecondDex extends BaseInMainDex {
+  DerivedInSecondDex() {
+    super();
+  }
+
+  DerivedInSecondDex(int intValue) {
+    // Not matched: Superclass in a different dex file has an IPUT.
+    super(intValue);
+  }
+
+  DerivedInSecondDex(long dummy) {
+    // Matched: Superclass in a different dex file has an IPUT that's pruned because we store 0.
+    super(0);
+  }
+}
diff --git a/test/569-checker-pattern-replacement/src-multidex/DerivedWithFinalField.java b/test/569-checker-pattern-replacement/src-multidex/DerivedWithFinalField.java
new file mode 100644
index 0000000..5b39b8a
--- /dev/null
+++ b/test/569-checker-pattern-replacement/src-multidex/DerivedWithFinalField.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 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 final class DerivedWithFinalField extends BaseWithFinalField {
+  DerivedWithFinalField() {
+    this(0);
+  }
+
+  DerivedWithFinalField(int intValue) {
+    super(intValue);
+    doubleField = 0.0;
+  }
+
+  DerivedWithFinalField(double doubleValue) {
+    super(0);
+    doubleField = doubleValue;
+  }
+
+  DerivedWithFinalField(int intValue, double doubleValue) {
+    super(intValue);
+    doubleField = doubleValue;
+  }
+
+  public final double doubleField;
+}
diff --git a/test/569-checker-pattern-replacement/src/BaseInMainDex.java b/test/569-checker-pattern-replacement/src/BaseInMainDex.java
new file mode 100644
index 0000000..b401540
--- /dev/null
+++ b/test/569-checker-pattern-replacement/src/BaseInMainDex.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2016 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 BaseInMainDex {
+  BaseInMainDex() {
+  }
+
+  BaseInMainDex(int intValue) {
+    intField = intValue;
+  }
+
+  public int intField;
+}
diff --git a/test/569-checker-pattern-replacement/src/Main.java b/test/569-checker-pattern-replacement/src/Main.java
index e2d451c..345e9fd 100644
--- a/test/569-checker-pattern-replacement/src/Main.java
+++ b/test/569-checker-pattern-replacement/src/Main.java
@@ -15,368 +15,1210 @@
  */
 
 public class Main {
-    /// CHECK-START: void Main.staticNop() inliner (before)
-    /// CHECK:                          InvokeStaticOrDirect
+  /// CHECK-START: void Main.staticNop() inliner (before)
+  /// CHECK:                          InvokeStaticOrDirect
 
-    /// CHECK-START: void Main.staticNop() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-START: void Main.staticNop() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
 
-    public static void staticNop() {
-      Second.staticNop(11);
+  public static void staticNop() {
+    Second.staticNop(11);
+  }
+
+  /// CHECK-START: void Main.nop(Second) inliner (before)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: void Main.nop(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static void nop(Second s) {
+    s.nop();
+  }
+
+  /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Ignored:i\d+>>    IntConstant 77
+  /// CHECK-DAG:  <<ClinitCk:l\d+>>   ClinitCheck
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:  <<Invoke:l\d+>>     InvokeStaticOrDirect [<<Ignored>>,<<Value>>{{(,[ij]\d+)?}},<<ClinitCk>>]
+  /// CHECK-DAG:                      Return [<<Invoke>>]
+
+  /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:                      Return [<<Value>>]
+
+  /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static Object staticReturnArg2(String value) {
+    return Second.staticReturnArg2(77, value);
+  }
+
+  /// CHECK-START: long Main.returnArg1(Second, long) inliner (before)
+  /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
+  /// CHECK-DAG:  <<Invoke:j\d+>>     InvokeVirtual [<<NullCk>>,<<Value>>]
+  /// CHECK-DAG:                      Return [<<Invoke>>]
+
+  /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:                      Return [<<Value>>]
+
+  /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static long returnArg1(Second s, long value) {
+    return s.returnArg1(value);
+  }
+
+  /// CHECK-START: int Main.staticReturn9() inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.staticReturn9() inliner (before)
+  /// CHECK-NOT:                      IntConstant 9
+
+  /// CHECK-START: int Main.staticReturn9() inliner (after)
+  /// CHECK-DAG:  <<Const9:i\d+>>     IntConstant 9
+  /// CHECK-DAG:                      Return [<<Const9>>]
+
+  /// CHECK-START: int Main.staticReturn9() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static int staticReturn9() {
+    return Second.staticReturn9();
+  }
+
+  /// CHECK-START: int Main.return7(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
+
+  /// CHECK-START: int Main.return7(Second) inliner (before)
+  /// CHECK-NOT:                      IntConstant 7
+
+  /// CHECK-START: int Main.return7(Second) inliner (after)
+  /// CHECK-DAG:  <<Const7:i\d+>>     IntConstant 7
+  /// CHECK-DAG:                      Return [<<Const7>>]
+
+  /// CHECK-START: int Main.return7(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static int return7(Second s) {
+    return s.return7(null);
+  }
+
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeStaticOrDirect
+
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
+  /// CHECK-NOT:                      NullConstant
+
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
+  /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
+  /// CHECK-DAG:                      Return [<<Null>>]
+
+  /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static String staticReturnNull() {
+    return Second.staticReturnNull();
+  }
+
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeVirtual
+
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
+  /// CHECK-NOT:                      NullConstant
+
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
+  /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
+  /// CHECK-DAG:                      Return [<<Null>>]
+
+  /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static Object returnNull(Second s) {
+    return s.returnNull();
+  }
+
+  /// CHECK-START: int Main.getInt(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
+
+  /// CHECK-START: int Main.getInt(Second) inliner (after)
+  /// CHECK:      {{i\d+}}            InstanceFieldGet
+
+  /// CHECK-START: int Main.getInt(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static int getInt(Second s) {
+    return s.getInstanceIntField();
+  }
+
+  /// CHECK-START: double Main.getDouble(Second) inliner (before)
+  /// CHECK:      {{d\d+}}            InvokeVirtual
+
+  /// CHECK-START: double Main.getDouble(Second) inliner (after)
+  /// CHECK:      {{d\d+}}            InstanceFieldGet
+
+  /// CHECK-START: double Main.getDouble(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static double getDouble(Second s) {
+    return s.getInstanceDoubleField(22);
+  }
+
+  /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeVirtual
+
+  /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
+  /// CHECK:      {{l\d+}}            InstanceFieldGet
+
+  /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static Object getObject(Second s) {
+    return s.getInstanceObjectField(-1L);
+  }
+
+  /// CHECK-START: java.lang.String Main.getString(Second) inliner (before)
+  /// CHECK:      {{l\d+}}            InvokeVirtual
+
+  /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
+  /// CHECK:      {{l\d+}}            InstanceFieldGet
+
+  /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static String getString(Second s) {
+    return s.getInstanceStringField(null, "whatever", 1234L);
+  }
+
+  /// CHECK-START: int Main.staticGetInt(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
+  /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldGet
+
+  public static int staticGetInt(Second s) {
+    return Second.staticGetInstanceIntField(s);
+  }
+
+  /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (before)
+  /// CHECK:      {{d\d+}}            InvokeVirtual
+
+  /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
+  /// CHECK:      {{d\d+}}            InvokeVirtual
+
+  /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldGet
+
+  public static double getDoubleFromParam(Second s) {
+    return s.getInstanceDoubleFieldFromParam(s);
+  }
+
+  /// CHECK-START: int Main.getStaticInt(Second) inliner (before)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
+
+  /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
+  /// CHECK:      {{i\d+}}            InvokeVirtual
+
+  /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldGet
+  /// CHECK-NOT:                      StaticFieldGet
+
+  public static int getStaticInt(Second s) {
+    return s.getStaticIntField();
+  }
+
+  /// CHECK-START: long Main.setLong(Second, long) inliner (before)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: long Main.setLong(Second, long) inliner (after)
+  /// CHECK:                          InstanceFieldSet
+
+  /// CHECK-START: long Main.setLong(Second, long) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static long setLong(Second s, long value) {
+    s.setInstanceLongField(-1, value);
+    return s.instanceLongField;
+  }
+
+  /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (before)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
+  /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Arg2:i\d+>>       ParameterValue
+  /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<NullCk>>,<<Value>>]
+  /// CHECK-DAG:  <<NullCk2:l\d+>>    NullCheck [<<Second>>]
+  /// CHECK-DAG:  <<IGet:j\d+>>       InstanceFieldGet [<<NullCk2>>]
+  /// CHECK-DAG:  <<Conv:j\d+>>       TypeConversion [<<Arg2>>]
+  /// CHECK-DAG:  <<Add:j\d+>>        Add [<<IGet>>,<<Conv>>]
+  /// CHECK-DAG:                      Return [<<Add>>]
+
+  /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
+  /// CHECK-NOT:                      InvokeVirtual
+
+  public static long setLongReturnArg2(Second s, long value, int arg2) {
+    int result = s.setInstanceLongFieldReturnArg2(value, arg2);
+    return s.instanceLongField + result;
+  }
+
+  /// CHECK-START: long Main.staticSetLong(Second, long) inliner (before)
+  /// CHECK:                          InvokeStaticOrDirect
+
+  /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
+  /// CHECK:                          InvokeStaticOrDirect
+
+  /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static long staticSetLong(Second s, long value) {
+    Second.staticSetInstanceLongField(s, value);
+    return s.instanceLongField;
+  }
+
+  /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (before)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static long setLongThroughParam(Second s, long value) {
+    s.setInstanceLongFieldThroughParam(s, value);
+    return s.instanceLongField;
+  }
+
+  /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (before)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
+  /// CHECK:                          InvokeVirtual
+
+  /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+  /// CHECK-NOT:                      StaticFieldSet
+
+  public static float setStaticFloat(Second s, float value) {
+    s.setStaticFloatField(value);
+    return s.staticFloatField;
+  }
+
+  /// CHECK-START: java.lang.Object Main.newObject() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:java.lang.Object.<init>
+
+  /// CHECK-START: java.lang.Object Main.newObject() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  public static Object newObject() {
+    return new Object();
+  }
+
+  /// CHECK-START: double Main.constructBase() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase() {
+    Base b = new Base();
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBase(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructBase(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(int intValue) {
+    Base b = new Base(intValue);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBaseWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBaseWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBaseWith0() {
+    Base b = new Base(0);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: java.lang.String Main.constructBase(java.lang.String) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static String constructBase(String stringValue) {
+    Base b = new Base(stringValue);
+    return b.stringField;
+  }
+
+  /// CHECK-START: java.lang.String Main.constructBaseWithNullString() inliner (before)
+  /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Null>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: java.lang.String Main.constructBaseWithNullString() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: java.lang.String Main.constructBaseWithNullString() inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static String constructBaseWithNullString() {
+    String stringValue = null;
+    Base b = new Base(stringValue);
+    return b.stringField;
+  }
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<OValue>>]
+
+  /// CHECK-START: double Main.constructBase(double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(double doubleValue, Object objectValue) {
+    Base b = new Base(doubleValue, objectValue);
+    return (b.objectField != null) ? b.doubleField : -b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<IValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<OValue>>]
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(int intValue, double doubleValue, Object objectValue) {
+    Base b = new Base(intValue, doubleValue, objectValue);
+    double tmp = b.intField + b.doubleField;
+    return (b.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     IntConstant 0
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     NullConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (after)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+
+  /// CHECK-START: double Main.constructBaseWith0DoubleNull(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBaseWith0DoubleNull(double doubleValue) {
+    Base b = new Base(0, doubleValue, null);
+    double tmp = b.intField + b.doubleField;
+    return (b.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object, java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(
+      int intValue, double doubleValue, Object objectValue, String stringValue) {
+    Base b = new Base(intValue, doubleValue, objectValue, stringValue);
+    double tmp = b.intField + b.doubleField;
+    tmp = (b.objectField != null) ? tmp : -tmp;
+    return (b.stringField != null) ? 2.0 * tmp : 0.5 * tmp;
+  }
+
+  /// CHECK-START: double Main.constructBase(double) inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructBase(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(double doubleValue) {
+    Base b = new Base(doubleValue);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBaseWith0d() inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBaseWith0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBaseWith0d() {
+    Base b = new Base(0.0);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructBase(java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(Object objectValue) {
+    Base b = new Base(objectValue);
+    double tmp = b.intField + b.doubleField;
+    return (b.objectField != null) ? tmp + 1.0 : tmp - 1.0;
+  }
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<JValue:j\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<JValue>>{{(,[ij]\d+)?}}] method_name:Base.<init>
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<IValue>>]
+
+  /// CHECK-START: double Main.constructBase(int, long) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructBase(int intValue, long dummy) {
+    Base b = new Base(intValue, dummy);
+    return b.intField + b.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerived() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived() {
+    Derived d = new Derived();
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructDerived(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(int intValue) {
+    Derived d = new Derived(intValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerivedWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWith0() {
+    Derived d = new Derived(0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: java.lang.String Main.constructDerived(java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: java.lang.String Main.constructDerived(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: java.lang.String Main.constructDerived(java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static String constructDerived(String stringValue) {
+    Derived d = new Derived(stringValue);
+    return d.stringField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructDerived(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(double doubleValue) {
+    Derived d = new Derived(doubleValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWith0d() inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerivedWith0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWith0d() {
+    Derived d = new Derived(0.0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(int intValue, double doubleValue, Object objectValue) {
+    Derived d = new Derived(intValue, doubleValue, objectValue);
+    double tmp = d.intField + d.doubleField;
+    return (d.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, java.lang.String) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,{{l\d+}},{{l\d+}}{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, java.lang.String) inliner (after)
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(
+      int intValue, double doubleValue, Object objectValue, String stringValue) {
+    Derived d = new Derived(intValue, doubleValue, objectValue, stringValue);
+    double tmp = d.intField + d.doubleField;
+    tmp = (d.objectField != null) ? tmp : -tmp;
+    return (d.stringField != null) ? 2.0 * tmp : 0.5 * tmp;
+  }
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (before)
+  /// CHECK-DAG:  <<Value:f\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (after)
+  /// CHECK-DAG:  <<Value:f\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+
+  /// CHECK-START: double Main.constructDerived(float) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(float floatValue) {
+    Derived d = new Derived(floatValue);
+    return d.intField + d.doubleField + d.floatField;
+  }
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<OValue:l\d+>>     ParameterValue
+  /// CHECK-DAG:  <<FValue:f\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>,<<OValue>>,<<FValue>>{{(,[ij]\d+)?}}] method_name:Derived.<init>
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (after)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<FValue:f\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<IValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<DValue>>]
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<FValue>>]
+
+  /// CHECK-START: double Main.constructDerived(int, double, java.lang.Object, float) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerived(
+      int intValue, double doubleValue, Object objectValue, float floatValue) {
+    Derived d = new Derived(intValue, doubleValue, objectValue, floatValue);
+    double tmp = d.intField + d.doubleField + d.floatField;
+    return (d.objectField != null) ? tmp : -tmp;
+  }
+
+  /// CHECK-START: int Main.constructBaseWithFinalField() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:BaseWithFinalField.<init>
+
+  /// CHECK-START: int Main.constructBaseWithFinalField() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructBaseWithFinalField() {
+    BaseWithFinalField b = new BaseWithFinalField();
+    return b.intField;
+  }
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:BaseWithFinalField.<init>
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: int Main.constructBaseWithFinalField(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructBaseWithFinalField(int intValue) {
+    BaseWithFinalField b = new BaseWithFinalField(intValue);
+    return b.intField;
+  }
+
+  /// CHECK-START: int Main.constructBaseWithFinalFieldWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:BaseWithFinalField.<init>
+
+  /// CHECK-START: int Main.constructBaseWithFinalFieldWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructBaseWithFinalFieldWith0() {
+    BaseWithFinalField b = new BaseWithFinalField(0);
+    return b.intField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalField() {
+    DerivedWithFinalField d = new DerivedWithFinalField();
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalField(int intValue) {
+    DerivedWithFinalField d = new DerivedWithFinalField(intValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalFieldWith0() {
+    DerivedWithFinalField d = new DerivedWithFinalField(0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalField(double doubleValue) {
+    DerivedWithFinalField d = new DerivedWithFinalField(doubleValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0d() inliner (before)
+  /// CHECK-DAG:  <<Value:d\d+>>      DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalFieldWith0d() {
+    DerivedWithFinalField d = new DerivedWithFinalField(0.0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     ParameterValue
+  /// CHECK-DAG:  <<DValue:d\d+>>     ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-DAG:  <<Value:d\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  /// CHECK-DAG:                      InstanceFieldSet [<<Obj>>,<<Value>>]
+  /// CHECK-DAG:                      MemoryBarrier
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-DAG:                      InstanceFieldSet
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  /// CHECK-START: double Main.constructDerivedWithFinalField(int, double) inliner (after)
+  /// CHECK-DAG:                      MemoryBarrier
+  /// CHECK-NOT:                      MemoryBarrier
+
+  public static double constructDerivedWithFinalField(int intValue, double doubleValue) {
+    DerivedWithFinalField d = new DerivedWithFinalField(intValue, doubleValue);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0And0d() inliner (before)
+  /// CHECK-DAG:  <<IValue:i\d+>>     IntConstant 0
+  /// CHECK-DAG:  <<DValue:d\d+>>     DoubleConstant
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<IValue>>,<<DValue>>{{(,[ij]\d+)?}}] method_name:DerivedWithFinalField.<init>
+
+  /// CHECK-START: double Main.constructDerivedWithFinalFieldWith0And0d() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static double constructDerivedWithFinalFieldWith0And0d() {
+    DerivedWithFinalField d = new DerivedWithFinalField(0, 0.0);
+    return d.intField + d.doubleField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex() inliner (before)
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex() inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDex() {
+    DerivedInSecondDex d = new DerivedInSecondDex();
+    return d.intField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(int) inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(int) inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(int) inliner (after)
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDex(int intValue) {
+    DerivedInSecondDex d = new DerivedInSecondDex(intValue);
+    return d.intField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDexWith0() inliner (before)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDexWith0() inliner (after)
+  /// CHECK-DAG:  <<Value:i\d+>>      IntConstant 0
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDexWith0() inliner (after)
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDexWith0() {
+    DerivedInSecondDex d = new DerivedInSecondDex(0);
+    return d.intField;
+  }
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(long) inliner (before)
+  /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
+  /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
+  // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
+  /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>,<<Value>>{{(,[ij]\d+)?}}] method_name:DerivedInSecondDex.<init>
+
+  /// CHECK-START: int Main.constructDerivedInSecondDex(long) inliner (after)
+  /// CHECK-NOT:                      InvokeStaticOrDirect
+  /// CHECK-NOT:                      MemoryBarrier
+  /// CHECK-NOT:                      InstanceFieldSet
+
+  public static int constructDerivedInSecondDex(long dummy) {
+    DerivedInSecondDex d = new DerivedInSecondDex(dummy);
+    return d.intField;
+  }
+
+  public static void main(String[] args) throws Exception {
+    Second s = new Second();
+
+    // Replaced NOP pattern.
+    staticNop();
+    nop(s);
+    // Replaced "return arg" pattern.
+    assertEquals("arbitrary string", staticReturnArg2("arbitrary string"));
+    assertEquals(4321L, returnArg1(s, 4321L));
+    // Replaced "return const" pattern.
+    assertEquals(9, staticReturn9());
+    assertEquals(7, return7(s));
+    assertEquals(null, staticReturnNull());
+    assertEquals(null, returnNull(s));
+    // Replaced IGET pattern.
+    assertEquals(42, getInt(s));
+    assertEquals(-42.0, getDouble(s));
+    assertEquals(null, getObject(s));
+    assertEquals("dummy", getString(s));
+    // Not replaced IGET pattern.
+    assertEquals(42, staticGetInt(s));
+    assertEquals(-42.0, getDoubleFromParam(s));
+    // SGET.
+    assertEquals(4242, getStaticInt(s));
+    // Replaced IPUT pattern.
+    assertEquals(111L, setLong(s, 111L));
+    assertEquals(345L, setLongReturnArg2(s, 222L, 123));
+    // Not replaced IPUT pattern.
+    assertEquals(222L, staticSetLong(s, 222L));
+    assertEquals(333L, setLongThroughParam(s, 333L));
+    // SPUT.
+    assertEquals(-11.5f, setStaticFloat(s, -11.5f));
+
+    if (newObject() == null) {
+      throw new AssertionError("new Object() cannot be null.");
     }
 
-    /// CHECK-START: void Main.nop(Second) inliner (before)
-    /// CHECK:                          InvokeVirtual
+    assertEquals(0.0, constructBase());
+    assertEquals(42.0, constructBase(42));
+    assertEquals(0.0, constructBaseWith0());
+    assertEquals("something", constructBase("something"));
+    assertEquals(null, constructBaseWithNullString());
+    assertEquals(11.0, constructBase(11.0, new Object()));
+    assertEquals(-12.0, constructBase(12.0, null));
+    assertEquals(30.0, constructBase(17, 13.0, new Object()));
+    assertEquals(-34.0, constructBase(19, 15.0, null));
+    assertEquals(-22.5, constructBaseWith0DoubleNull(22.5));
+    assertEquals(-8.0, constructBase(2, 14.0, null, null));
+    assertEquals(-64.0, constructBase(4, 28.0, null, "dummy"));
+    assertEquals(13.0, constructBase(24, 2.0, new Object(), null));
+    assertEquals(30.0, constructBase(11, 4.0, new Object(), "dummy"));
+    assertEquals(43.0, constructBase(43.0));
+    assertEquals(0.0, constructBaseWith0d());
+    assertEquals(1.0, constructBase(new Object()));
+    assertEquals(-1.0, constructBase((Object) null));
+    assertEquals(123.0, constructBase(123, 65L));
 
-    /// CHECK-START: void Main.nop(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
+    assertEquals(0.0, constructDerived());
+    assertEquals(73.0, constructDerived(73));
+    assertEquals(0.0, constructDerivedWith0());
+    assertEquals(null, constructDerived("something else"));
+    assertEquals(18.0, constructDerived(18.0));
+    assertEquals(0.0, constructDerivedWith0d());
+    assertEquals(-7.0, constructDerived(5, 7.0, new Object()));
+    assertEquals(-4.0, constructDerived(9, 4.0, null));
+    assertEquals(0.0, constructDerived(1, 9.0, null, null));
+    assertEquals(0.0, constructDerived(2, 8.0, null, "dummy"));
+    assertEquals(0.0, constructDerived(3, 7.0, new Object(), null));
+    assertEquals(0.0, constructDerived(4, 6.0, new Object(), "dummy"));
+    assertEquals(17.0, constructDerived(17.0f));
+    assertEquals(-5.5, constructDerived(6, -7.0, new Object(), 6.5f));
 
-    public static void nop(Second s) {
-      s.nop();
+    assertEquals(0, constructBaseWithFinalField());
+    assertEquals(77, constructBaseWithFinalField(77));
+    assertEquals(0, constructBaseWithFinalFieldWith0());
+    assertEquals(0.0, constructDerivedWithFinalField());
+    assertEquals(-33.0, constructDerivedWithFinalField(-33));
+    assertEquals(0.0, constructDerivedWithFinalFieldWith0());
+    assertEquals(-44.0, constructDerivedWithFinalField(-44.0));
+    assertEquals(0.0, constructDerivedWithFinalFieldWith0d());
+    assertEquals(88, constructDerivedWithFinalField(22, 66.0));
+    assertEquals(0.0, constructDerivedWithFinalFieldWith0And0d());
+
+    assertEquals(0, constructDerivedInSecondDex());
+    assertEquals(123, constructDerivedInSecondDex(123));
+    assertEquals(0, constructDerivedInSecondDexWith0());
+    assertEquals(0, constructDerivedInSecondDex(7L));
+  }
+
+  private static void assertEquals(int expected, int actual) {
+    if (expected != actual) {
+      throw new AssertionError("Wrong result: " + expected + " != " + actual);
     }
+  }
 
-    /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (before)
-    /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
-    /// CHECK-DAG:  <<Ignored:i\d+>>    IntConstant 77
-    /// CHECK-DAG:  <<ClinitCk:l\d+>>   ClinitCheck
-    // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
-    /// CHECK-DAG:  <<Invoke:l\d+>>     InvokeStaticOrDirect [<<Ignored>>,<<Value>>{{(,[ij]\d+)?}},<<ClinitCk>>]
-    /// CHECK-DAG:                      Return [<<Invoke>>]
-
-    /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
-    /// CHECK-DAG:  <<Value:l\d+>>      ParameterValue
-    /// CHECK-DAG:                      Return [<<Value>>]
-
-    /// CHECK-START: java.lang.Object Main.staticReturnArg2(java.lang.String) inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
-
-    public static Object staticReturnArg2(String value) {
-      return Second.staticReturnArg2(77, value);
+  private static void assertEquals(double expected, double actual) {
+    if (expected != actual) {
+      throw new AssertionError("Wrong result: " + expected + " != " + actual);
     }
+  }
 
-    /// CHECK-START: long Main.returnArg1(Second, long) inliner (before)
-    /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
-    /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
-    /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
-    /// CHECK-DAG:  <<Invoke:j\d+>>     InvokeVirtual [<<NullCk>>,<<Value>>]
-    /// CHECK-DAG:                      Return [<<Invoke>>]
-
-    /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
-    /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
-    /// CHECK-DAG:                      Return [<<Value>>]
-
-    /// CHECK-START: long Main.returnArg1(Second, long) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static long returnArg1(Second s, long value) {
-      return s.returnArg1(value);
+  private static void assertEquals(Object expected, Object actual) {
+    if (expected != actual && (expected == null || !expected.equals(actual))) {
+      throw new AssertionError("Wrong result: " + expected + " != " + actual);
     }
-
-    /// CHECK-START: int Main.staticReturn9() inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
-
-    /// CHECK-START: int Main.staticReturn9() inliner (before)
-    /// CHECK-NOT:                      IntConstant 9
-
-    /// CHECK-START: int Main.staticReturn9() inliner (after)
-    /// CHECK-DAG:  <<Const9:i\d+>>     IntConstant 9
-    /// CHECK-DAG:                      Return [<<Const9>>]
-
-    /// CHECK-START: int Main.staticReturn9() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
-
-    public static int staticReturn9() {
-      return Second.staticReturn9();
-    }
-
-    /// CHECK-START: int Main.return7(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
-
-    /// CHECK-START: int Main.return7(Second) inliner (before)
-    /// CHECK-NOT:                      IntConstant 7
-
-    /// CHECK-START: int Main.return7(Second) inliner (after)
-    /// CHECK-DAG:  <<Const7:i\d+>>     IntConstant 7
-    /// CHECK-DAG:                      Return [<<Const7>>]
-
-    /// CHECK-START: int Main.return7(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static int return7(Second s) {
-      return s.return7(null);
-    }
-
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeStaticOrDirect
-
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (before)
-    /// CHECK-NOT:                      NullConstant
-
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
-    /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
-    /// CHECK-DAG:                      Return [<<Null>>]
-
-    /// CHECK-START: java.lang.String Main.staticReturnNull() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
-
-    public static String staticReturnNull() {
-      return Second.staticReturnNull();
-    }
-
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeVirtual
-
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (before)
-    /// CHECK-NOT:                      NullConstant
-
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
-    /// CHECK-DAG:  <<Null:l\d+>>       NullConstant
-    /// CHECK-DAG:                      Return [<<Null>>]
-
-    /// CHECK-START: java.lang.Object Main.returnNull(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static Object returnNull(Second s) {
-      return s.returnNull();
-    }
-
-    /// CHECK-START: int Main.getInt(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
-
-    /// CHECK-START: int Main.getInt(Second) inliner (after)
-    /// CHECK:      {{i\d+}}            InstanceFieldGet
-
-    /// CHECK-START: int Main.getInt(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static int getInt(Second s) {
-      return s.getInstanceIntField();
-    }
-
-    /// CHECK-START: double Main.getDouble(Second) inliner (before)
-    /// CHECK:      {{d\d+}}            InvokeVirtual
-
-    /// CHECK-START: double Main.getDouble(Second) inliner (after)
-    /// CHECK:      {{d\d+}}            InstanceFieldGet
-
-    /// CHECK-START: double Main.getDouble(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static double getDouble(Second s) {
-      return s.getInstanceDoubleField(22);
-    }
-
-    /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeVirtual
-
-    /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
-    /// CHECK:      {{l\d+}}            InstanceFieldGet
-
-    /// CHECK-START: java.lang.Object Main.getObject(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static Object getObject(Second s) {
-      return s.getInstanceObjectField(-1L);
-    }
-
-    /// CHECK-START: java.lang.String Main.getString(Second) inliner (before)
-    /// CHECK:      {{l\d+}}            InvokeVirtual
-
-    /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
-    /// CHECK:      {{l\d+}}            InstanceFieldGet
-
-    /// CHECK-START: java.lang.String Main.getString(Second) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static String getString(Second s) {
-      return s.getInstanceStringField(null, "whatever", 1234L);
-    }
-
-    /// CHECK-START: int Main.staticGetInt(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
-
-    /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
-    /// CHECK:      {{i\d+}}            InvokeStaticOrDirect
-
-    /// CHECK-START: int Main.staticGetInt(Second) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldGet
-
-    public static int staticGetInt(Second s) {
-      return Second.staticGetInstanceIntField(s);
-    }
-
-    /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (before)
-    /// CHECK:      {{d\d+}}            InvokeVirtual
-
-    /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
-    /// CHECK:      {{d\d+}}            InvokeVirtual
-
-    /// CHECK-START: double Main.getDoubleFromParam(Second) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldGet
-
-    public static double getDoubleFromParam(Second s) {
-      return s.getInstanceDoubleFieldFromParam(s);
-    }
-
-    /// CHECK-START: int Main.getStaticInt(Second) inliner (before)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
-
-    /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
-    /// CHECK:      {{i\d+}}            InvokeVirtual
-
-    /// CHECK-START: int Main.getStaticInt(Second) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldGet
-    /// CHECK-NOT:                      StaticFieldGet
-
-    public static int getStaticInt(Second s) {
-      return s.getStaticIntField();
-    }
-
-    /// CHECK-START: long Main.setLong(Second, long) inliner (before)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: long Main.setLong(Second, long) inliner (after)
-    /// CHECK:                          InstanceFieldSet
-
-    /// CHECK-START: long Main.setLong(Second, long) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static long setLong(Second s, long value) {
-      s.setInstanceLongField(-1, value);
-      return s.instanceLongField;
-    }
-
-    /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (before)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
-    /// CHECK-DAG:  <<Second:l\d+>>     ParameterValue
-    /// CHECK-DAG:  <<Value:j\d+>>      ParameterValue
-    /// CHECK-DAG:  <<Arg2:i\d+>>       ParameterValue
-    /// CHECK-DAG:  <<NullCk:l\d+>>     NullCheck [<<Second>>]
-    /// CHECK-DAG:                      InstanceFieldSet [<<NullCk>>,<<Value>>]
-    /// CHECK-DAG:  <<NullCk2:l\d+>>    NullCheck [<<Second>>]
-    /// CHECK-DAG:  <<IGet:j\d+>>       InstanceFieldGet [<<NullCk2>>]
-    /// CHECK-DAG:  <<Conv:j\d+>>       TypeConversion [<<Arg2>>]
-    /// CHECK-DAG:  <<Add:j\d+>>        Add [<<IGet>>,<<Conv>>]
-    /// CHECK-DAG:                      Return [<<Add>>]
-
-    /// CHECK-START: long Main.setLongReturnArg2(Second, long, int) inliner (after)
-    /// CHECK-NOT:                      InvokeVirtual
-
-    public static long setLongReturnArg2(Second s, long value, int arg2) {
-      int result = s.setInstanceLongFieldReturnArg2(value, arg2);
-      return s.instanceLongField + result;
-    }
-
-    /// CHECK-START: long Main.staticSetLong(Second, long) inliner (before)
-    /// CHECK:                          InvokeStaticOrDirect
-
-    /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
-    /// CHECK:                          InvokeStaticOrDirect
-
-    /// CHECK-START: long Main.staticSetLong(Second, long) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldSet
-
-    public static long staticSetLong(Second s, long value) {
-      Second.staticSetInstanceLongField(s, value);
-      return s.instanceLongField;
-    }
-
-    /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (before)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: long Main.setLongThroughParam(Second, long) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldSet
-
-    public static long setLongThroughParam(Second s, long value) {
-      s.setInstanceLongFieldThroughParam(s, value);
-      return s.instanceLongField;
-    }
-
-    /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (before)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
-    /// CHECK:                          InvokeVirtual
-
-    /// CHECK-START: float Main.setStaticFloat(Second, float) inliner (after)
-    /// CHECK-NOT:                      InstanceFieldSet
-    /// CHECK-NOT:                      StaticFieldSet
-
-    public static float setStaticFloat(Second s, float value) {
-      s.setStaticFloatField(value);
-      return s.staticFloatField;
-    }
-
-    /// CHECK-START: java.lang.Object Main.newObject() inliner (before)
-    /// CHECK-DAG:  <<Obj:l\d+>>        NewInstance
-    // Note: The ArtMethod* (typed as int or long) is optional after sharpening.
-    /// CHECK-DAG:                      InvokeStaticOrDirect [<<Obj>>{{(,[ij]\d+)?}}] method_name:java.lang.Object.<init>
-
-    /// CHECK-START: java.lang.Object Main.newObject() inliner (after)
-    /// CHECK-NOT:                      InvokeStaticOrDirect
-
-    public static Object newObject() {
-      return new Object();
-    }
-
-    public static void main(String[] args) throws Exception {
-      Second s = new Second();
-
-      // Replaced NOP pattern.
-      staticNop();
-      nop(s);
-      // Replaced "return arg" pattern.
-      assertEquals("arbitrary string", staticReturnArg2("arbitrary string"));
-      assertEquals(4321L, returnArg1(s, 4321L));
-      // Replaced "return const" pattern.
-      assertEquals(9, staticReturn9());
-      assertEquals(7, return7(s));
-      assertEquals(null, staticReturnNull());
-      assertEquals(null, returnNull(s));
-      // Replaced IGET pattern.
-      assertEquals(42, getInt(s));
-      assertEquals(-42.0, getDouble(s));
-      assertEquals(null, getObject(s));
-      assertEquals("dummy", getString(s));
-      // Not replaced IGET pattern.
-      assertEquals(42, staticGetInt(s));
-      assertEquals(-42.0, getDoubleFromParam(s));
-      // SGET.
-      assertEquals(4242, getStaticInt(s));
-      // Replaced IPUT pattern.
-      assertEquals(111L, setLong(s, 111L));
-      assertEquals(345L, setLongReturnArg2(s, 222L, 123));
-      // Not replaced IPUT pattern.
-      assertEquals(222L, staticSetLong(s, 222L));
-      assertEquals(333L, setLongThroughParam(s, 333L));
-      // SPUT.
-      assertEquals(-11.5f, setStaticFloat(s, -11.5f));
-
-      if (newObject() == null) {
-        throw new AssertionError("new Object() cannot be null.");
-      }
-    }
-
-    private static void assertEquals(int expected, int actual) {
-      if (expected != actual) {
-        throw new AssertionError("Wrong result: " + expected + " != " + actual);
-      }
-    }
-
-    private static void assertEquals(double expected, double actual) {
-      if (expected != actual) {
-        throw new AssertionError("Wrong result: " + expected + " != " + actual);
-      }
-    }
-
-    private static void assertEquals(Object expected, Object actual) {
-      if (expected != actual && (expected == null || !expected.equals(actual))) {
-        throw new AssertionError("Wrong result: " + expected + " != " + actual);
-      }
-    }
+  }
 }
diff --git a/test/570-checker-osr/expected.txt b/test/570-checker-osr/expected.txt
new file mode 100644
index 0000000..25fb220
--- /dev/null
+++ b/test/570-checker-osr/expected.txt
@@ -0,0 +1,5 @@
+JNI_OnLoad called
+100000
+200000
+300000
+400000
diff --git a/test/570-checker-osr/info.txt b/test/570-checker-osr/info.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/570-checker-osr/info.txt
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
new file mode 100644
index 0000000..4c58b39
--- /dev/null
+++ b/test/570-checker-osr/osr.cc
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2016 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.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
+#include "jit/profiling_info.h"
+#include "oat_quick_method_header.h"
+#include "scoped_thread_state_change.h"
+#include "stack_map.h"
+
+namespace art {
+
+class OsrVisitor : public StackVisitor {
+ public:
+  explicit OsrVisitor(Thread* thread)
+      SHARED_REQUIRES(Locks::mutator_lock_)
+      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+        in_osr_method_(false),
+        in_interpreter_(false) {}
+
+  bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
+    ArtMethod* m = GetMethod();
+    std::string m_name(m->GetName());
+
+    if ((m_name.compare("$noinline$returnInt") == 0) ||
+        (m_name.compare("$noinline$returnFloat") == 0) ||
+        (m_name.compare("$noinline$returnDouble") == 0) ||
+        (m_name.compare("$noinline$returnLong") == 0) ||
+        (m_name.compare("$noinline$deopt") == 0) ||
+        (m_name.compare("$noinline$inlineCache") == 0)) {
+      const OatQuickMethodHeader* header =
+          Runtime::Current()->GetJit()->GetCodeCache()->LookupOsrMethodHeader(m);
+      if (header != nullptr && header == GetCurrentOatQuickMethodHeader()) {
+        in_osr_method_ = true;
+      } else if (IsCurrentFrameInInterpreter()) {
+        in_interpreter_ = true;
+      }
+      return false;
+    }
+    return true;
+  }
+
+  bool in_osr_method_;
+  bool in_interpreter_;
+};
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_ensureInOsrCode(JNIEnv*, jclass) {
+  jit::Jit* jit = Runtime::Current()->GetJit();
+  if (jit == nullptr) {
+    // Just return true for non-jit configurations to stop the infinite loop.
+    return JNI_TRUE;
+  }
+  ScopedObjectAccess soa(Thread::Current());
+  OsrVisitor visitor(soa.Self());
+  visitor.WalkStack();
+  return visitor.in_osr_method_;
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_ensureInInterpreter(JNIEnv*, jclass) {
+  if (!Runtime::Current()->UseJit()) {
+    // The return value is irrelevant if we're not using JIT.
+    return false;
+  }
+  ScopedObjectAccess soa(Thread::Current());
+  OsrVisitor visitor(soa.Self());
+  visitor.WalkStack();
+  return visitor.in_interpreter_;
+}
+
+class ProfilingInfoVisitor : public StackVisitor {
+ public:
+  explicit ProfilingInfoVisitor(Thread* thread)
+      SHARED_REQUIRES(Locks::mutator_lock_)
+      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
+
+  bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
+    ArtMethod* m = GetMethod();
+    std::string m_name(m->GetName());
+
+    if (m_name.compare("$noinline$inlineCache") == 0) {
+      ProfilingInfo::Create(Thread::Current(), m, /* retry_allocation */ true);
+      return false;
+    }
+    return true;
+  }
+};
+
+extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasProfilingInfo(JNIEnv*, jclass) {
+  if (!Runtime::Current()->UseJit()) {
+    return;
+  }
+  ScopedObjectAccess soa(Thread::Current());
+  ProfilingInfoVisitor visitor(soa.Self());
+  visitor.WalkStack();
+}
+
+class OsrCheckVisitor : public StackVisitor {
+ public:
+  explicit OsrCheckVisitor(Thread* thread)
+      SHARED_REQUIRES(Locks::mutator_lock_)
+      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
+
+  bool VisitFrame() SHARED_REQUIRES(Locks::mutator_lock_) {
+    ArtMethod* m = GetMethod();
+    std::string m_name(m->GetName());
+
+    jit::Jit* jit = Runtime::Current()->GetJit();
+    if (m_name.compare("$noinline$inlineCache") == 0 && jit != nullptr) {
+      while (jit->GetCodeCache()->LookupOsrMethodHeader(m) == nullptr) {
+        // Sleep to yield to the compiler thread.
+        sleep(0);
+        // Will either ensure it's compiled or do the compilation itself.
+        jit->CompileMethod(m, Thread::Current(), /* osr */ true);
+      }
+      return false;
+    }
+    return true;
+  }
+};
+
+extern "C" JNIEXPORT void JNICALL Java_Main_ensureHasOsrCode(JNIEnv*, jclass) {
+  if (!Runtime::Current()->UseJit()) {
+    return;
+  }
+  ScopedObjectAccess soa(Thread::Current());
+  OsrCheckVisitor visitor(soa.Self());
+  visitor.WalkStack();
+}
+
+}  // namespace art
diff --git a/test/570-checker-osr/smali/Osr.smali b/test/570-checker-osr/smali/Osr.smali
new file mode 100644
index 0000000..869c7c3
--- /dev/null
+++ b/test/570-checker-osr/smali/Osr.smali
@@ -0,0 +1,35 @@
+# Copyright (C) 2016 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 LOsr;
+
+.super Ljava/lang/Object;
+
+# Check that blocks only havig nops are not merged when they are loop headers.
+# This ensures we can do on-stack replacement for branches to those nop blocks.
+
+## CHECK-START: int Osr.simpleLoop(int, int) dead_code_elimination_final (after)
+## CHECK-DAG:                     SuspendCheck loop:<<OuterLoop:B\d+>> outer_loop:none
+## CHECK-DAG:                     SuspendCheck loop:{{B\d+}} outer_loop:<<OuterLoop>>
+.method public static simpleLoop(II)I
+   .registers 3
+   const/16 v0, 0
+   :nop_entry
+   nop
+   :loop_entry
+   add-int v0, v0, v0
+   if-eq v0, v1, :loop_entry
+   if-eq v0, v2, :nop_entry
+   return v0
+.end method
diff --git a/test/570-checker-osr/src/DeoptimizationController.java b/test/570-checker-osr/src/DeoptimizationController.java
new file mode 100644
index 0000000..907d133
--- /dev/null
+++ b/test/570-checker-osr/src/DeoptimizationController.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+// This file is a copy of 802-deoptimization/src/DeoptimizationController.java
+// because run-test requires standalone individual test.
+
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+
+/**
+ * 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(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
+    } catch (IOException e) {
+      System.setProperty("java.io.tmpdir", "/data/local/tmp");
+      try {
+        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
+      } catch (IOException e2) {
+        System.setProperty("java.io.tmpdir", "/sdcard");
+        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
+      }
+    }
+  }
+
+  public static void startDeoptimization() {
+    File tempFile = null;
+    try {
+      tempFile = createTempFile();
+      String tempFileName = tempFile.getPath();
+
+      VMDebug.startMethodTracing(tempFileName, 0, 0, false, 1000);
+      if (VMDebug.getMethodTracingMode() == 0) {
+        throw new IllegalStateException("Not tracing.");
+      }
+    } catch (Exception exc) {
+      exc.printStackTrace(System.err);
+    } finally {
+      if (tempFile != null) {
+        tempFile.delete();
+      }
+    }
+  }
+
+  public static void stopDeoptimization() {
+    try {
+      VMDebug.stopMethodTracing();
+      if (VMDebug.getMethodTracingMode() != 0) {
+        throw new IllegalStateException("Still tracing.");
+      }
+    } catch (Exception exc) {
+      exc.printStackTrace(System.err);
+    }
+  }
+
+  private static class VMDebug {
+    private static final Method startMethodTracingMethod;
+    private static final Method stopMethodTracingMethod;
+    private static final Method getMethodTracingModeMethod;
+
+    static {
+      try {
+        Class<?> c = Class.forName("dalvik.system.VMDebug");
+        startMethodTracingMethod = c.getDeclaredMethod("startMethodTracing", String.class,
+            Integer.TYPE, Integer.TYPE, Boolean.TYPE, Integer.TYPE);
+        stopMethodTracingMethod = c.getDeclaredMethod("stopMethodTracing");
+        getMethodTracingModeMethod = c.getDeclaredMethod("getMethodTracingMode");
+      } catch (Exception e) {
+        throw new RuntimeException(e);
+      }
+    }
+
+    public static void startMethodTracing(String filename, int bufferSize, int flags,
+        boolean samplingEnabled, int intervalUs) throws Exception {
+      startMethodTracingMethod.invoke(null, filename, bufferSize, flags, samplingEnabled,
+          intervalUs);
+    }
+    public static void stopMethodTracing() throws Exception {
+      stopMethodTracingMethod.invoke(null);
+    }
+    public static int getMethodTracingMode() throws Exception {
+      return (int) getMethodTracingModeMethod.invoke(null);
+    }
+  }
+}
diff --git a/test/570-checker-osr/src/Main.java b/test/570-checker-osr/src/Main.java
new file mode 100644
index 0000000..828908a
--- /dev/null
+++ b/test/570-checker-osr/src/Main.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016 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) {
+    new SubMain();
+    System.loadLibrary(args[0]);
+    if ($noinline$returnInt() != 53) {
+      throw new Error("Unexpected return value");
+    }
+    if ($noinline$returnFloat() != 42.2f) {
+      throw new Error("Unexpected return value");
+    }
+    if ($noinline$returnDouble() != Double.longBitsToDouble(0xF000000000001111L)) {
+      throw new Error("Unexpected return value ");
+    }
+    if ($noinline$returnLong() != 0xFFFF000000001111L) {
+      throw new Error("Unexpected return value");
+    }
+
+    try {
+      $noinline$deopt();
+    } catch (Exception e) {}
+    DeoptimizationController.stopDeoptimization();
+
+    $noinline$inlineCache(new Main(), /* isSecondInvocation */ false);
+    if ($noinline$inlineCache(new SubMain(), /* isSecondInvocation */ true) != SubMain.class) {
+      throw new Error("Unexpected return value");
+    }
+  }
+
+  public static int $noinline$returnInt() {
+    if (doThrow) throw new Error("");
+    int i = 0;
+    for (; i < 100000; ++i) {
+    }
+    while (!ensureInOsrCode()) {}
+    System.out.println(i);
+    return 53;
+  }
+
+  public static float $noinline$returnFloat() {
+    if (doThrow) throw new Error("");
+    int i = 0;
+    for (; i < 200000; ++i) {
+    }
+    while (!ensureInOsrCode()) {}
+    System.out.println(i);
+    return 42.2f;
+  }
+
+  public static double $noinline$returnDouble() {
+    if (doThrow) throw new Error("");
+    int i = 0;
+    for (; i < 300000; ++i) {
+    }
+    while (!ensureInOsrCode()) {}
+    System.out.println(i);
+    return Double.longBitsToDouble(0xF000000000001111L);
+  }
+
+  public static long $noinline$returnLong() {
+    if (doThrow) throw new Error("");
+    int i = 0;
+    for (; i < 400000; ++i) {
+    }
+    while (!ensureInOsrCode()) {}
+    System.out.println(i);
+    return 0xFFFF000000001111L;
+  }
+
+  public static void $noinline$deopt() {
+    if (doThrow) throw new Error("");
+    int i = 0;
+    for (; i < 100000; ++i) {
+    }
+    while (!ensureInOsrCode()) {}
+    DeoptimizationController.startDeoptimization();
+  }
+
+  public static Class $noinline$inlineCache(Main m, boolean isSecondInvocation) {
+    // If we are running in non-JIT mode, or were unlucky enough to get this method
+    // already JITted, just return the expected value.
+    if (!ensureInInterpreter()) {
+      return SubMain.class;
+    }
+
+    ensureHasProfilingInfo();
+
+    // Ensure that we have OSR code to jump to.
+    if (isSecondInvocation) {
+      ensureHasOsrCode();
+    }
+
+    // This call will be optimized in the OSR compiled code
+    // to check and deoptimize if m is not of type 'Main'.
+    Main other = m.inlineCache();
+
+    // Jump to OSR compiled code. The second run
+    // of this method will have 'm' as a SubMain, and the compiled
+    // code we are jumping to will have wrongly optimize other as being a
+    // 'Main'.
+    if (isSecondInvocation) {
+      while (!ensureInOsrCode()) {}
+    }
+
+    // We used to wrongly optimize this call and assume 'other' was a 'Main'.
+    return other.returnClass();
+  }
+
+  public Main inlineCache() {
+    return new Main();
+  }
+
+  public Class returnClass() {
+    return Main.class;
+  }
+
+  public static int[] array = new int[4];
+
+  public static native boolean ensureInInterpreter();
+  public static native boolean ensureInOsrCode();
+  public static native void ensureHasProfilingInfo();
+  public static native void ensureHasOsrCode();
+
+  public static boolean doThrow = false;
+}
+
+class SubMain extends Main {
+  public Class returnClass() {
+    return SubMain.class;
+  }
+
+  public Main inlineCache() {
+    return new SubMain();
+  }
+}
diff --git a/test/570-checker-select/src/Main.java b/test/570-checker-select/src/Main.java
index 2f8094d..8a4cf60 100644
--- a/test/570-checker-select/src/Main.java
+++ b/test/570-checker-select/src/Main.java
@@ -19,6 +19,16 @@
   /// CHECK-START: int Main.BoolCond_IntVarVar(boolean, int, int) register (after)
   /// CHECK:               Select [{{i\d+}},{{i\d+}},{{z\d+}}]
 
+  /// CHECK-START-ARM64: int Main.BoolCond_IntVarVar(boolean, int, int) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csel ne
+
+  /// CHECK-START-X86_64: int Main.BoolCond_IntVarVar(boolean, int, int) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> ParameterValue
+  /// CHECK:                          Select [{{i\d+}},{{i\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/ne
+
   public static int BoolCond_IntVarVar(boolean cond, int x, int y) {
     return cond ? x : y;
   }
@@ -26,6 +36,16 @@
   /// CHECK-START: int Main.BoolCond_IntVarCst(boolean, int) register (after)
   /// CHECK:               Select [{{i\d+}},{{i\d+}},{{z\d+}}]
 
+  /// CHECK-START-ARM64: int Main.BoolCond_IntVarCst(boolean, int) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csinc ne
+
+  /// CHECK-START-X86_64: int Main.BoolCond_IntVarCst(boolean, int) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> ParameterValue
+  /// CHECK:                          Select [{{i\d+}},{{i\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/ne
+
   public static int BoolCond_IntVarCst(boolean cond, int x) {
     return cond ? x : 1;
   }
@@ -33,13 +53,79 @@
   /// CHECK-START: int Main.BoolCond_IntCstVar(boolean, int) register (after)
   /// CHECK:               Select [{{i\d+}},{{i\d+}},{{z\d+}}]
 
+  /// CHECK-START-ARM64: int Main.BoolCond_IntCstVar(boolean, int) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csinc eq
+
+  /// CHECK-START-X86_64: int Main.BoolCond_IntCstVar(boolean, int) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> ParameterValue
+  /// CHECK:                          Select [{{i\d+}},{{i\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/ne
+
   public static int BoolCond_IntCstVar(boolean cond, int y) {
     return cond ? 1 : y;
   }
 
+  /// CHECK-START: long Main.BoolCond_LongVarVar(boolean, long, long) register (after)
+  /// CHECK:               Select [{{j\d+}},{{j\d+}},{{z\d+}}]
+
+  /// CHECK-START-ARM64: long Main.BoolCond_LongVarVar(boolean, long, long) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csel ne
+
+  /// CHECK-START-X86_64: long Main.BoolCond_LongVarVar(boolean, long, long) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> ParameterValue
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/neq
+
+  public static long BoolCond_LongVarVar(boolean cond, long x, long y) {
+    return cond ? x : y;
+  }
+
+  /// CHECK-START: long Main.BoolCond_LongVarCst(boolean, long) register (after)
+  /// CHECK:               Select [{{j\d+}},{{j\d+}},{{z\d+}}]
+
+  /// CHECK-START-ARM64: long Main.BoolCond_LongVarCst(boolean, long) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csinc ne
+
+  /// CHECK-START-X86_64: long Main.BoolCond_LongVarCst(boolean, long) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> ParameterValue
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/neq
+
+  public static long BoolCond_LongVarCst(boolean cond, long x) {
+    return cond ? x : 1L;
+  }
+
+  /// CHECK-START: long Main.BoolCond_LongCstVar(boolean, long) register (after)
+  /// CHECK:               Select [{{j\d+}},{{j\d+}},{{z\d+}}]
+
+  /// CHECK-START-ARM64: long Main.BoolCond_LongCstVar(boolean, long) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csinc eq
+
+  /// CHECK-START-X86_64: long Main.BoolCond_LongCstVar(boolean, long) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> ParameterValue
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/neq
+
+  public static long BoolCond_LongCstVar(boolean cond, long y) {
+    return cond ? 1L : y;
+  }
+
   /// CHECK-START: float Main.BoolCond_FloatVarVar(boolean, float, float) register (after)
   /// CHECK:               Select [{{f\d+}},{{f\d+}},{{z\d+}}]
 
+  /// CHECK-START-ARM64: float Main.BoolCond_FloatVarVar(boolean, float, float) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            fcsel ne
+
   public static float BoolCond_FloatVarVar(boolean cond, float x, float y) {
     return cond ? x : y;
   }
@@ -47,6 +133,11 @@
   /// CHECK-START: float Main.BoolCond_FloatVarCst(boolean, float) register (after)
   /// CHECK:               Select [{{f\d+}},{{f\d+}},{{z\d+}}]
 
+  /// CHECK-START-ARM64: float Main.BoolCond_FloatVarCst(boolean, float) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            fcsel ne
+
   public static float BoolCond_FloatVarCst(boolean cond, float x) {
     return cond ? x : 1.0f;
   }
@@ -54,6 +145,11 @@
   /// CHECK-START: float Main.BoolCond_FloatCstVar(boolean, float) register (after)
   /// CHECK:               Select [{{f\d+}},{{f\d+}},{{z\d+}}]
 
+  /// CHECK-START-ARM64: float Main.BoolCond_FloatCstVar(boolean, float) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            fcsel ne
+
   public static float BoolCond_FloatCstVar(boolean cond, float y) {
     return cond ? 1.0f : y;
   }
@@ -62,6 +158,16 @@
   /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
   /// CHECK-NEXT:                     Select [{{i\d+}},{{i\d+}},<<Cond>>]
 
+  /// CHECK-START-ARM64: int Main.IntNonmatCond_IntVarVar(int, int, int, int) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csel le
+
+  /// CHECK-START-X86_64: int Main.IntNonmatCond_IntVarVar(int, int, int, int) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+  /// CHECK-NEXT:                     Select [{{i\d+}},{{i\d+}},<<Cond>>]
+  /// CHECK:                          cmovle/ng
+
   public static int IntNonmatCond_IntVarVar(int a, int b, int x, int y) {
     return a > b ? x : y;
   }
@@ -71,15 +177,119 @@
   /// CHECK-NEXT:       <<Sel:i\d+>>  Select [{{i\d+}},{{i\d+}},{{z\d+}}]
   /// CHECK-NEXT:                     Add [<<Cond>>,<<Sel>>]
 
+  /// CHECK-START-ARM64: int Main.IntMatCond_IntVarVar(int, int, int, int) disassembly (after)
+  /// CHECK:               LessThanOrEqual
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            cset le
+  /// CHECK:               Select
+  /// CHECK-NEXT:            csel le
+
+  /// CHECK-START-X86_64: int Main.IntMatCond_IntVarVar(int, int, int, int) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+  /// CHECK:                          Select [{{i\d+}},{{i\d+}},<<Cond>>]
+  /// CHECK:                          cmovle/ng
+
   public static int IntMatCond_IntVarVar(int a, int b, int x, int y) {
     int result = (a > b ? x : y);
     return result + (a > b ? 0 : 1);
   }
 
+  /// CHECK-START: long Main.IntNonmatCond_LongVarVar(int, int, long, long) register (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+  /// CHECK-NEXT:                     Select [{{j\d+}},{{j\d+}},<<Cond>>]
+
+  /// CHECK-START-ARM64: long Main.IntNonmatCond_LongVarVar(int, int, long, long) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csel le
+
+  /// CHECK-START-X86_64: long Main.IntNonmatCond_LongVarVar(int, int, long, long) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+  /// CHECK-NEXT:                     Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovle/ngq
+
+  public static long IntNonmatCond_LongVarVar(int a, int b, long x, long y) {
+    return a > b ? x : y;
+  }
+
+  /// CHECK-START: long Main.IntMatCond_LongVarVar(int, int, long, long) register (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+  /// CHECK:            <<Sel1:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:            <<Sel2:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          Add [<<Sel2>>,<<Sel1>>]
+
+  /// CHECK-START-ARM64: long Main.IntMatCond_LongVarVar(int, int, long, long) disassembly (after)
+  /// CHECK:               LessThanOrEqual
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            cset le
+  /// CHECK:               Select
+  /// CHECK-NEXT:            csel le
+
+  /// CHECK-START-X86_64: long Main.IntMatCond_LongVarVar(int, int, long, long) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{i\d+}},{{i\d+}}]
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovle/ngq
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/neq
+
+  public static long IntMatCond_LongVarVar(int a, int b, long x, long y) {
+    long result = (a > b ? x : y);
+    return result + (a > b ? 0L : 1L);
+  }
+
+  /// CHECK-START: long Main.LongNonmatCond_LongVarVar(long, long, long, long) register (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}]
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+
+  /// CHECK-START-ARM64: long Main.LongNonmatCond_LongVarVar(long, long, long, long) disassembly (after)
+  /// CHECK:               Select
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            csel le
+
+  /// CHECK-START-X86_64: long Main.LongNonmatCond_LongVarVar(long, long, long, long) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}]
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovle/ngq
+
+  public static long LongNonmatCond_LongVarVar(long a, long b, long x, long y) {
+    return a > b ? x : y;
+  }
+
+  /// CHECK-START: long Main.LongMatCond_LongVarVar(long, long, long, long) register (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}]
+  /// CHECK:            <<Sel1:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:            <<Sel2:j\d+>> Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          Add [<<Sel2>>,<<Sel1>>]
+
+  /// CHECK-START-ARM64: long Main.LongMatCond_LongVarVar(long, long, long, long) disassembly (after)
+  /// CHECK:               LessThanOrEqual
+  /// CHECK-NEXT:            cmp
+  /// CHECK-NEXT:            cset le
+  /// CHECK:               Select
+  /// CHECK-NEXT:            csel le
+
+  /// CHECK-START-X86_64: long Main.LongMatCond_LongVarVar(long, long, long, long) disassembly (after)
+  /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{j\d+}},{{j\d+}}]
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovle/ngq
+  /// CHECK:                          Select [{{j\d+}},{{j\d+}},<<Cond>>]
+  /// CHECK:                          cmovnz/neq
+
+  public static long LongMatCond_LongVarVar(long a, long b, long x, long y) {
+    long result = (a > b ? x : y);
+    return result + (a > b ? 0L : 1L);
+  }
+
   /// CHECK-START: int Main.FloatLtNonmatCond_IntVarVar(float, float, int, int) register (after)
   /// CHECK:            <<Cond:z\d+>> LessThanOrEqual [{{f\d+}},{{f\d+}}]
   /// CHECK-NEXT:                     Select [{{i\d+}},{{i\d+}},<<Cond>>]
 
+  /// CHECK-START-ARM64: int Main.FloatLtNonmatCond_IntVarVar(float, float, int, int) disassembly (after)
+  /// CHECK:               LessThanOrEqual
+  /// CHECK:               Select
+  /// CHECK-NEXT:            fcmp
+  /// CHECK-NEXT:            csel le
+
   public static int FloatLtNonmatCond_IntVarVar(float a, float b, int x, int y) {
     return a > b ? x : y;
   }
@@ -88,6 +298,12 @@
   /// CHECK:            <<Cond:z\d+>> GreaterThanOrEqual [{{f\d+}},{{f\d+}}]
   /// CHECK-NEXT:                     Select [{{i\d+}},{{i\d+}},<<Cond>>]
 
+  /// CHECK-START-ARM64: int Main.FloatGtNonmatCond_IntVarVar(float, float, int, int) disassembly (after)
+  /// CHECK:               GreaterThanOrEqual
+  /// CHECK:               Select
+  /// CHECK-NEXT:            fcmp
+  /// CHECK-NEXT:            csel hs
+
   public static int FloatGtNonmatCond_IntVarVar(float a, float b, int x, int y) {
     return a < b ? x : y;
   }
@@ -96,6 +312,12 @@
   /// CHECK:            <<Cond:z\d+>> GreaterThanOrEqual [{{f\d+}},{{f\d+}}]
   /// CHECK-NEXT:                     Select [{{f\d+}},{{f\d+}},<<Cond>>]
 
+  /// CHECK-START-ARM64: float Main.FloatGtNonmatCond_FloatVarVar(float, float, float, float) disassembly (after)
+  /// CHECK:               GreaterThanOrEqual
+  /// CHECK:               Select
+  /// CHECK-NEXT:            fcmp
+  /// CHECK-NEXT:            fcsel hs
+
   public static float FloatGtNonmatCond_FloatVarVar(float a, float b, float x, float y) {
     return a < b ? x : y;
   }
@@ -105,6 +327,13 @@
   /// CHECK-NEXT:       <<Sel:i\d+>>  Select [{{i\d+}},{{i\d+}},<<Cond>>]
   /// CHECK-NEXT:                     Add [<<Cond>>,<<Sel>>]
 
+  /// CHECK-START-ARM64: int Main.FloatLtMatCond_IntVarVar(float, float, int, int) disassembly (after)
+  /// CHECK:               LessThanOrEqual
+  /// CHECK-NEXT:            fcmp
+  /// CHECK-NEXT:            cset le
+  /// CHECK:               Select
+  /// CHECK-NEXT:            csel le
+
   public static int FloatLtMatCond_IntVarVar(float a, float b, int x, int y) {
     int result = (a > b ? x : y);
     return result + (a > b ? 0 : 1);
@@ -115,6 +344,13 @@
   /// CHECK-NEXT:       <<Sel:i\d+>>  Select [{{i\d+}},{{i\d+}},<<Cond>>]
   /// CHECK-NEXT:                     Add [<<Cond>>,<<Sel>>]
 
+  /// CHECK-START-ARM64: int Main.FloatGtMatCond_IntVarVar(float, float, int, int) disassembly (after)
+  /// CHECK:               GreaterThanOrEqual
+  /// CHECK-NEXT:            fcmp
+  /// CHECK-NEXT:            cset hs
+  /// CHECK:               Select
+  /// CHECK-NEXT:            csel hs
+
   public static int FloatGtMatCond_IntVarVar(float a, float b, int x, int y) {
     int result = (a < b ? x : y);
     return result + (a < b ? 0 : 1);
@@ -125,6 +361,13 @@
   /// CHECK-NEXT:       <<Sel:f\d+>>  Select [{{f\d+}},{{f\d+}},<<Cond>>]
   /// CHECK-NEXT:                     TypeConversion [<<Cond>>]
 
+  /// CHECK-START-ARM64: float Main.FloatGtMatCond_FloatVarVar(float, float, float, float) disassembly (after)
+  /// CHECK:               GreaterThanOrEqual
+  /// CHECK-NEXT:            fcmp
+  /// CHECK-NEXT:            cset hs
+  /// CHECK:               Select
+  /// CHECK-NEXT:            fcsel hs
+
   public static float FloatGtMatCond_FloatVarVar(float a, float b, float x, float y) {
     float result = (a < b ? x : y);
     return result + (a < b ? 0 : 1);
@@ -150,6 +393,13 @@
     assertEqual(1, BoolCond_IntCstVar(true, 7));
     assertEqual(7, BoolCond_IntCstVar(false, 7));
 
+    assertEqual(5L, BoolCond_LongVarVar(true, 5L, 7L));
+    assertEqual(7L, BoolCond_LongVarVar(false, 5L, 7L));
+    assertEqual(5L, BoolCond_LongVarCst(true, 5L));
+    assertEqual(1L, BoolCond_LongVarCst(false, 5L));
+    assertEqual(1L, BoolCond_LongCstVar(true, 7L));
+    assertEqual(7L, BoolCond_LongCstVar(false, 7L));
+
     assertEqual(5, BoolCond_FloatVarVar(true, 5, 7));
     assertEqual(7, BoolCond_FloatVarVar(false, 5, 7));
     assertEqual(5, BoolCond_FloatVarCst(true, 5));
diff --git a/test/572-checker-array-get-regression/expected.txt b/test/572-checker-array-get-regression/expected.txt
new file mode 100644
index 0000000..f7d1ad4
--- /dev/null
+++ b/test/572-checker-array-get-regression/expected.txt
@@ -0,0 +1 @@
+524287
diff --git a/test/572-checker-array-get-regression/info.txt b/test/572-checker-array-get-regression/info.txt
new file mode 100644
index 0000000..d06feee
--- /dev/null
+++ b/test/572-checker-array-get-regression/info.txt
@@ -0,0 +1,3 @@
+Regression test for the ARM64 Baker's read barrier fast path compiler
+instrumentation of array loads with a large constant index, where we
+used to require too many scratch (temporary) registers.
diff --git a/test/572-checker-array-get-regression/src/Main.java b/test/572-checker-array-get-regression/src/Main.java
new file mode 100644
index 0000000..b55be70
--- /dev/null
+++ b/test/572-checker-array-get-regression/src/Main.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 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(test().intValue());
+  }
+
+  /// CHECK-START: java.lang.Integer Main.test() builder (after)
+  /// CHECK-DAG:     <<Method:[ij]\d+>>    CurrentMethod
+  /// CHECK-DAG:     <<Const2P19:i\d+>>    IntConstant 524288
+  /// CHECK-DAG:     <<ConstM1:i\d+>>      IntConstant -1
+  /// CHECK-DAG:     <<Array:l\d+>>        NewArray [<<Const2P19>>,<<Method>>]
+  /// CHECK-DAG:     <<NullCheck1:l\d+>>   NullCheck [<<Array>>]
+  /// CHECK-DAG:     <<Length1:i\d+>>      ArrayLength [<<NullCheck1>>]
+  /// CHECK-DAG:     <<Index:i\d+>>        Add [<<Length1>>,<<ConstM1>>]
+  /// CHECK-DAG:     <<NullCheck2:l\d+>>   NullCheck [<<Array>>]
+  /// CHECK-DAG:     <<Length2:i\d+>>      ArrayLength [<<NullCheck2>>]
+  /// CHECK-DAG:     <<BoundsCheck:i\d+>>  BoundsCheck [<<Index>>,<<Length2>>]
+  /// CHECK-DAG:     <<LastElement:l\d+>>  ArrayGet [<<NullCheck2>>,<<BoundsCheck>>]
+  /// CHECK-DAG:                           Return [<<LastElement>>]
+
+
+  /// CHECK-START: java.lang.Integer Main.test() register (before)
+  /// CHECK-DAG:     <<Method:[ij]\d+>>    CurrentMethod
+  /// CHECK-DAG:     <<Const2P19:i\d+>>    IntConstant 524288
+  /// CHECK-DAG:     <<Const2P19M1:i\d+>>  IntConstant 524287
+  /// CHECK-DAG:     <<Array:l\d+>>        NewArray [<<Const2P19>>,<<Method>>]
+  /// CHECK-DAG:     <<LastElement:l\d+>>  ArrayGet [<<Array>>,<<Const2P19M1>>]
+  /// CHECK-DAG:                           Return [<<LastElement>>]
+
+  public static Integer test() {
+    Integer[] integers = new Integer[1 << 19];
+    initIntegerArray(integers);
+    // Array load with a large constant index (after constant folding
+    // and bounds check elimination).
+    Integer last_integer = integers[integers.length - 1];
+    return last_integer;
+  }
+
+  public static void initIntegerArray(Integer[] integers) {
+    for (int i = 0; i < integers.length; ++i) {
+      integers[i] = new Integer(i);
+    }
+  }
+
+}
diff --git a/test/573-checker-checkcast-regression/expected.txt b/test/573-checker-checkcast-regression/expected.txt
new file mode 100644
index 0000000..b8626c4
--- /dev/null
+++ b/test/573-checker-checkcast-regression/expected.txt
@@ -0,0 +1 @@
+4
diff --git a/test/573-checker-checkcast-regression/info.txt b/test/573-checker-checkcast-regression/info.txt
new file mode 100644
index 0000000..74a6d6e
--- /dev/null
+++ b/test/573-checker-checkcast-regression/info.txt
@@ -0,0 +1,4 @@
+Regression test for the x86-64 Baker's read barrier fast path compiler
+instrumentation of CheckCasts, where we used to use an
+art::x86_64::NearLabel, the range of which was sometimes too short
+with Baker's read barriers enabled.
diff --git a/test/573-checker-checkcast-regression/src/Main.java b/test/573-checker-checkcast-regression/src/Main.java
new file mode 100644
index 0000000..473a2b1
--- /dev/null
+++ b/test/573-checker-checkcast-regression/src/Main.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2016 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) {
+    Object[] array = { new Integer(1), new Integer(2), new Integer(3) };
+    int result = test(array, 0, 2);
+    System.out.println(result);
+  }
+
+  // This test method uses two integers (`index1` and `index2`) to
+  // force the register allocator to use some high registers (R8-R15)
+  // on x86-64 in the code generated for the first CheckCast (which
+  // converts `new_array` to an `Object[]`), so as to produce code
+  // containing a conditional jump whose offset does not fit in a
+  // NearLabel when using Baker's read barrier fast path (because
+  // x86-64 instructions using these high registers have a larger
+  // encoding).
+  //
+  // The intent of this artifical constraint is to ensure the initial
+  // failure is properly tested by this regression test.
+
+  /// CHECK-START: int Main.test(java.lang.Object, int, int) register (after)
+  /// CHECK-DAG:     CheckCast check_kind:array_object_check
+  /// CHECK-DAG:     CheckCast check_kind:exact_check
+  /// CHECK-DAG:     CheckCast check_kind:exact_check
+
+  static public int test(Object new_array, int index1, int index2) {
+    Object[] objectArray = (Object[]) new_array;
+    Integer integer1 = (Integer) objectArray[index1];
+    Integer integer2 = (Integer) objectArray[index2];
+    return integer1.intValue() + integer2.intValue();
+  }
+
+}
diff --git a/test/574-irreducible-and-constant-area/expected.txt b/test/574-irreducible-and-constant-area/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/574-irreducible-and-constant-area/expected.txt
diff --git a/test/574-irreducible-and-constant-area/info.txt b/test/574-irreducible-and-constant-area/info.txt
new file mode 100644
index 0000000..e957a5a
--- /dev/null
+++ b/test/574-irreducible-and-constant-area/info.txt
@@ -0,0 +1,3 @@
+Regression test for intrinsics on x86, which used to wrongly assume
+a HInvokeStaticOrDirect must have a special input (does not apply for irreducible
+loops).
diff --git a/test/574-irreducible-and-constant-area/run b/test/574-irreducible-and-constant-area/run
new file mode 100755
index 0000000..ffdbcc9
--- /dev/null
+++ b/test/574-irreducible-and-constant-area/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2016 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.
+
+# Don't do relocation, as this affects this test.
+exec ${RUN} "$@" --no-relocate
diff --git a/test/574-irreducible-and-constant-area/smali/IrreducibleLoop.smali b/test/574-irreducible-and-constant-area/smali/IrreducibleLoop.smali
new file mode 100644
index 0000000..d7d4346
--- /dev/null
+++ b/test/574-irreducible-and-constant-area/smali/IrreducibleLoop.smali
@@ -0,0 +1,35 @@
+# Copyright (C) 2016 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 LIrreducibleLoop;
+
+.super Ljava/lang/Object;
+
+.method public static simpleLoop(I)I
+   .registers 5
+   const/16 v0, 42
+   const/16 v1, 42
+   const-wide/high16 v2, 0x4000000000000000L
+   if-eq p0, v0, :other_loop_entry
+   :loop_entry
+   invoke-static {v1, v1}, LMain;->$inline$foo(FF)V
+   invoke-static {v2, v3, v2, v3}, LMain;->$inline$foo(DD)V
+   if-ne p0, v0, :exit
+   add-int v0, v0, v0
+   :other_loop_entry
+   add-int v0, v0, v0
+   goto :loop_entry
+   :exit
+   return v0
+.end method
diff --git a/test/574-irreducible-and-constant-area/src/Main.java b/test/574-irreducible-and-constant-area/src/Main.java
new file mode 100644
index 0000000..3cdd924
--- /dev/null
+++ b/test/574-irreducible-and-constant-area/src/Main.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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;
+
+public class Main {
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) throws Exception {
+    Class<?> c = Class.forName("IrreducibleLoop");
+    Method m = c.getMethod("simpleLoop", int.class);
+    Object[] arguments = { 42 };
+    m.invoke(null, arguments);
+  }
+
+  public static void $inline$foo(float a, float b) {
+    Math.abs(a);
+    Math.max(a, b);
+    Math.min(a, b);
+  }
+
+  public static void $inline$foo(double a, double b) {
+    Math.abs(a);
+    Math.max(a, b);
+    Math.min(a, b);
+  }
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index 73ce307..8808a50 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -58,4 +58,6 @@
 b/26594149 (6)
 b/26594149 (7)
 b/26594149 (8)
+b/27148248
+b/26965384
 Done!
diff --git a/test/800-smali/smali/b_26965384.smali b/test/800-smali/smali/b_26965384.smali
new file mode 100644
index 0000000..47ed418
--- /dev/null
+++ b/test/800-smali/smali/b_26965384.smali
@@ -0,0 +1,20 @@
+.class public LB26965384;
+.super LB26965384Super;
+
+.method public constructor <init>()V
+    .locals 1
+    const v0, 0
+    iput v0, p0, LB26965384;->a:I
+    invoke-direct {p0}, LB26965384Super;-><init>()V
+    return-void
+.end method
+
+
+# Just by loading this class we should fail. It doesn't really matter what's in
+# this method.
+.method public static run()V
+    .registers 4
+    new-instance v0, LB26965384;
+    invoke-direct {v0}, LB26965384;-><init>()V
+    return-void
+.end method
diff --git a/test/800-smali/smali/b_26965384Super.smali b/test/800-smali/smali/b_26965384Super.smali
new file mode 100644
index 0000000..32faea7
--- /dev/null
+++ b/test/800-smali/smali/b_26965384Super.smali
@@ -0,0 +1,10 @@
+.class public LB26965384Super;
+.super Ljava/lang/Object;
+
+.field public a:I
+
+.method public constructor <init>()V
+    .locals 0
+    invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+    return-void
+.end method
diff --git a/test/800-smali/smali/b_27148248.smali b/test/800-smali/smali/b_27148248.smali
new file mode 100644
index 0000000..4601cc6
--- /dev/null
+++ b/test/800-smali/smali/b_27148248.smali
@@ -0,0 +1,27 @@
+# Copyright (C) 2016 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 LB27148248;
+
+# Regression for dex2oatd crash during compilation of method which
+# used to throw with argument of non-reference type.
+
+.super Ljava/lang/Object;
+
+.method public static run()V
+   .registers 1
+   const v0, 0xbad
+   throw v0
+.end method
+
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index b0eff5d..4e6de46 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -160,6 +160,10 @@
                 null));
         testCases.add(new TestCase("b/26594149 (8)", "B26594149_8", "run", null, new VerifyError(),
                 null));
+        testCases.add(new TestCase("b/27148248", "B27148248", "run", null, new VerifyError(),
+                null));
+        testCases.add(new TestCase("b/26965384", "B26965384", "run", null, new VerifyError(),
+                null));
     }
 
     public void runTests() {
diff --git a/test/971-iface-super/util-src/generate_smali.py b/test/971-iface-super/util-src/generate_smali.py
index f01c904..3681411 100755
--- a/test/971-iface-super/util-src/generate_smali.py
+++ b/test/971-iface-super/util-src/generate_smali.py
@@ -39,7 +39,7 @@
 import string
 
 # The max depth the type tree can have.
-MAX_IFACE_DEPTH = 3
+MAX_IFACE_DEPTH = 2
 
 class MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin):
   """
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index faaf1f0..e547c72 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -40,7 +40,8 @@
   466-get-live-vreg/get_live_vreg_jni.cc \
   497-inlining-and-class-loader/clear_dex_cache.cc \
   543-env-long-ref/env_long_ref.cc \
-  566-polymorphic-inlining/polymorphic_inline.cc
+  566-polymorphic-inlining/polymorphic_inline.cc \
+  570-checker-osr/osr.cc
 
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttestd.so
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index dfb540e..364be59 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -42,8 +42,7 @@
 
 ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
   TEST_ART_RUN_TEST_DEPENDENCIES += \
-    $(JACK) \
-    $(JILL_JAR)
+    $(JACK)
   TEST_ART_RUN_TEST_ORDERONLY_DEPENDENCIES += setup-jack-server
 endif
 
@@ -72,8 +71,8 @@
 	  DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
 	  JACK_VERSION=$(JACK_DEFAULT_VERSION) \
 	  JACK=$(abspath $(JACK)) \
+	  JACK_VERSION=$(JACK_DEFAULT_VERSION) \
 	  JACK_CLASSPATH=$(TARGET_JACK_CLASSPATH) \
-	  JILL_JAR=$(abspath $(JILL_JAR)) \
 	  $(LOCAL_PATH)/run-test $$(PRIVATE_RUN_TEST_OPTIONS) --output-path $$(abspath $$(dir $$@)) $(1)
 	$(hide) touch $$@
 
@@ -235,6 +234,18 @@
         $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(TEST_ART_TIMING_SENSITIVE_RUN_TESTS), $(ALL_ADDRESS_SIZES))
 endif
 
+# 569-checker-pattern-replacement tests behaviour present only on host.
+TEST_ART_BROKEN_TARGET_TESTS := \
+  569-checker-pattern-replacement
+
+ifneq (,$(filter target,$(TARGET_TYPES)))
+  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_TARGET_TESTS), $(ALL_ADDRESS_SIZES))
+endif
+
+TEST_ART_BROKEN_TARGET_TESTS :=
+
 # Tests that require python3.
 TEST_ART_PYTHON3_DEPENDENCY_RUN_TESTS := \
   960-default-smali \
@@ -302,18 +313,7 @@
 
 # Temporarily disable some broken tests when forcing access checks in interpreter b/22414682
 TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS := \
-  004-JniTest \
-  005-annotations \
-  044-proxy \
-  073-mismatched-field \
-  088-monitor-verification \
-  135-MirandaDispatch \
-  137-cfi \
-  412-new-array \
-  471-uninitialized-locals \
-  506-verify-aput \
-  554-jit-profile-file \
-  800-smali
+  137-cfi
 
 ifneq (,$(filter interp-ac,$(COMPILER_TYPES)))
   ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \
@@ -412,13 +412,14 @@
 
 # 137:
 # This test unrolls and expects managed frames, but tracing means we run the interpreter.
-# 802:
+# 802 and 570-checker-osr:
 # This test dynamically enables tracing to force a deoptimization. This makes the test meaningless
 # when already tracing, and writes an error message that we do not want to check for.
 TEST_ART_BROKEN_TRACING_RUN_TESTS := \
   087-gc-after-link \
   137-cfi \
   141-class-unload \
+  570-checker-osr \
   802-deoptimization
 
 ifneq (,$(filter trace stream,$(TRACE_TYPES)))
@@ -470,10 +471,7 @@
 
 # Known broken tests for the mips32 optimizing compiler backend.
 TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS := \
-    441-checker-inliner \
     510-checker-try-catch \
-    536-checker-intrinsic-optimization \
-    557-checker-instruction-simplifier-ror \
 
 ifeq (mips,$(TARGET_ARCH))
   ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
@@ -488,7 +486,6 @@
 
 # Known broken tests for the mips64 optimizing compiler backend.
 TEST_ART_BROKEN_OPTIMIZING_MIPS64_RUN_TESTS := \
-    557-checker-instruction-simplifier-ror \
 
 ifeq (mips64,$(TARGET_ARCH))
   ifneq (,$(filter optimizing,$(COMPILER_TYPES)))
@@ -964,8 +961,8 @@
 	    DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
 	    JACK_VERSION=$(JACK_DEFAULT_VERSION) \
 	    JACK=$(abspath $(JACK)) \
+	    JACK_VERSION=$(JACK_DEFAULT_VERSION) \
 	    JACK_CLASSPATH=$$(PRIVATE_JACK_CLASSPATH) \
-	    JILL_JAR=$(abspath $(JILL_JAR)) \
 	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(12) \
 	      && $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
 	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 8245ccf..2db1e6c 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -406,6 +406,9 @@
   TMP_DIR_OPTION="-Djava.io.tmpdir=/data/local/tmp"
 fi
 
+# We set DumpNativeStackOnSigQuit to false to avoid stressing libunwind.
+# b/27185632
+# b/24664297
 dalvikvm_cmdline="$INVOKE_WITH $GDB $ANDROID_ROOT/bin/$DALVIKVM \
                   $GDB_ARGS \
                   $FLAGS \
@@ -420,6 +423,7 @@
                   $DEBUGGER_OPTS \
                   $DALVIKVM_BOOT_OPT \
                   $TMP_DIR_OPTION \
+                  -XX:DumpNativeStackOnSigQuit:false \
                   -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX $MAIN $ARGS"
 
 # Remove whitespace.
diff --git a/test/run-test b/test/run-test
index faa597e..f1875d7 100755
--- a/test/run-test
+++ b/test/run-test
@@ -88,13 +88,7 @@
   export JACK_CLASSPATH="${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack:${OUT_DIR:-$ANDROID_BUILD_TOP/out}/host/common/obj/JAVA_LIBRARIES/core-oj-hostdex_intermediates/classes.jack"
 fi
 
-# If JILL_JAR is not set, assume it is located in the prebuilts directory.
-if [ -z "$JILL_JAR" ]; then
-  export JILL_JAR="$ANDROID_BUILD_TOP/prebuilts/sdk/tools/jill.jar"
-fi
-
 export JACK="$JACK -g -cp $JACK_CLASSPATH"
-export JILL="java -jar $JILL_JAR"
 
 info="info.txt"
 build="build"
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 9e02ce2..2eb52bc 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -21,7 +21,7 @@
 
 out_dir=${OUT_DIR-out}
 java_libraries_dir=${out_dir}/target/common/obj/JAVA_LIBRARIES
-common_targets="vogar ${java_libraries_dir}/core-tests_intermediates/javalib.jar apache-harmony-jdwp-tests-hostdex ${java_libraries_dir}/jsr166-tests_intermediates/javalib.jar ${out_dir}/host/linux-x86/bin/jack"
+common_targets="vogar core-tests apache-harmony-jdwp-tests-hostdex jsr166-tests ${out_dir}/host/linux-x86/bin/jack"
 mode="target"
 j_arg="-j$(nproc)"
 showcommands=
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 6d67f84..44206df 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -171,7 +171,7 @@
   bug: 25437292
 },
 {
-  description: "Failing tests after enso move.",
+  description: "Failing tests after OpenJDK move.",
   result: EXEC_FAILED,
   bug: 26326992,
   names: ["libcore.icu.RelativeDateTimeFormatterTest#test_getRelativeDateTimeStringDST",
@@ -196,6 +196,12 @@
           "org.apache.harmony.tests.java.text.DecimalFormatSymbolsTest#test_setInternationalCurrencySymbolLjava_lang_String",
           "org.apache.harmony.tests.java.text.DecimalFormatTest#testSerializationHarmonyRICompatible",
           "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parseLjava_lang_StringLjava_text_ParsePosition",
+          "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parse_W_w_dd_MMMM_yyyy_EEEE",
+          "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parse_dayOfYearPatterns",
+          "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parse_h_m_z",
+          "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parse_h_z_2DigitOffsetFromGMT",
+          "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parse_h_z_4DigitOffsetFromGMT",
+          "org.apache.harmony.tests.java.text.SimpleDateFormatTest#test_parse_h_z_4DigitOffsetNoGMT",
           "org.apache.harmony.tests.java.util.jar.JarFileTest#test_getInputStreamLjava_util_jar_JarEntry_subtest0",
           "libcore.java.util.CalendarTest#test_clear_45877",
           "org.apache.harmony.crypto.tests.javax.crypto.spec.SecretKeySpecTest#testGetFormat",
diff --git a/tools/libcore_failures_concurrent_collector.txt b/tools/libcore_failures_concurrent_collector.txt
index 95d1292..d8ef9ba 100644
--- a/tools/libcore_failures_concurrent_collector.txt
+++ b/tools/libcore_failures_concurrent_collector.txt
@@ -27,7 +27,8 @@
   description: "TimeoutException on host-{x86,x86-64}-concurrent-collector",
   result: EXEC_FAILED,
   modes: [host],
-  names: ["libcore.java.util.zip.DeflaterOutputStreamTest#testSyncFlushDisabled",
+  names: ["libcore.java.util.zip.DeflaterOutputStreamTest#testSyncFlushEnabled",
+          "libcore.java.util.zip.DeflaterOutputStreamTest#testSyncFlushDisabled",
           "libcore.java.util.zip.GZIPOutputStreamTest#testSyncFlushEnabled",
           "libcore.java.util.zip.OldAndroidGZIPStreamTest#testGZIPStream",
           "libcore.java.util.zip.OldAndroidZipStreamTest#testZipStream",
@@ -40,7 +41,8 @@
   result: EXEC_FAILED,
   modes: [device],
   names: ["libcore.icu.RelativeDateTimeFormatterTest#test_bug25821045",
-          "libcore.java.text.SimpleDateFormatTest#testLocales"],
+          "libcore.java.text.SimpleDateFormatTest#testLocales",
+          "libcore.java.util.zip.ZipFileTest#testZipFileWithLotsOfEntries"],
   bug: 26711853
 }
 ]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index f346239..45fb4b4d 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -20,13 +20,13 @@
 fi
 
 # Jar containing jsr166 tests.
-jsr166_test_jar=${OUT_DIR-out}/target/common/obj/JAVA_LIBRARIES/jsr166-tests_intermediates/javalib.jar
+jsr166_test_jack=${OUT_DIR-out}/target/common/obj/JAVA_LIBRARIES/jsr166-tests_intermediates/classes.jack
 
 # Jar containing all the other tests.
-test_jar=${OUT_DIR-out}/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/javalib.jar
+test_jack=${OUT_DIR-out}/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jack
 
 
-if [ ! -f $test_jar ]; then
+if [ ! -f $test_jack ]; then
   echo "Before running, you must build core-tests, jsr166-tests and vogar: \
         make core-tests jsr166-tests vogar vogar.jar"
   exit 1
@@ -108,7 +108,11 @@
 # the default timeout.
 vogar_args="$vogar_args --timeout 480"
 
+# Use Jack with "1.8" configuration.
+export JACK_VERSION=`basename prebuilts/sdk/tools/jacks/*ALPHA* | sed 's/^jack-//' | sed 's/.jar$//'`
+vogar_args="$vogar_args --toolchain jack --language JN"
+
 # Run the tests using vogar.
 echo "Running tests for the following test packages:"
 echo ${working_packages[@]} | tr " " "\n"
-vogar $vogar_args --vm-arg -Xusejit:true $expectations --classpath $jsr166_test_jar --classpath $test_jar ${working_packages[@]}
+vogar $vogar_args --vm-arg -Xusejit:true $expectations --classpath $jsr166_test_jack --classpath $test_jack ${working_packages[@]}