Merge "art: convert makefiles to support multilib build"
diff --git a/Android.mk b/Android.mk
index b8d14e3..06bbc67 100644
--- a/Android.mk
+++ b/Android.mk
@@ -147,7 +147,7 @@
 	@echo test-art-host-interpreter PASSED
 
 .PHONY: test-art-host-dependencies
-test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) $(HOST_CORE_DEX_LOCATIONS) $(HOST_OUT_EXECUTABLES)/jasmin
+test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) $(HOST_CORE_DEX_LOCATIONS)
 
 .PHONY: test-art-host-gtest
 test-art-host-gtest: $(ART_HOST_TEST_TARGETS)
@@ -172,15 +172,15 @@
 
 define declare-test-art-host-run-test
 .PHONY: test-art-host-run-test-default-$(1)
-test-art-host-run-test-default-$(1): test-art-host-dependencies
-	art/test/run-test --host $(1)
+test-art-host-run-test-default-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
+	DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test --host $(1)
 	@echo test-art-host-run-test-default-$(1) PASSED
 
 TEST_ART_HOST_RUN_TEST_DEFAULT_TARGETS += test-art-host-run-test-default-$(1)
 
 .PHONY: test-art-host-run-test-interpreter-$(1)
-test-art-host-run-test-interpreter-$(1): test-art-host-dependencies
-	art/test/run-test --host --interpreter $(1)
+test-art-host-run-test-interpreter-$(1): test-art-host-dependencies $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
+	DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test --host --interpreter $(1)
 	@echo test-art-host-run-test-interpreter-$(1) PASSED
 
 TEST_ART_HOST_RUN_TEST_INTERPRETER_TARGETS += test-art-host-run-test-interpreter-$(1)
@@ -213,7 +213,7 @@
 	@echo test-art-target PASSED
 
 .PHONY: test-art-target-dependencies
-test-art-target-dependencies: $(ART_TARGET_TEST_DEPENDENCIES) $(ART_TEST_OUT)/libarttest.so $(HOST_OUT_EXECUTABLES)/jasmin
+test-art-target-dependencies: $(ART_TARGET_TEST_DEPENDENCIES) $(ART_TEST_OUT)/libarttest.so
 
 .PHONY: test-art-target-sync
 test-art-target-sync: test-art-target-dependencies
@@ -230,8 +230,8 @@
 
 define declare-test-art-target-run-test
 .PHONY: test-art-target-run-test-$(1)
-test-art-target-run-test-$(1): test-art-target-sync
-	art/test/run-test $(1)
+test-art-target-run-test-$(1): test-art-target-sync $(DX) $(HOST_OUT_EXECUTABLES)/jasmin
+	DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) art/test/run-test $(1)
 	@echo test-art-target-run-test-$(1) PASSED
 
 TEST_ART_TARGET_RUN_TEST_TARGETS += test-art-target-run-test-$(1)
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 332e505..791e954 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -17,14 +17,15 @@
 LOCAL_PATH := art
 
 TEST_COMMON_SRC_FILES := \
-	compiler/dex/arena_allocator_test.cc \
 	compiler/driver/compiler_driver_test.cc \
 	compiler/elf_writer_test.cc \
 	compiler/image_test.cc \
 	compiler/jni/jni_compiler_test.cc \
 	compiler/leb128_encoder_test.cc \
 	compiler/oat_test.cc \
+	compiler/optimizing/pretty_printer_test.cc \
 	compiler/output_stream_test.cc \
+	compiler/utils/arena_allocator_test.cc \
 	compiler/utils/dedupe_set_test.cc \
 	compiler/utils/arm/managed_register_arm_test.cc \
 	compiler/utils/x86/managed_register_x86_test.cc \
@@ -59,6 +60,7 @@
 	runtime/reference_table_test.cc \
 	runtime/runtime_test.cc \
 	runtime/thread_pool_test.cc \
+	runtime/transaction_test.cc \
 	runtime/utils_test.cc \
 	runtime/verifier/method_verifier_test.cc \
 	runtime/verifier/reg_type_test.cc \
diff --git a/compiler/Android.mk b/compiler/Android.mk
index c51087c..49fb05e 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -21,7 +21,6 @@
 LIBART_COMPILER_SRC_FILES := \
 	compiled_method.cc \
 	dex/local_value_numbering.cc \
-	dex/arena_allocator.cc \
 	dex/arena_bit_vector.cc \
 	dex/quick/arm/assemble_arm.cc \
 	dex/quick/arm/call_arm.cc \
@@ -81,7 +80,10 @@
 	llvm/runtime_support_builder.cc \
 	llvm/runtime_support_builder_arm.cc \
 	llvm/runtime_support_builder_x86.cc \
+	optimizing/builder.cc \
+	optimizing/nodes.cc \
 	trampolines/trampoline_compiler.cc \
+	utils/arena_allocator.cc \
 	utils/arm/assembler_arm.cc \
 	utils/arm/managed_register_arm.cc \
 	utils/assembler.cc \
@@ -90,6 +92,7 @@
 	utils/x86/assembler_x86.cc \
 	utils/x86/managed_register_x86.cc \
 	buffered_output_stream.cc \
+	compiler_backend.cc \
 	elf_fixup.cc \
 	elf_stripper.cc \
 	elf_writer.cc \
diff --git a/compiler/compiler_backend.cc b/compiler/compiler_backend.cc
new file mode 100644
index 0000000..b8f21a9
--- /dev/null
+++ b/compiler/compiler_backend.cc
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "compiler_backend.h"
+#include "elf_writer_quick.h"
+#include "dex/quick/mir_to_lir.h"
+#include "dex/mir_graph.h"
+#include "driver/compiler_driver.h"
+#include "mirror/art_method-inl.h"
+
+#ifdef ART_USE_PORTABLE_COMPILER
+#include "dex/portable/mir_to_gbc.h"
+#include "elf_writer_mclinker.h"
+#endif
+
+namespace art {
+
+#ifdef ART_SEA_IR_MODE
+extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler,
+                                                   const art::DexFile::CodeItem* code_item,
+                                                   uint32_t access_flags,
+                                                   art::InvokeType invoke_type,
+                                                   uint16_t class_def_idx,
+                                                   uint32_t method_idx,
+                                                   jobject class_loader,
+                                                   const art::DexFile& dex_file);
+#endif
+
+extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver);
+extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver);
+extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler,
+                                                      const art::DexFile::CodeItem* code_item,
+                                                      uint32_t access_flags,
+                                                      art::InvokeType invoke_type,
+                                                      uint16_t class_def_idx,
+                                                      uint32_t method_idx,
+                                                      jobject class_loader,
+                                                      const art::DexFile& dex_file);
+
+extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& compiler,
+                                                         uint32_t access_flags, uint32_t method_idx,
+                                                         const art::DexFile& dex_file);
+
+
+static CompiledMethod* TryCompileWithSeaIR(art::CompilerDriver& compiler,
+                                           const art::DexFile::CodeItem* code_item,
+                                           uint32_t access_flags,
+                                           art::InvokeType invoke_type,
+                                           uint16_t class_def_idx,
+                                           uint32_t method_idx,
+                                           jobject class_loader,
+                                           const art::DexFile& dex_file) {
+#ifdef ART_SEA_IR_MODE
+    bool use_sea = Runtime::Current()->IsSeaIRMode();
+    use_sea = use_sea &&
+        (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
+    if (use_sea) {
+      LOG(INFO) << "Using SEA IR to compile..." << std::endl;
+      return SeaIrCompileMethod(compiler,
+                                code_item,
+                                access_flags,
+                                invoke_type,
+                                class_def_idx,
+                                method_idx,
+                                class_loader,
+                                dex_file);
+  }
+#endif
+  return nullptr;
+}
+
+
+class QuickBackend : public CompilerBackend {
+ public:
+  QuickBackend() : CompilerBackend(100) {}
+
+  void Init(CompilerDriver& driver) const {
+    ArtInitQuickCompilerContext(driver);
+  }
+
+  void UnInit(CompilerDriver& driver) const {
+    ArtUnInitQuickCompilerContext(driver);
+  }
+
+  CompiledMethod* Compile(CompilerDriver& compiler,
+                          const DexFile::CodeItem* code_item,
+                          uint32_t access_flags,
+                          InvokeType invoke_type,
+                          uint16_t class_def_idx,
+                          uint32_t method_idx,
+                          jobject class_loader,
+                          const DexFile& dex_file) const {
+    CompiledMethod* method = TryCompileWithSeaIR(compiler,
+                                                 code_item,
+                                                 access_flags,
+                                                 invoke_type,
+                                                 class_def_idx,
+                                                 method_idx,
+                                                 class_loader,
+                                                 dex_file);
+    if (method != nullptr) return method;
+
+    return ArtQuickCompileMethod(compiler,
+                                 code_item,
+                                 access_flags,
+                                 invoke_type,
+                                 class_def_idx,
+                                 method_idx,
+                                 class_loader,
+                                 dex_file);
+  }
+
+  CompiledMethod* JniCompile(CompilerDriver& driver,
+                             uint32_t access_flags,
+                             uint32_t method_idx,
+                             const DexFile& dex_file) const {
+    return ArtQuickJniCompileMethod(driver, access_flags, method_idx, dex_file);
+  }
+
+  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
+    return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
+  }
+
+  bool WriteElf(art::File* file,
+                OatWriter& oat_writer,
+                const std::vector<const art::DexFile*>& dex_files,
+                const std::string& android_root,
+                bool is_host, const CompilerDriver& driver) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, driver);
+  }
+
+  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
+    Mir2Lir* mir_to_lir = nullptr;
+    switch (cu->instruction_set) {
+      case kThumb2:
+        mir_to_lir = ArmCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+        break;
+      case kMips:
+        mir_to_lir = MipsCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+        break;
+      case kX86:
+        mir_to_lir = X86CodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+        break;
+      default:
+        LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
+    }
+
+    /* The number of compiler temporaries depends on backend so set it up now if possible */
+    if (mir_to_lir) {
+      size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps();
+      bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
+      CHECK(set_max);
+    }
+    return mir_to_lir;;
+  }
+
+  void InitCompilationUnit(CompilationUnit& cu) const {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(QuickBackend);
+};
+
+#ifdef ART_USE_PORTABLE_COMPILER
+
+extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver);
+extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver);
+extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
+                                                 const art::DexFile::CodeItem* code_item,
+                                                 uint32_t access_flags,
+                                                 art::InvokeType invoke_type,
+                                                 uint16_t class_def_idx,
+                                                 uint32_t method_idx,
+                                                 jobject class_loader,
+                                                 const art::DexFile& dex_file);
+extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver,
+                                                        uint32_t access_flags, uint32_t method_idx,
+                                                        const art::DexFile& dex_file);
+
+
+class LLVMBackend : public CompilerBackend {
+ public:
+  LLVMBackend() : CompilerBackend(1000) {}
+
+  void Init(CompilerDriver& driver) const {
+    ArtInitCompilerContext(driver);
+  }
+
+  void UnInit(CompilerDriver& driver) const {
+    ArtUnInitCompilerContext(driver);
+  }
+
+  CompiledMethod* Compile(CompilerDriver& compiler,
+                          const DexFile::CodeItem* code_item,
+                          uint32_t access_flags,
+                          InvokeType invoke_type,
+                          uint16_t class_def_idx,
+                          uint32_t method_idx,
+                          jobject class_loader,
+                          const DexFile& dex_file) const {
+    CompiledMethod* method = TryCompileWithSeaIR(compiler,
+                                                 code_item,
+                                                 access_flags,
+                                                 invoke_type,
+                                                 class_def_idx,
+                                                 method_idx,
+                                                 class_loader,
+                                                 dex_file);
+    if (method != nullptr) return method;
+
+    return ArtCompileMethod(compiler,
+                            code_item,
+                            access_flags,
+                            invoke_type,
+                            class_def_idx,
+                            method_idx,
+                            class_loader,
+                            dex_file);
+  }
+
+  CompiledMethod* JniCompile(CompilerDriver& driver,
+                             uint32_t access_flags,
+                             uint32_t method_idx,
+                             const DexFile& dex_file) const {
+    return ArtLLVMJniCompileMethod(driver, access_flags, method_idx, dex_file);
+  }
+
+  uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
+    return reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
+  }
+
+  bool WriteElf(art::File* file,
+                OatWriter& oat_writer,
+                const std::vector<const art::DexFile*>& dex_files,
+                const std::string& android_root,
+                bool is_host, const CompilerDriver& driver) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    return art::ElfWriterMclinker::Create(
+        file, oat_writer, dex_files, android_root, is_host, driver);
+  }
+
+  Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
+    return PortableCodeGenerator(
+        cu, cu->mir_graph.get(), &cu->arena,
+        reinterpret_cast<art::llvm::LlvmCompilationUnit*>(compilation_unit));
+  }
+
+  void InitCompilationUnit(CompilationUnit& cu) const {
+      // Fused long branches not currently useful in bitcode.
+    cu.disable_opt |=
+        (1 << kBranchFusing) |
+        (1 << kSuppressExceptionEdges);
+  }
+
+  bool isPortable() const { return true; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LLVMBackend);
+};
+#endif
+
+CompilerBackend* CompilerBackend::Create(CompilerBackend::Kind kind) {
+  switch (kind) {
+    case kQuick:
+      return new QuickBackend();
+      break;
+    case kPortable:
+#ifdef ART_USE_PORTABLE_COMPILER
+      return new LLVMBackend();
+#else
+      LOG(FATAL) << "Portable compiler not compiled";
+#endif
+      break;
+    default:
+      LOG(FATAL) << "UNREACHABLE";
+  }
+  return nullptr;
+}
+
+}  // namespace art
diff --git a/compiler/compiler_backend.h b/compiler/compiler_backend.h
new file mode 100644
index 0000000..b20c125
--- /dev/null
+++ b/compiler/compiler_backend.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_COMPILER_BACKEND_H_
+#define ART_COMPILER_COMPILER_BACKEND_H_
+
+#include "dex_file.h"
+#include "os.h"
+
+namespace art {
+
+class Backend;
+class CompilationUnit;
+class CompilerDriver;
+class CompiledMethod;
+class MIRGraph;
+class OatWriter;
+
+namespace mirror {
+  class ArtMethod;
+}
+
+class CompilerBackend {
+ public:
+  enum Kind {
+    kQuick,
+    kPortable
+  };
+
+  explicit CompilerBackend(int warning)
+      : maximum_compilation_time_before_warning_(warning) {}
+
+  static CompilerBackend* Create(Kind kind);
+
+  virtual void Init(CompilerDriver& driver) const = 0;
+
+  virtual void UnInit(CompilerDriver& driver) const = 0;
+
+  virtual CompiledMethod* Compile(CompilerDriver& compiler,
+                                  const DexFile::CodeItem* code_item,
+                                  uint32_t access_flags,
+                                  InvokeType invoke_type,
+                                  uint16_t class_def_idx,
+                                  uint32_t method_idx,
+                                  jobject class_loader,
+                                  const DexFile& dex_file) const = 0;
+
+  virtual CompiledMethod* JniCompile(CompilerDriver& driver,
+                                     uint32_t access_flags,
+                                     uint32_t method_idx,
+                                     const DexFile& dex_file) const = 0;
+
+  virtual uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const = 0;
+
+  virtual bool WriteElf(art::File* file,
+                        OatWriter& oat_writer,
+                        const std::vector<const art::DexFile*>& dex_files,
+                        const std::string& android_root,
+                        bool is_host, const CompilerDriver& driver) const
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
+  virtual Backend* GetCodeGenerator(CompilationUnit* cu,
+                                    void* compilation_unit) const = 0;
+
+  uint64_t GetMaximumCompilationTimeBeforeWarning() const {
+    return maximum_compilation_time_before_warning_;
+  }
+
+  virtual bool IsPortable() const { return false; }
+
+  virtual void InitCompilationUnit(CompilationUnit& cu) const = 0;
+
+  virtual ~CompilerBackend() {}
+
+ private:
+  uint64_t maximum_compilation_time_before_warning_;
+
+  DISALLOW_COPY_AND_ASSIGN(CompilerBackend);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_COMPILER_BACKEND_H_
diff --git a/compiler/dex/arena_bit_vector.h b/compiler/dex/arena_bit_vector.h
index 4b2193a..e904406 100644
--- a/compiler/dex/arena_bit_vector.h
+++ b/compiler/dex/arena_bit_vector.h
@@ -17,9 +17,9 @@
 #ifndef ART_COMPILER_DEX_ARENA_BIT_VECTOR_H_
 #define ART_COMPILER_DEX_ARENA_BIT_VECTOR_H_
 
-#include "arena_allocator.h"
 #include "base/bit_vector.h"
 #include "compiler_enums.h"
+#include "utils/arena_allocator.h"
 
 namespace art {
 
diff --git a/compiler/dex/backend.h b/compiler/dex/backend.h
index 01959b7..596b3c9 100644
--- a/compiler/dex/backend.h
+++ b/compiler/dex/backend.h
@@ -17,11 +17,11 @@
 #ifndef ART_COMPILER_DEX_BACKEND_H_
 #define ART_COMPILER_DEX_BACKEND_H_
 
-#include "compiled_method.h"
-#include "arena_allocator.h"
-
 namespace art {
 
+class ArenaAllocator;
+class CompiledMethod;
+
 class Backend {
   public:
     virtual ~Backend() {}
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index 32fd79b..ded8005 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -19,7 +19,6 @@
 
 #include <vector>
 #include <llvm/IR/Module.h>
-#include "arena_allocator.h"
 #include "compiler_enums.h"
 #include "dex/quick/mir_to_lir.h"
 #include "dex_instruction.h"
@@ -29,6 +28,7 @@
 #include "llvm/ir_builder.h"
 #include "safe_map.h"
 #include "base/timing_logger.h"
+#include "utils/arena_allocator.h"
 
 namespace art {
 
@@ -68,7 +68,7 @@
   uint32_t disable_opt;                // opt_control_vector flags.
   uint32_t enable_debug;               // debugControlVector flags.
   bool verbose;
-  CompilerBackend compiler_backend;
+  const CompilerBackend* compiler_backend;
   InstructionSet instruction_set;
 
   const InstructionSetFeatures& GetInstructionSetFeatures() {
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 8f83cd0..591d92a 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-#include <llvm/Support/Threading.h>
-
+#include "compiler_backend.h"
 #include "compiler_internals.h"
 #include "driver/compiler_driver.h"
 #include "dataflow_iterator-inl.h"
@@ -27,42 +26,9 @@
 #include "base/logging.h"
 #include "base/timing_logger.h"
 
-#if defined(ART_USE_PORTABLE_COMPILER)
-#include "dex/portable/mir_to_gbc.h"
-#include "llvm/llvm_compilation_unit.h"
-#endif
-
 #include "dex/quick/dex_file_to_method_inliner_map.h"
 
-namespace {
-#if !defined(ART_USE_PORTABLE_COMPILER)
-  pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT;
-#endif
-  void InitializeLLVMForQuick() {
-    ::llvm::llvm_start_multithreaded();
-  }
-}
-
 namespace art {
-namespace llvm {
-::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
-}
-
-LLVMInfo::LLVMInfo() {
-#if !defined(ART_USE_PORTABLE_COMPILER)
-  pthread_once(&llvm_multi_init, InitializeLLVMForQuick);
-#endif
-  // Create context, module, intrinsic helper & ir builder
-  llvm_context_.reset(new ::llvm::LLVMContext());
-  llvm_module_ = new ::llvm::Module("art", *llvm_context_);
-  ::llvm::StructType::create(*llvm_context_, "JavaObject");
-  art::llvm::makeLLVMModuleContents(llvm_module_);
-  intrinsic_helper_.reset(new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_));
-  ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_));
-}
-
-LLVMInfo::~LLVMInfo() {
-}
 
 extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver) {
   CHECK(driver.GetCompilerContext() == NULL);
@@ -123,7 +89,7 @@
     disable_opt(0),
     enable_debug(0),
     verbose(false),
-    compiler_backend(kNoBackend),
+    compiler_backend(NULL),
     instruction_set(kNone),
     num_dalvik_registers(0),
     insns(NULL),
@@ -163,15 +129,12 @@
 }
 
 static CompiledMethod* CompileMethod(CompilerDriver& compiler,
-                                     const CompilerBackend compiler_backend,
+                                     CompilerBackend* compiler_backend,
                                      const DexFile::CodeItem* code_item,
                                      uint32_t access_flags, InvokeType invoke_type,
                                      uint16_t class_def_idx, uint32_t method_idx,
-                                     jobject class_loader, const DexFile& dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
-                                     , llvm::LlvmCompilationUnit* llvm_compilation_unit
-#endif
-) {
+                                     jobject class_loader, const DexFile& dex_file,
+                                     void* llvm_compilation_unit) {
   VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
   if (code_item->insns_size_in_code_units_ >= 0x10000) {
     LOG(INFO) << "Method size exceeds compiler limits: " << code_item->insns_size_in_code_units_
@@ -211,12 +174,7 @@
    * MIR and backend flags?  Need command-line setting as well.
    */
 
-  if (compiler_backend == kPortable) {
-    // Fused long branches not currently useful in bitcode.
-    cu.disable_opt |=
-        (1 << kBranchFusing) |
-        (1 << kSuppressExceptionEdges);
-  }
+  compiler_backend->InitCompilationUnit(cu);
 
   if (cu.instruction_set == kMips) {
     // Disable some optimizations for mips for now
@@ -241,37 +199,7 @@
    * The reason we do this is that optimizations on the MIR graph may need to get information
    * that is only available if a CG exists.
    */
-#if defined(ART_USE_PORTABLE_COMPILER)
-  if (compiler_backend == kPortable) {
-    cu.cg.reset(PortableCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena, llvm_compilation_unit));
-  } else {
-#endif
-    Mir2Lir* mir_to_lir = nullptr;
-    switch (compiler.GetInstructionSet()) {
-      case kThumb2:
-        mir_to_lir = ArmCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena);
-        break;
-      case kMips:
-        mir_to_lir = MipsCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena);
-        break;
-      case kX86:
-        mir_to_lir = X86CodeGenerator(&cu, cu.mir_graph.get(), &cu.arena);
-        break;
-      default:
-        LOG(FATAL) << "Unexpected instruction set: " << compiler.GetInstructionSet();
-    }
-
-    cu.cg.reset(mir_to_lir);
-
-    /* The number of compiler temporaries depends on backend so set it up now if possible */
-    if (mir_to_lir) {
-      size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps();
-      bool set_max = cu.mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
-      CHECK(set_max);
-    }
-#if defined(ART_USE_PORTABLE_COMPILER)
-  }
-#endif
+  cu.cg.reset(compiler_backend->GetCodeGenerator(&cu, llvm_compilation_unit));
 
   /* Gathering opcode stats? */
   if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
@@ -283,11 +211,9 @@
                               class_loader, dex_file);
 
   cu.NewTimingSplit("MIROpt:CheckFilters");
-#if !defined(ART_USE_PORTABLE_COMPILER)
   if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) {
     return NULL;
   }
-#endif
 
   /* Create the pass driver and launch it */
   PassDriver driver(&cu);
@@ -338,7 +264,7 @@
 }
 
 CompiledMethod* CompileOneMethod(CompilerDriver& compiler,
-                                 const CompilerBackend backend,
+                                 CompilerBackend* backend,
                                  const DexFile::CodeItem* code_item,
                                  uint32_t access_flags,
                                  InvokeType invoke_type,
@@ -346,13 +272,9 @@
                                  uint32_t method_idx,
                                  jobject class_loader,
                                  const DexFile& dex_file,
-                                 llvm::LlvmCompilationUnit* llvm_compilation_unit) {
+                                 void* compilation_unit) {
   return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx,
-                       method_idx, class_loader, dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
-                       , llvm_compilation_unit
-#endif
-                       );  // NOLINT(whitespace/parens)
+                       method_idx, class_loader, dex_file, compilation_unit);
 }
 
 }  // namespace art
@@ -364,7 +286,7 @@
                           uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
                           const art::DexFile& dex_file) {
   // TODO: check method fingerprint here to determine appropriate backend type.  Until then, use build default
-  art::CompilerBackend backend = compiler.GetCompilerBackend();
+  art::CompilerBackend* backend = compiler.GetCompilerBackend();
   return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type,
                                class_def_idx, method_idx, class_loader, dex_file,
                                NULL /* use thread llvm_info */);
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 10bcdb9..dfd8e63 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -881,6 +881,23 @@
   }
 }
 
+MIR* MIRGraph::GetNextUnconditionalMir(BasicBlock* bb, MIR* current) {
+  MIR* next_mir = nullptr;
+
+  if (current != nullptr) {
+    next_mir = current->next;
+  }
+
+  if (next_mir == nullptr) {
+    // Only look for next MIR that follows unconditionally.
+    if ((bb->taken == NullBasicBlockId) && (bb->fall_through != NullBasicBlockId)) {
+      next_mir = GetBasicBlock(bb->fall_through)->first_mir_insn;
+    }
+  }
+
+  return next_mir;
+}
+
 char* MIRGraph::GetDalvikDisassembly(const MIR* mir) {
   DecodedInstruction insn = mir->dalvikInsn;
   std::string str;
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index f8706c4..d304db9 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -21,7 +21,7 @@
 #include "dex_instruction.h"
 #include "compiler_ir.h"
 #include "arena_bit_vector.h"
-#include "growable_array.h"
+#include "utils/growable_array.h"
 
 namespace art {
 
@@ -721,6 +721,17 @@
   void AppendMIR(BasicBlock* bb, MIR* mir);
   void PrependMIR(BasicBlock* bb, MIR* mir);
   void InsertMIRAfter(BasicBlock* bb, MIR* current_mir, MIR* new_mir);
+
+  /**
+   * @brief Used to obtain the next MIR that follows unconditionally.
+   * @details The implementation does not guarantee that a MIR does not
+   * follow even if this method returns nullptr.
+   * @param bb The basic block of "current" MIR.
+   * @param current The MIR for which to find an unconditional follower.
+   * @return Returns the following MIR if one can be found.
+   */
+  MIR* GetNextUnconditionalMir(BasicBlock* bb, MIR* current);
+
   char* GetDalvikDisassembly(const MIR* mir);
   void ReplaceSpecialChars(std::string& str);
   std::string GetSSAName(int ssa_reg);
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 209ed3d..b91ef28 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -406,7 +406,7 @@
       // Is this the select pattern?
       // TODO: flesh out support for Mips.  NOTE: llvm's select op doesn't quite work here.
       // TUNING: expand to support IF_xx compare & branches
-      if ((cu_->compiler_backend != kPortable) &&
+      if (cu_->compiler_backend->IsPortable() &&
           (cu_->instruction_set == kThumb2 || cu_->instruction_set == kX86) &&
           ((mir->dalvikInsn.opcode == Instruction::IF_EQZ) ||
           (mir->dalvikInsn.opcode == Instruction::IF_NEZ))) {
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index e6cc2de..3187fbb 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -41,6 +41,22 @@
 const char kCatchBlock = 'C';
 
 namespace art {
+namespace llvm {
+::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
+}
+
+LLVMInfo::LLVMInfo() {
+  // Create context, module, intrinsic helper & ir builder
+  llvm_context_.reset(new ::llvm::LLVMContext());
+  llvm_module_ = new ::llvm::Module("art", *llvm_context_);
+  ::llvm::StructType::create(*llvm_context_, "JavaObject");
+  art::llvm::makeLLVMModuleContents(llvm_module_);
+  intrinsic_helper_.reset(new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_));
+  ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_));
+}
+
+LLVMInfo::~LLVMInfo() {
+}
 
 ::llvm::BasicBlock* MirConverter::GetLLVMBlock(int id) {
   return id_to_block_map_.Get(id);
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index a30e80a..b36dde9 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -18,225 +18,11 @@
 
 #include "arm_lir.h"
 #include "codegen_arm.h"
-#include "dex/quick/dex_file_method_inliner.h"
 #include "dex/quick/mir_to_lir-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 
 namespace art {
 
-// TODO: generalize & move to RegUtil.cc
-// The number of dalvik registers passed in core registers.
-constexpr int kInArgsInCoreRegs = 3;
-// The core register corresponding to the first (index 0) input argument.
-constexpr int kInArg0CoreReg = r1;  // r0 is Method*.
-// Offset, in words, for getting args from stack (even core reg args have space on stack).
-constexpr int kInArgToStackOffset = 1;
-
-/* Lock argument if it's in register. */
-void ArmMir2Lir::LockArg(int in_position, bool wide) {
-  if (in_position < kInArgsInCoreRegs) {
-    LockTemp(kInArg0CoreReg + in_position);
-  }
-  if (wide && in_position + 1 < kInArgsInCoreRegs) {
-    LockTemp(kInArg0CoreReg + in_position + 1);
-  }
-}
-
-/* Load argument into register. LockArg(in_position, wide) must have been previously called. */
-int ArmMir2Lir::LoadArg(int in_position, bool wide) {
-  if (in_position < kInArgsInCoreRegs) {
-    int low_reg = kInArg0CoreReg + in_position;
-    if (!wide) {
-      return low_reg;
-    }
-    int high_reg = (in_position != kInArgsInCoreRegs - 1) ? low_reg + 1 : LoadArg(in_position + 1);
-    return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
-  }
-  int low_reg = AllocTemp();
-  int offset = (in_position + kInArgToStackOffset) * sizeof(uint32_t);
-  if (!wide) {
-    LoadWordDisp(rARM_SP, offset, low_reg);
-    return low_reg;
-  }
-  int high_reg = AllocTemp();
-  LoadBaseDispWide(rARM_SP, offset, low_reg, high_reg, INVALID_SREG);
-  return (low_reg & 0xff) | ((high_reg & 0xff) << 8);
-}
-
-void ArmMir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
-  int reg = kInArg0CoreReg + in_position;
-  int offset = (in_position + kInArgToStackOffset) * sizeof(uint32_t);
-  if (!rl_dest.wide) {
-    if (in_position < kInArgsInCoreRegs) {
-      OpRegCopy(rl_dest.low_reg, reg);
-    } else {
-      LoadWordDisp(rARM_SP, offset, rl_dest.low_reg);
-    }
-  } else {
-    if (in_position < kInArgsInCoreRegs - 1) {
-      OpRegCopyWide(rl_dest.low_reg, rl_dest.high_reg, reg, reg + 1);
-    } else if (in_position == kInArgsInCoreRegs - 1) {
-      OpRegCopy(rl_dest.low_reg, reg);
-      LoadWordDisp(rARM_SP, offset + sizeof(uint32_t), rl_dest.high_reg);
-    } else {
-      LoadBaseDispWide(rARM_SP, offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
-    }
-  }
-}
-
-/* Find the next MIR, which may be in a following basic block */
-// TODO: make this a utility in mir_graph.
-MIR* ArmMir2Lir::GetNextMir(BasicBlock** p_bb, MIR* mir) {
-  BasicBlock* bb = *p_bb;
-  MIR* orig_mir = mir;
-  while (bb != NULL) {
-    if (mir != NULL) {
-      mir = mir->next;
-    }
-    if (mir != NULL) {
-      return mir;
-    } else {
-      bb = mir_graph_->GetBasicBlock(bb->fall_through);
-      *p_bb = bb;
-      if (bb) {
-         mir = bb->first_mir_insn;
-         if (mir != NULL) {
-           return mir;
-         }
-      }
-    }
-  }
-  return orig_mir;
-}
-
-/* Used for the "verbose" listing */
-// TODO:  move to common code
-void ArmMir2Lir::GenPrintLabel(MIR* mir) {
-  /* Mark the beginning of a Dalvik instruction for line tracking */
-  if (cu_->verbose) {
-    char* inst_str = mir_graph_->GetDalvikDisassembly(mir);
-    MarkBoundary(mir->offset, inst_str);
-  }
-}
-
-MIR* ArmMir2Lir::SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
-  // FastInstance() already checked by DexFileMethodInliner.
-  const InlineIGetIPutData& data = special.d.ifield_data;
-  if (data.method_is_static || data.object_arg != 0) {
-    return NULL;  // The object is not "this" and has to be null-checked.
-  }
-
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
-
-  // Point of no return - no aborts after this
-  ArmMir2Lir::GenPrintLabel(mir);
-  LockArg(data.object_arg);
-  RegLocation rl_dest = wide ? GetReturnWide(false) : GetReturn(false);
-  int reg_obj = LoadArg(data.object_arg);
-  if (wide) {
-    LoadBaseDispWide(reg_obj, data.field_offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
-  } else {
-    LoadBaseDisp(reg_obj, data.field_offset, rl_dest.low_reg, kWord, INVALID_SREG);
-  }
-  if (data.is_volatile) {
-    GenMemBarrier(kLoadLoad);
-  }
-  return GetNextMir(bb, mir);
-}
-
-MIR* ArmMir2Lir::SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special) {
-  // FastInstance() already checked by DexFileMethodInliner.
-  const InlineIGetIPutData& data = special.d.ifield_data;
-  if (data.method_is_static || data.object_arg != 0) {
-    return NULL;  // The object is not "this" and has to be null-checked.
-  }
-
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
-
-  // Point of no return - no aborts after this
-  ArmMir2Lir::GenPrintLabel(mir);
-  LockArg(data.object_arg);
-  LockArg(data.src_arg, wide);
-  int reg_obj = LoadArg(data.object_arg);
-  int reg_src = LoadArg(data.src_arg, wide);
-  if (data.is_volatile) {
-    GenMemBarrier(kStoreStore);
-  }
-  if (wide) {
-    StoreBaseDispWide(reg_obj, data.field_offset, reg_src & 0xff, reg_src >> 8);
-  } else {
-    StoreBaseDisp(reg_obj, data.field_offset, reg_src, kWord);
-  }
-  if (data.is_volatile) {
-    GenMemBarrier(kLoadLoad);
-  }
-  if (data.is_object) {
-    MarkGCCard(reg_src, reg_obj);
-  }
-  return GetNextMir(bb, mir);
-}
-
-MIR* ArmMir2Lir::SpecialIdentity(MIR* mir, const InlineMethod& special) {
-  const InlineReturnArgData& data = special.d.return_data;
-  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
-  bool wide = (data.op_size == kLong);
-
-  // Point of no return - no aborts after this
-  ArmMir2Lir::GenPrintLabel(mir);
-  LockArg(data.arg, wide);
-  RegLocation rl_dest = wide ? GetReturnWide(false) : GetReturn(false);
-  LoadArgDirect(data.arg, rl_dest);
-  return mir;
-}
-
-/*
- * Special-case code genration for simple non-throwing leaf methods.
- */
-void ArmMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
-                                const InlineMethod& special) {
-  DCHECK(special.flags & kInlineSpecial);
-  current_dalvik_offset_ = mir->offset;
-  MIR* next_mir = NULL;
-  switch (special.opcode) {
-    case kInlineOpNop:
-      DCHECK(mir->dalvikInsn.opcode == Instruction::RETURN_VOID);
-      next_mir = mir;
-      break;
-    case kInlineOpConst:
-      ArmMir2Lir::GenPrintLabel(mir);
-      LoadConstant(rARM_RET0, static_cast<int>(special.d.data));
-      next_mir = GetNextMir(&bb, mir);
-      break;
-    case kInlineOpIGet:
-      next_mir = SpecialIGet(&bb, mir, special);
-      break;
-    case kInlineOpIPut:
-      next_mir = SpecialIPut(&bb, mir, special);
-      break;
-    case kInlineOpReturnArg:
-      next_mir = SpecialIdentity(mir, special);
-      break;
-    default:
-      return;
-  }
-  if (next_mir != NULL) {
-    current_dalvik_offset_ = next_mir->offset;
-    if (special.opcode != kInlineOpReturnArg) {
-      ArmMir2Lir::GenPrintLabel(next_mir);
-    }
-    NewLIR1(kThumbBx, rARM_LR);
-    core_spill_mask_ = 0;
-    num_core_spills_ = 0;
-    fp_spill_mask_ = 0;
-    num_fp_spills_ = 0;
-    frame_size_ = 0;
-    core_vmap_table_.clear();
-    fp_vmap_table_.clear();
-  }
-}
-
 /*
  * The sparse table in the literal pool is an array of <key,displacement>
  * pairs.  For each set, we'll load them as a pair using ldmia.
@@ -610,4 +396,8 @@
   }
 }
 
+void ArmMir2Lir::GenSpecialExitSequence() {
+  NewLIR1(kThumbBx, rARM_LR);
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index 7ee241c..65dee80 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -52,6 +52,7 @@
     int AllocTypedTempPair(bool fp_hint, int reg_class);
     int S2d(int low_reg, int high_reg);
     int TargetReg(SpecialTargetRegister reg);
+    int GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
     RegLocation GetReturnWideAlt();
     RegLocation LocCReturn();
@@ -122,6 +123,7 @@
     void GenDivZeroCheck(int reg_lo, int reg_hi);
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
+    void GenSpecialExitSequence();
     void GenFillArrayData(DexOffset table_offset, RegLocation rl_src);
     void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
     void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
@@ -136,7 +138,6 @@
     void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
     void GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
     void GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
-    void GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
 
     // Required for target - single operation generators.
     LIR* OpUnconditionalBranch(LIR* target);
@@ -170,7 +171,6 @@
     LIR* LoadBaseDispBody(int rBase, int displacement, int r_dest, int r_dest_hi, OpSize size,
                           int s_reg);
     LIR* StoreBaseDispBody(int rBase, int displacement, int r_src, int r_src_hi, OpSize size);
-    void GenPrintLabel(MIR* mir);
     LIR* OpRegRegRegShift(OpKind op, int r_dest, int r_src1, int r_src2, int shift);
     LIR* OpRegRegShift(OpKind op, int r_dest_src1, int r_src2, int shift);
     static const ArmEncodingMap EncodingMap[kArmLast];
@@ -185,13 +185,6 @@
   private:
     void GenFusedLongCmpImmBranch(BasicBlock* bb, RegLocation rl_src1, int64_t val,
                                   ConditionCode ccode);
-    void LockArg(int in_position, bool wide = false);
-    int LoadArg(int in_position, bool wide = false);
-    void LoadArgDirect(int in_position, RegLocation rl_dest);
-    MIR* GetNextMir(BasicBlock** p_bb, MIR* mir);
-    MIR* SpecialIGet(BasicBlock** bb, MIR* mir, const InlineMethod& special);
-    MIR* SpecialIPut(BasicBlock** bb, MIR* mir, const InlineMethod& special);
-    MIR* SpecialIdentity(MIR* mir, const InlineMethod& special);
     LIR* LoadFPConstantValue(int r_dest, int value);
     void ReplaceFixup(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
     void InsertFixupBefore(LIR* prev_lir, LIR* orig_lir, LIR* new_lir);
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index ceec7d5..83431ad 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -83,6 +83,19 @@
   return res;
 }
 
+int ArmMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
+  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
+  switch (arg_num) {
+    case 0:
+      return rARM_ARG1;
+    case 1:
+      return rARM_ARG2;
+    case 2:
+      return rARM_ARG3;
+    default:
+      return INVALID_REG;
+  }
+}
 
 // Create a double from a pair of singles.
 int ArmMir2Lir::S2d(int low_reg, int high_reg) {
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 05eb360..c5dccda 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1017,19 +1017,13 @@
   /* Allocate Registers using simple local allocation scheme */
   SimpleRegAlloc();
 
-  /*
-   * Custom codegen for special cases.  If for any reason the
-   * special codegen doesn't succeed, first_lir_insn_ will be
-   * set to NULL;
-   */
-  // TODO: Clean up GenSpecial() and return true only if special implementation is emitted.
-  // Currently, GenSpecial() returns IsSpecial() but doesn't check after SpecialMIR2LIR().
+  /* First try the custom light codegen for special cases. */
   DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
-  cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
+  bool special_worked = cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file)
       ->GenSpecial(this, cu_->method_idx);
 
-  /* Convert MIR to LIR, etc. */
-  if (first_lir_insn_ == NULL) {
+  /* Take normal path for converting MIR to LIR only if the special codegen did not succeed. */
+  if (special_worked == false) {
     MethodMIR2LIR();
   }
 
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 389dd9a..cb424d9 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -271,6 +271,13 @@
 }
 
 bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier) {
+  InlineMethod method;
+  bool success = AnalyseMethodCode(verifier, &method);
+  return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
+}
+
+bool DexFileMethodInliner::AnalyseMethodCode(verifier::MethodVerifier* verifier,
+                                             InlineMethod* method) {
   // We currently support only plain return or 2-instruction methods.
 
   const DexFile::CodeItem* code_item = verifier->CodeItem();
@@ -278,27 +285,22 @@
   const Instruction* instruction = Instruction::At(code_item->insns_);
   Instruction::Code opcode = instruction->Opcode();
 
-  InlineMethod method;
-  bool success;
   switch (opcode) {
     case Instruction::RETURN_VOID:
-      method.opcode = kInlineOpNop;
-      method.flags = kInlineSpecial;
-      method.d.data = 0u;
-      success = true;
-      break;
+      method->opcode = kInlineOpNop;
+      method->flags = kInlineSpecial;
+      method->d.data = 0u;
+      return true;
     case Instruction::RETURN:
     case Instruction::RETURN_OBJECT:
     case Instruction::RETURN_WIDE:
-      success = AnalyseReturnMethod(code_item, &method);
-      break;
+      return AnalyseReturnMethod(code_item, method);
     case Instruction::CONST:
     case Instruction::CONST_4:
     case Instruction::CONST_16:
     case Instruction::CONST_HIGH16:
       // TODO: Support wide constants (RETURN_WIDE).
-      success = AnalyseConstMethod(code_item, &method);
-      break;
+      return AnalyseConstMethod(code_item, method);
     case Instruction::IGET:
     case Instruction::IGET_OBJECT:
     case Instruction::IGET_BOOLEAN:
@@ -306,8 +308,7 @@
     case Instruction::IGET_CHAR:
     case Instruction::IGET_SHORT:
     case Instruction::IGET_WIDE:
-      success = AnalyseIGetMethod(verifier, &method);
-      break;
+      return AnalyseIGetMethod(verifier, method);
     case Instruction::IPUT:
     case Instruction::IPUT_OBJECT:
     case Instruction::IPUT_BOOLEAN:
@@ -315,13 +316,10 @@
     case Instruction::IPUT_CHAR:
     case Instruction::IPUT_SHORT:
     case Instruction::IPUT_WIDE:
-      success = AnalyseIPutMethod(verifier, &method);
-      break;
+      return AnalyseIPutMethod(verifier, method);
     default:
-      success = false;
-      break;
+      return false;
   }
-  return success && AddInlineMethod(verifier->GetMethodReference().dex_method_index, method);
 }
 
 bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) {
@@ -407,9 +405,7 @@
     }
     special = it->second;
   }
-  // TODO: Return true only if special implementation is emitted.
-  backend->SpecialMIR2LIR(special);
-  return true;
+  return backend->SpecialMIR2LIR(special);
 }
 
 uint32_t DexFileMethodInliner::FindClassIndex(const DexFile* dex_file, IndexCache* cache,
@@ -596,7 +592,7 @@
   if (return_opcode == Instruction::RETURN_OBJECT && vB != 0) {
     return false;  // Returning non-null reference constant?
   }
-  result->opcode = kInlineOpConst;
+  result->opcode = kInlineOpNonWideConst;
   result->flags = kInlineSpecial;
   result->d.data = static_cast<uint64_t>(vB);
   return true;
@@ -633,6 +629,11 @@
     return false;  // Not returning the value retrieved by IGET?
   }
 
+  if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
+    // TODO: Support inlining IGET on other register than "this".
+    return false;
+  }
+
   if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, false, verifier,
                                                   &result->d.ifield_data)) {
     return false;
@@ -645,6 +646,7 @@
   data->is_object = (opcode == Instruction::IGET_OBJECT) ? 1u : 0u;
   data->object_arg = object_reg - arg_start;  // Allow IGET on any register, not just "this".
   data->src_arg = 0;
+  data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
   data->reserved = 0;
   return true;
 }
@@ -676,6 +678,11 @@
   DCHECK_GE(src_reg, arg_start);
   DCHECK_LT(size == kLong ? src_reg + 1 : src_reg, code_item->registers_size_);
 
+  if ((verifier->GetAccessFlags() & kAccStatic) != 0 || object_reg != arg_start) {
+    // TODO: Support inlining IPUT on other register than "this".
+    return false;
+  }
+
   if (!CompilerDriver::ComputeSpecialAccessorInfo(field_idx, true, verifier,
                                                   &result->d.ifield_data)) {
     return false;
@@ -688,6 +695,7 @@
   data->is_object = (opcode == Instruction::IPUT_OBJECT) ? 1u : 0u;
   data->object_arg = object_reg - arg_start;  // Allow IPUT on any register, not just "this".
   data->src_arg = src_reg - arg_start;
+  data->method_is_static = (verifier->GetAccessFlags() & kAccStatic) != 0;
   data->reserved = 0;
   return true;
 }
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index fb7528e..3dcb964 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -57,7 +57,7 @@
 
   kInlineOpNop,
   kInlineOpReturnArg,
-  kInlineOpConst,
+  kInlineOpNonWideConst,
   kInlineOpIGet,
   kInlineOpIPut,
 };
@@ -150,13 +150,24 @@
      * Analyse method code to determine if the method is a candidate for inlining.
      * If it is, record its data for later.
      *
-     * @param method_idx the index of the inlining candidate.
-     * @param code_item a previously verified code item of the method.
+     * @param verifier the method verifier holding data about the method to analyse.
+     * @return true if the method is a candidate for inlining, false otherwise.
      */
     bool AnalyseMethodCode(verifier::MethodVerifier* verifier)
         SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
 
     /**
+     * Analyse method code to determine if the method is a candidate for inlining.
+     * If it is, record the inlining data.
+     *
+     * @param verifier the method verifier holding data about the method to analyse.
+     * @param method placeholder for the inline method data.
+     * @return true if the method is a candidate for inlining, false otherwise.
+     */
+    bool AnalyseMethodCode(verifier::MethodVerifier* verifier, InlineMethod* method)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+
+    /**
      * Check whether a particular method index corresponds to an intrinsic function.
      */
     bool IsIntrinsic(uint32_t method_index) LOCKS_EXCLUDED(lock_);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index ee61c8b..5fa4596 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -293,10 +293,10 @@
     StoreWordDisp(TargetReg(kSp), 0, TargetReg(kArg0));
   }
 
-  if (cu_->num_ins == 0)
+  if (cu_->num_ins == 0) {
     return;
-  const int num_arg_regs = 3;
-  static SpecialTargetRegister arg_regs[] = {kArg1, kArg2, kArg3};
+  }
+
   int start_vreg = cu_->num_dalvik_registers - cu_->num_ins;
   /*
    * Copy incoming arguments to their proper home locations.
@@ -312,15 +312,17 @@
    */
   for (int i = 0; i < cu_->num_ins; i++) {
     PromotionMap* v_map = &promotion_map_[start_vreg + i];
-    if (i < num_arg_regs) {
+    int reg = GetArgMappingToPhysicalReg(i);
+
+    if (reg != INVALID_REG) {
       // If arriving in register
       bool need_flush = true;
       RegLocation* t_loc = &ArgLocs[i];
       if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) {
-        OpRegCopy(v_map->core_reg, TargetReg(arg_regs[i]));
+        OpRegCopy(v_map->core_reg, reg);
         need_flush = false;
       } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) {
-        OpRegCopy(v_map->FpReg, TargetReg(arg_regs[i]));
+        OpRegCopy(v_map->FpReg, reg);
         need_flush = false;
       } else {
         need_flush = true;
@@ -350,8 +352,7 @@
         }
       }
       if (need_flush) {
-        StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i),
-                      TargetReg(arg_regs[i]), kWord);
+        StoreBaseDisp(TargetReg(kSp), SRegOffset(start_vreg + i), reg, kWord);
       }
     } else {
       // If arriving in frame & promoted
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 2e385a3..a663519 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -23,9 +23,10 @@
 
 namespace art {
 
-void MipsMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
+bool MipsMir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
                                  const InlineMethod& special) {
-    // TODO
+  // TODO
+  return false;
 }
 
 /*
@@ -345,4 +346,8 @@
   OpReg(kOpBx, r_RA);
 }
 
+void MipsMir2Lir::GenSpecialExitSequence() {
+  OpReg(kOpBx, r_RA);
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 11b8f83..dad8a3b 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -52,6 +52,7 @@
     int AllocTypedTempPair(bool fp_hint, int reg_class);
     int S2d(int low_reg, int high_reg);
     int TargetReg(SpecialTargetRegister reg);
+    int GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
     RegLocation GetReturnWideAlt();
     RegLocation LocCReturn();
@@ -121,6 +122,7 @@
     void GenDivZeroCheck(int reg_lo, int reg_hi);
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
+    void GenSpecialExitSequence();
     void GenFillArrayData(uint32_t table_offset, RegLocation rl_src);
     void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
     void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
@@ -133,7 +135,7 @@
     void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
     void GenPackedSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
     void GenSparseSwitch(MIR* mir, uint32_t table_offset, RegLocation rl_src);
-    void GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
+    bool GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
 
     // Required for target - single operation generators.
     LIR* OpUnconditionalBranch(LIR* target);
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index b744adc..224e8f2 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -86,6 +86,20 @@
   return res;
 }
 
+int MipsMir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
+  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
+  switch (arg_num) {
+    case 0:
+      return rMIPS_ARG1;
+    case 1:
+      return rMIPS_ARG2;
+    case 2:
+      return rMIPS_ARG3;
+    default:
+      return INVALID_REG;
+  }
+}
+
 // Create a double from a pair of singles.
 int MipsMir2Lir::S2d(int low_reg, int high_reg) {
   return MIPS_S2D(low_reg, high_reg);
diff --git a/compiler/dex/quick/mir_to_lir.cc b/compiler/dex/quick/mir_to_lir.cc
index ae54fb8..8c2ed36 100644
--- a/compiler/dex/quick/mir_to_lir.cc
+++ b/compiler/dex/quick/mir_to_lir.cc
@@ -16,12 +16,244 @@
 
 #include "dex/compiler_internals.h"
 #include "dex/dataflow_iterator-inl.h"
+#include "dex/quick/dex_file_method_inliner.h"
 #include "mir_to_lir-inl.h"
 #include "object_utils.h"
 #include "thread-inl.h"
 
 namespace art {
 
+void Mir2Lir::LockArg(int in_position, bool wide) {
+  int reg_arg_low = GetArgMappingToPhysicalReg(in_position);
+  int reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) : INVALID_REG;
+
+  if (reg_arg_low != INVALID_REG) {
+    LockTemp(reg_arg_low);
+  }
+  if (reg_arg_high != INVALID_REG && reg_arg_low != reg_arg_high) {
+    LockTemp(reg_arg_high);
+  }
+}
+
+int Mir2Lir::LoadArg(int in_position, bool wide) {
+  int reg_arg_low = GetArgMappingToPhysicalReg(in_position);
+  int reg_arg_high = wide ? GetArgMappingToPhysicalReg(in_position + 1) : INVALID_REG;
+
+  int offset = StackVisitor::GetOutVROffset(in_position);
+  if (cu_->instruction_set == kX86) {
+    /*
+     * When doing a call for x86, it moves the stack pointer in order to push return.
+     * Thus, we add another 4 bytes to figure out the out of caller (in of callee).
+     * TODO: This needs revisited for 64-bit.
+     */
+    offset += sizeof(uint32_t);
+  }
+
+  // If the VR is wide and there is no register for high part, we need to load it.
+  if (wide && reg_arg_high == INVALID_REG) {
+    // If the low part is not in a reg, we allocate a pair. Otherwise, we just load to high reg.
+    if (reg_arg_low == INVALID_REG) {
+      int new_regs = AllocTypedTempPair(false, kAnyReg);
+      DECODE_REG_PAIR(new_regs, reg_arg_low, reg_arg_high);
+      LoadBaseDispWide(TargetReg(kSp), offset, reg_arg_low, reg_arg_high, INVALID_SREG);
+    } else {
+      reg_arg_high = AllocTemp();
+      int offset_high = offset + sizeof(uint32_t);
+      LoadWordDisp(TargetReg(kSp), offset_high, reg_arg_high);
+    }
+  }
+
+  // If the low part is not in a register yet, we need to load it.
+  if (reg_arg_low == INVALID_REG) {
+    reg_arg_low = AllocTemp();
+    LoadWordDisp(TargetReg(kSp), offset, reg_arg_low);
+  }
+
+  if (wide) {
+    return ENCODE_REG_PAIR(reg_arg_low, reg_arg_high);
+  } else {
+    return reg_arg_low;
+  }
+}
+
+void Mir2Lir::LoadArgDirect(int in_position, RegLocation rl_dest) {
+  int offset = StackVisitor::GetOutVROffset(in_position);
+  if (cu_->instruction_set == kX86) {
+    /*
+     * When doing a call for x86, it moves the stack pointer in order to push return.
+     * Thus, we add another 4 bytes to figure out the out of caller (in of callee).
+     * TODO: This needs revisited for 64-bit.
+     */
+    offset += sizeof(uint32_t);
+  }
+
+  if (!rl_dest.wide) {
+    int reg = GetArgMappingToPhysicalReg(in_position);
+    if (reg != INVALID_REG) {
+      OpRegCopy(rl_dest.low_reg, reg);
+    } else {
+      LoadWordDisp(TargetReg(kSp), offset, rl_dest.low_reg);
+    }
+  } else {
+    int reg_arg_low = GetArgMappingToPhysicalReg(in_position);
+    int reg_arg_high = GetArgMappingToPhysicalReg(in_position + 1);
+
+    if (reg_arg_low != INVALID_REG && reg_arg_high != INVALID_REG) {
+      OpRegCopyWide(rl_dest.low_reg, rl_dest.high_reg, reg_arg_low, reg_arg_high);
+    } else if (reg_arg_low != INVALID_REG && reg_arg_high == INVALID_REG) {
+      OpRegCopy(rl_dest.low_reg, reg_arg_low);
+      int offset_high = offset + sizeof(uint32_t);
+      LoadWordDisp(TargetReg(kSp), offset_high, rl_dest.high_reg);
+    } else if (reg_arg_low == INVALID_REG && reg_arg_high != INVALID_REG) {
+      OpRegCopy(rl_dest.high_reg, reg_arg_high);
+      LoadWordDisp(TargetReg(kSp), offset, rl_dest.low_reg);
+    } else {
+      LoadBaseDispWide(TargetReg(kSp), offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
+    }
+  }
+}
+
+bool Mir2Lir::GenSpecialIGet(MIR* mir, const InlineMethod& special) {
+  // FastInstance() already checked by DexFileMethodInliner.
+  const InlineIGetIPutData& data = special.d.ifield_data;
+  if (data.method_is_static || data.object_arg != 0) {
+    // The object is not "this" and has to be null-checked.
+    return false;
+  }
+
+  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
+  bool wide = (data.op_size == kLong);
+  bool double_or_float = cu_->shorty[0] == 'F' || cu_->shorty[0] == 'D';
+
+  // Point of no return - no aborts after this
+  GenPrintLabel(mir);
+  LockArg(data.object_arg);
+  RegLocation rl_dest = wide ? GetReturnWide(double_or_float) : GetReturn(double_or_float);
+  int reg_obj = LoadArg(data.object_arg);
+  if (wide) {
+    LoadBaseDispWide(reg_obj, data.field_offset, rl_dest.low_reg, rl_dest.high_reg, INVALID_SREG);
+  } else {
+    LoadBaseDisp(reg_obj, data.field_offset, rl_dest.low_reg, kWord, INVALID_SREG);
+  }
+  if (data.is_volatile) {
+    GenMemBarrier(kLoadLoad);
+  }
+  return true;
+}
+
+bool Mir2Lir::GenSpecialIPut(MIR* mir, const InlineMethod& special) {
+  // FastInstance() already checked by DexFileMethodInliner.
+  const InlineIGetIPutData& data = special.d.ifield_data;
+  if (data.method_is_static || data.object_arg != 0) {
+    // The object is not "this" and has to be null-checked.
+    return false;
+  }
+
+  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
+  bool wide = (data.op_size == kLong);
+
+  // Point of no return - no aborts after this
+  GenPrintLabel(mir);
+  LockArg(data.object_arg);
+  LockArg(data.src_arg, wide);
+  int reg_obj = LoadArg(data.object_arg);
+  int reg_src = LoadArg(data.src_arg, wide);
+  if (data.is_volatile) {
+    GenMemBarrier(kStoreStore);
+  }
+  if (wide) {
+    int low_reg, high_reg;
+    DECODE_REG_PAIR(reg_src, low_reg, high_reg);
+    StoreBaseDispWide(reg_obj, data.field_offset, low_reg, high_reg);
+  } else {
+    StoreBaseDisp(reg_obj, data.field_offset, reg_src, kWord);
+  }
+  if (data.is_volatile) {
+    GenMemBarrier(kLoadLoad);
+  }
+  if (data.is_object) {
+    MarkGCCard(reg_src, reg_obj);
+  }
+  return true;
+}
+
+bool Mir2Lir::GenSpecialIdentity(MIR* mir, const InlineMethod& special) {
+  const InlineReturnArgData& data = special.d.return_data;
+  DCHECK_NE(data.op_size, kDouble);  // The inliner doesn't distinguish kDouble, uses kLong.
+  bool wide = (data.op_size == kLong);
+  bool double_or_float = cu_->shorty[0] == 'F' || cu_->shorty[0] == 'D';
+
+  // Point of no return - no aborts after this
+  GenPrintLabel(mir);
+  LockArg(data.arg, wide);
+  RegLocation rl_dest = wide ? GetReturnWide(double_or_float) : GetReturn(double_or_float);
+  LoadArgDirect(data.arg, rl_dest);
+  return true;
+}
+
+/*
+ * Special-case code generation for simple non-throwing leaf methods.
+ */
+bool Mir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special) {
+  DCHECK(special.flags & kInlineSpecial);
+  current_dalvik_offset_ = mir->offset;
+  MIR* return_mir = nullptr;
+  bool successful = false;
+
+  switch (special.opcode) {
+    case kInlineOpNop:
+      successful = true;
+      DCHECK_EQ(mir->dalvikInsn.opcode, Instruction::RETURN_VOID);
+      return_mir = mir;
+      break;
+    case kInlineOpNonWideConst: {
+      successful = true;
+      RegLocation rl_dest = GetReturn(cu_->shorty[0] == 'F');
+      GenPrintLabel(mir);
+      LoadConstant(rl_dest.low_reg, static_cast<int>(special.d.data));
+      return_mir = mir_graph_->GetNextUnconditionalMir(bb, mir);
+      break;
+    }
+    case kInlineOpReturnArg:
+      successful = GenSpecialIdentity(mir, special);
+      return_mir = mir;
+      break;
+    case kInlineOpIGet:
+      successful = GenSpecialIGet(mir, special);
+      return_mir = mir_graph_->GetNextUnconditionalMir(bb, mir);
+      break;
+    case kInlineOpIPut:
+      successful = GenSpecialIPut(mir, special);
+      return_mir = mir_graph_->GetNextUnconditionalMir(bb, mir);
+      break;
+    default:
+      break;
+  }
+
+  if (successful) {
+    // Handle verbosity for return MIR.
+    if (return_mir != nullptr) {
+      current_dalvik_offset_ = return_mir->offset;
+      // Not handling special identity case because it already generated code as part
+      // of the return. The label should have been added before any code was generated.
+      if (special.opcode != kInlineOpReturnArg) {
+        GenPrintLabel(return_mir);
+      }
+    }
+    GenSpecialExitSequence();
+
+    core_spill_mask_ = 0;
+    num_core_spills_ = 0;
+    fp_spill_mask_ = 0;
+    num_fp_spills_ = 0;
+    frame_size_ = 0;
+    core_vmap_table_.clear();
+    fp_vmap_table_.clear();
+  }
+
+  return successful;
+}
+
 /*
  * Target-independent code generation.  Use only high-level
  * load/store utilities here, or target-dependent genXX() handlers
@@ -693,6 +925,14 @@
   }
 }
 
+void Mir2Lir::GenPrintLabel(MIR* mir) {
+  // Mark the beginning of a Dalvik instruction for line tracking.
+  if (cu_->verbose) {
+     char* inst_str = mir_graph_->GetDalvikDisassembly(mir);
+     MarkBoundary(mir->offset, inst_str);
+  }
+}
+
 // Handle the content in each basic block.
 bool Mir2Lir::MethodBlockCodeGen(BasicBlock* bb) {
   if (bb->block_type == kDead) return false;
@@ -745,11 +985,8 @@
     current_dalvik_offset_ = mir->offset;
     int opcode = mir->dalvikInsn.opcode;
 
-    // Mark the beginning of a Dalvik instruction for line tracking.
-    if (cu_->verbose) {
-       char* inst_str = mir_graph_->GetDalvikDisassembly(mir);
-       MarkBoundary(mir->offset, inst_str);
-    }
+    GenPrintLabel(mir);
+
     // Remember the first LIR for this block.
     if (head_lir == NULL) {
       head_lir = &block_label_list_[bb->id];
@@ -786,7 +1023,7 @@
   return false;
 }
 
-void Mir2Lir::SpecialMIR2LIR(const InlineMethod& special) {
+bool Mir2Lir::SpecialMIR2LIR(const InlineMethod& special) {
   cu_->NewTimingSplit("SpecialMIR2LIR");
   // Find the first DalvikByteCode block.
   int num_reachable_blocks = mir_graph_->GetNumReachableBlocks();
@@ -800,7 +1037,7 @@
     }
   }
   if (bb == NULL) {
-    return;
+    return false;
   }
   DCHECK_EQ(bb->start_offset, 0);
   DCHECK(bb->first_mir_insn != NULL);
@@ -813,7 +1050,7 @@
   ResetDefTracking();
   ClobberAllRegs();
 
-  GenSpecialCase(bb, mir, special);
+  return GenSpecialCase(bb, mir, special);
 }
 
 void Mir2Lir::MethodMIR2LIR() {
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 5d4439f..c60c394 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -22,11 +22,11 @@
 #include "dex/compiler_enums.h"
 #include "dex/compiler_ir.h"
 #include "dex/backend.h"
-#include "dex/growable_array.h"
-#include "dex/arena_allocator.h"
 #include "driver/compiler_driver.h"
 #include "leb128_encoder.h"
 #include "safe_map.h"
+#include "utils/arena_allocator.h"
+#include "utils/growable_array.h"
 
 namespace art {
 
@@ -185,6 +185,13 @@
 #define ENCODE_MEM              (ENCODE_DALVIK_REG | ENCODE_LITERAL | \
                                  ENCODE_HEAP_REF | ENCODE_MUST_NOT_ALIAS)
 
+#define ENCODE_REG_PAIR(low_reg, high_reg) ((low_reg & 0xff) | ((high_reg & 0xff) << 8))
+#define DECODE_REG_PAIR(both_regs, low_reg, high_reg) \
+  do { \
+    low_reg = both_regs & 0xff; \
+    high_reg = (both_regs >> 8) & 0xff; \
+  } while (false)
+
 // Mask to denote sreg as the start of a double.  Must not interfere with low 16 bits.
 #define STARTING_DOUBLE_SREG 0x10000
 
@@ -738,7 +745,7 @@
     void CompileDalvikInstruction(MIR* mir, BasicBlock* bb, LIR* label_list);
     void HandleExtendedMethodMIR(BasicBlock* bb, MIR* mir);
     bool MethodBlockCodeGen(BasicBlock* bb);
-    void SpecialMIR2LIR(const InlineMethod& special);
+    bool SpecialMIR2LIR(const InlineMethod& special);
     void MethodMIR2LIR();
 
     /*
@@ -809,6 +816,7 @@
     virtual int AllocTypedTempPair(bool fp_hint, int reg_class) = 0;
     virtual int S2d(int low_reg, int high_reg) = 0;
     virtual int TargetReg(SpecialTargetRegister reg) = 0;
+    virtual int GetArgMappingToPhysicalReg(int arg_num) = 0;
     virtual RegLocation GetReturnAlt() = 0;
     virtual RegLocation GetReturnWideAlt() = 0;
     virtual RegLocation LocCReturn() = 0;
@@ -949,8 +957,6 @@
                                  RegLocation rl_src) = 0;
     virtual void GenSparseSwitch(MIR* mir, DexOffset table_offset,
                                  RegLocation rl_src) = 0;
-    virtual void GenSpecialCase(BasicBlock* bb, MIR* mir,
-                                const InlineMethod& special) = 0;
     virtual void GenArrayGet(int opt_flags, OpSize size, RegLocation rl_array,
                              RegLocation rl_index, RegLocation rl_dest, int scale) = 0;
     virtual void GenArrayPut(int opt_flags, OpSize size, RegLocation rl_array,
@@ -1084,6 +1090,30 @@
                                             uint32_t type_idx, RegLocation rl_dest,
                                             RegLocation rl_src);
 
+    /**
+     * @brief Used to insert marker that can be used to associate MIR with LIR.
+     * @details Only inserts marker if verbosity is enabled.
+     * @param mir The mir that is currently being generated.
+     */
+    void GenPrintLabel(MIR* mir);
+
+    /**
+     * @brief Used to generate return sequence when there is no frame.
+     * @details Assumes that the return registers have already been populated.
+     */
+    virtual void GenSpecialExitSequence() = 0;
+
+    /**
+     * @brief Used to generate code for special methods that are known to be
+     * small enough to work in frameless mode.
+     * @param bb The basic block of the first MIR.
+     * @param mir The first MIR of the special method.
+     * @param special Information about the special method.
+     * @return Returns whether or not this was handled successfully. Returns false
+     * if caller should punt to normal MIR2LIR conversion.
+     */
+    virtual bool GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
+
   private:
     void ClobberBody(RegisterInfo* p);
     void ResetDefBody(RegisterInfo* p) {
@@ -1095,6 +1125,55 @@
       current_dalvik_offset_ = dexpc;
     }
 
+    /**
+     * @brief Used to lock register if argument at in_position was passed that way.
+     * @details Does nothing if the argument is passed via stack.
+     * @param in_position The argument number whose register to lock.
+     * @param wide Whether the argument is wide.
+     */
+    void LockArg(int in_position, bool wide = false);
+
+    /**
+     * @brief Used to load VR argument to a physical register.
+     * @details The load is only done if the argument is not already in physical register.
+     * LockArg must have been previously called.
+     * @param in_position The argument number to load.
+     * @param wide Whether the argument is 64-bit or not.
+     * @return Returns the register (or register pair) for the loaded argument.
+     */
+    int LoadArg(int in_position, bool wide = false);
+
+    /**
+     * @brief Used to load a VR argument directly to a specified register location.
+     * @param in_position The argument number to place in register.
+     * @param rl_dest The register location where to place argument.
+     */
+    void LoadArgDirect(int in_position, RegLocation rl_dest);
+
+    /**
+     * @brief Used to generate LIR for special getter method.
+     * @param mir The mir that represents the iget.
+     * @param special Information about the special getter method.
+     * @return Returns whether LIR was successfully generated.
+     */
+    bool GenSpecialIGet(MIR* mir, const InlineMethod& special);
+
+    /**
+     * @brief Used to generate LIR for special setter method.
+     * @param mir The mir that represents the iput.
+     * @param special Information about the special setter method.
+     * @return Returns whether LIR was successfully generated.
+     */
+    bool GenSpecialIPut(MIR* mir, const InlineMethod& special);
+
+    /**
+     * @brief Used to generate LIR for special return-args method.
+     * @param mir The mir that represents the return of argument.
+     * @param special Information about the special return-args method.
+     * @return Returns whether LIR was successfully generated.
+     */
+    bool GenSpecialIdentity(MIR* mir, const InlineMethod& special);
+
 
   public:
     // TODO: add accessors for these.
diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc
index 7f646e0..0613cdf 100644
--- a/compiler/dex/quick/x86/call_x86.cc
+++ b/compiler/dex/quick/x86/call_x86.cc
@@ -22,11 +22,6 @@
 
 namespace art {
 
-void X86Mir2Lir::GenSpecialCase(BasicBlock* bb, MIR* mir,
-                                const InlineMethod& special) {
-  // TODO
-}
-
 /*
  * The sparse table in the literal pool is an array of <key,displacement>
  * pairs.
@@ -255,4 +250,8 @@
   NewLIR0(kX86Ret);
 }
 
+void X86Mir2Lir::GenSpecialExitSequence() {
+  NewLIR0(kX86Ret);
+}
+
 }  // namespace art
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index 70263d8..6100a1d 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -52,6 +52,7 @@
     int AllocTypedTempPair(bool fp_hint, int reg_class);
     int S2d(int low_reg, int high_reg);
     int TargetReg(SpecialTargetRegister reg);
+    int GetArgMappingToPhysicalReg(int arg_num);
     RegLocation GetReturnAlt();
     RegLocation GetReturnWideAlt();
     RegLocation LocCReturn();
@@ -123,6 +124,7 @@
     void GenDivZeroCheck(int reg_lo, int reg_hi);
     void GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method);
     void GenExitSequence();
+    void GenSpecialExitSequence();
     void GenFillArrayData(DexOffset table_offset, RegLocation rl_src);
     void GenFusedFPCmpBranch(BasicBlock* bb, MIR* mir, bool gt_bias, bool is_double);
     void GenFusedLongCmpBranch(BasicBlock* bb, MIR* mir);
@@ -135,7 +137,7 @@
     void GenNegFloat(RegLocation rl_dest, RegLocation rl_src);
     void GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
     void GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src);
-    void GenSpecialCase(BasicBlock* bb, MIR* mir, const InlineMethod& special);
+
     /*
      * @brief Generate a two address long operation with a constant value
      * @param rl_dest location of result
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index f4ae18f..5f04b7d 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -167,7 +167,14 @@
       NewLIR2(kX86MovdrxRR, dest_hi, src_lo);
     } else {
       // Handle overlap
-      if (src_hi == dest_lo) {
+      if (src_hi == dest_lo && src_lo == dest_hi) {
+        // Deal with cycles.
+        int temp_reg = AllocTemp();
+        OpRegCopy(temp_reg, dest_hi);
+        OpRegCopy(dest_hi, dest_lo);
+        OpRegCopy(dest_lo, temp_reg);
+        FreeTemp(temp_reg);
+      } else if (src_hi == dest_lo) {
         OpRegCopy(dest_hi, src_hi);
         OpRegCopy(dest_lo, src_lo);
       } else {
@@ -978,6 +985,10 @@
   }
 
   // Nope.  Do it the hard way
+  // Check for V*V.  We can eliminate a multiply in that case, as 2L*1H == 2H*1L.
+  bool is_square = mir_graph_->SRegToVReg(rl_src1.s_reg_low) ==
+                   mir_graph_->SRegToVReg(rl_src2.s_reg_low);
+
   FlushAllRegs();
   LockCallTemps();  // Prepare for explicit register usage.
   rl_src1 = UpdateLocWide(rl_src1);
@@ -995,36 +1006,52 @@
                  kWord, GetSRegHi(rl_src1.s_reg_low));
   }
 
-  // EAX <- 2H
-  if (src2_in_reg) {
-    NewLIR2(kX86Mov32RR, r0, rl_src2.high_reg);
-  } else {
-    LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, r0,
-                 kWord, GetSRegHi(rl_src2.s_reg_low));
-  }
+  if (is_square) {
+    // Take advantage of the fact that the values are the same.
+    // ECX <- ECX * 2L  (1H * 2L)
+    if (src2_in_reg) {
+      NewLIR2(kX86Imul32RR, r1, rl_src2.low_reg);
+    } else {
+      int displacement = SRegOffset(rl_src2.s_reg_low);
+      LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+      AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+                              true /* is_load */, true /* is_64bit */);
+    }
 
-  // EAX <- EAX * 1L  (2H * 1L)
-  if (src1_in_reg) {
-    NewLIR2(kX86Imul32RR, r0, rl_src1.low_reg);
+    // ECX <- 2*ECX (2H * 1L) + (1H * 2L)
+    NewLIR2(kX86Add32RR, r1, r1);
   } else {
-    int displacement = SRegOffset(rl_src1.s_reg_low);
-    LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
-    AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
-                            true /* is_load */, true /* is_64bit */);
-  }
+    // EAX <- 2H
+    if (src2_in_reg) {
+      NewLIR2(kX86Mov32RR, r0, rl_src2.high_reg);
+    } else {
+      LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, r0,
+                   kWord, GetSRegHi(rl_src2.s_reg_low));
+    }
 
-  // ECX <- ECX * 2L  (1H * 2L)
-  if (src2_in_reg) {
-    NewLIR2(kX86Imul32RR, r1, rl_src2.low_reg);
-  } else {
-    int displacement = SRegOffset(rl_src2.s_reg_low);
-    LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
-    AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
-                            true /* is_load */, true /* is_64bit */);
-  }
+    // EAX <- EAX * 1L  (2H * 1L)
+    if (src1_in_reg) {
+      NewLIR2(kX86Imul32RR, r0, rl_src1.low_reg);
+    } else {
+      int displacement = SRegOffset(rl_src1.s_reg_low);
+      LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
+      AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+                              true /* is_load */, true /* is_64bit */);
+    }
 
-  // ECX <- ECX + EAX  (2H * 1L) + (1H * 2L)
-  NewLIR2(kX86Add32RR, r1, r0);
+    // ECX <- ECX * 2L  (1H * 2L)
+    if (src2_in_reg) {
+      NewLIR2(kX86Imul32RR, r1, rl_src2.low_reg);
+    } else {
+      int displacement = SRegOffset(rl_src2.s_reg_low);
+      LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+      AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+                              true /* is_load */, true /* is_64bit */);
+    }
+
+    // ECX <- ECX + EAX  (2H * 1L) + (1H * 2L)
+    NewLIR2(kX86Add32RR, r1, r0);
+  }
 
   // EAX <- 2L
   if (src2_in_reg) {
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 1893ffc..8e04e64 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -92,6 +92,21 @@
   return res;
 }
 
+int X86Mir2Lir::GetArgMappingToPhysicalReg(int arg_num) {
+  // For the 32-bit internal ABI, the first 3 arguments are passed in registers.
+  // TODO: This is not 64-bit compliant and depends on new internal ABI.
+  switch (arg_num) {
+    case 0:
+      return rX86_ARG1;
+    case 1:
+      return rX86_ARG2;
+    case 2:
+      return rX86_ARG3;
+    default:
+      return INVALID_REG;
+  }
+}
+
 // Create a double from a pair of singles.
 int X86Mir2Lir::S2d(int low_reg, int high_reg) {
   return X86_S2D(low_reg, high_reg);
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5b22817..b46ae2b 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -25,6 +25,7 @@
 #include "base/stl_util.h"
 #include "base/timing_logger.h"
 #include "class_linker.h"
+#include "compiler_backend.h"
 #include "dex_compilation_unit.h"
 #include "dex_file-inl.h"
 #include "dex/verification_results.h"
@@ -49,15 +50,10 @@
 #include "thread.h"
 #include "thread_pool.h"
 #include "trampolines/trampoline_compiler.h"
+#include "transaction.h"
 #include "verifier/method_verifier.h"
 #include "verifier/method_verifier-inl.h"
 
-#if defined(ART_USE_PORTABLE_COMPILER)
-#include "elf_writer_mclinker.h"
-#else
-#include "elf_writer_quick.h"
-#endif
-
 namespace art {
 
 static double Percentage(size_t x, size_t y) {
@@ -287,28 +283,6 @@
   DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
 };
 
-extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver);
-extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver);
-
-extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver);
-extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver);
-
-extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
-                                                 const art::DexFile::CodeItem* code_item,
-                                                 uint32_t access_flags,
-                                                 art::InvokeType invoke_type,
-                                                 uint16_t class_def_idx,
-                                                 uint32_t method_idx,
-                                                 jobject class_loader,
-                                                 const art::DexFile& dex_file);
-extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler,
-                                                      const art::DexFile::CodeItem* code_item,
-                                                      uint32_t access_flags,
-                                                      art::InvokeType invoke_type,
-                                                      uint16_t class_def_idx,
-                                                      uint32_t method_idx,
-                                                      jobject class_loader,
-                                                      const art::DexFile& dex_file);
 
 extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler,
                                               const art::DexFile::CodeItem* code_item,
@@ -318,36 +292,20 @@
                                               uint32_t method_idx,
                                               jobject class_loader,
                                               const art::DexFile& dex_file);
-#ifdef ART_SEA_IR_MODE
-extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler,
-                                                   const art::DexFile::CodeItem* code_item,
-                                                   uint32_t access_flags,
-                                                   art::InvokeType invoke_type,
-                                                   uint16_t class_def_idx,
-                                                   uint32_t method_idx,
-                                                   jobject class_loader,
-                                                   const art::DexFile& dex_file);
-#endif
-extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver,
-                                                        uint32_t access_flags, uint32_t method_idx,
-                                                        const art::DexFile& dex_file);
-
-extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& compiler,
-                                                         uint32_t access_flags, uint32_t method_idx,
-                                                         const art::DexFile& dex_file);
 
 extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
                                                std::string const& filename);
 
 CompilerDriver::CompilerDriver(VerificationResults* verification_results,
                                DexFileToMethodInlinerMap* method_inliner_map,
-                               CompilerBackend compiler_backend, InstructionSet instruction_set,
+                               CompilerBackend::Kind compiler_backend_kind,
+                               InstructionSet instruction_set,
                                InstructionSetFeatures instruction_set_features,
                                bool image, DescriptorSet* image_classes, size_t thread_count,
                                bool dump_stats, bool dump_passes, CumulativeLogger* timer)
     : verification_results_(verification_results),
       method_inliner_map_(method_inliner_map),
-      compiler_backend_(compiler_backend),
+      compiler_backend_(CompilerBackend::Create(compiler_backend_kind)),
       instruction_set_(instruction_set),
       instruction_set_features_(instruction_set_features),
       freezing_constructor_lock_("freezing constructor lock"),
@@ -362,9 +320,7 @@
       dump_passes_(dump_passes),
       timings_logger_(timer),
       compiler_library_(NULL),
-      compiler_(NULL),
       compiler_context_(NULL),
-      jni_compiler_(NULL),
       compiler_enable_auto_elf_loading_(NULL),
       compiler_get_method_code_addr_(NULL),
       support_boot_image_fixup_(instruction_set != kMips),
@@ -375,34 +331,9 @@
 
   CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
 
-  // TODO: more work needed to combine initializations and allow per-method backend selection
-  typedef void (*InitCompilerContextFn)(CompilerDriver&);
-  InitCompilerContextFn init_compiler_context;
-  if (compiler_backend_ == kPortable) {
-    // Initialize compiler_context_
-    init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitCompilerContext);
-    compiler_ = reinterpret_cast<CompilerFn>(ArtCompileMethod);
-  } else {
-    init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitQuickCompilerContext);
-    compiler_ = reinterpret_cast<CompilerFn>(ArtQuickCompileMethod);
-  }
-
   dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
 
-#ifdef ART_SEA_IR_MODE
-  sea_ir_compiler_ = NULL;
-  if (Runtime::Current()->IsSeaIRMode()) {
-    sea_ir_compiler_ = reinterpret_cast<CompilerFn>(SeaIrCompileMethod);
-  }
-#endif
-
-  init_compiler_context(*this);
-
-  if (compiler_backend_ == kPortable) {
-    jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtLLVMJniCompileMethod);
-  } else {
-    jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtQuickJniCompileMethod);
-  }
+  compiler_backend_->Init(*this);
 
   CHECK(!Runtime::Current()->IsStarted());
   if (!image_) {
@@ -449,16 +380,7 @@
     STLDeleteElements(&classes_to_patch_);
   }
   CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key");
-  typedef void (*UninitCompilerContextFn)(CompilerDriver&);
-  UninitCompilerContextFn uninit_compiler_context;
-  // Uninitialize compiler_context_
-  // TODO: rework to combine initialization/uninitialization
-  if (compiler_backend_ == kPortable) {
-    uninit_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtUnInitCompilerContext);
-  } else {
-    uninit_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtUnInitQuickCompilerContext);
-  }
-  uninit_compiler_context(*this);
+  compiler_backend_->UnInit(*this);
 }
 
 CompilerTls* CompilerDriver::GetTls() {
@@ -1016,7 +938,6 @@
     return false;
   }
   DCHECK_GE(field->GetOffset().Int32Value(), 0);
-  result->method_is_static = method->IsStatic();
   result->field_idx = field_idx;
   result->field_offset = field->GetOffset().Int32Value();
   result->is_volatile = field->IsVolatile();
@@ -1153,7 +1074,7 @@
   *direct_method = 0;
   bool use_dex_cache = false;
   const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
-  if (compiler_backend_ == kPortable) {
+  if (compiler_backend_->IsPortable()) {
     if (sharp_type != kStatic && sharp_type != kDirect) {
       return;
     }
@@ -1230,23 +1151,13 @@
         CHECK(!method->IsAbstract());
         *type = sharp_type;
         *direct_method = reinterpret_cast<uintptr_t>(method);
-        if (compiler_backend_ == kQuick) {
-          *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
-        } else {
-          CHECK_EQ(compiler_backend_, kPortable);
-          *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
-        }
+        *direct_code = compiler_backend_->GetEntryPointOf(method);
         target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
         target_method->dex_method_index = method->GetDexMethodIndex();
       } else if (!must_use_direct_pointers) {
         // Set the code and rely on the dex cache for the method.
         *type = sharp_type;
-        if (compiler_backend_ == kQuick) {
-          *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
-        } else {
-          CHECK_EQ(compiler_backend_, kPortable);
-          *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
-        }
+        *direct_code = compiler_backend_->GetEntryPointOf(method);
       } else {
         // Direct pointers were required but none were available.
         VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
@@ -1795,425 +1706,6 @@
   context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
 }
 
-static const char* class_initializer_black_list[] = {
-  "Landroid/app/ActivityThread;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/bluetooth/BluetoothAudioGateway;",  // Calls android.bluetooth.BluetoothAudioGateway.classInitNative().
-  "Landroid/bluetooth/HeadsetBase;",  // Calls android.bluetooth.HeadsetBase.classInitNative().
-  "Landroid/content/res/CompatibilityInfo;",  // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
-  "Landroid/content/res/CompatibilityInfo$1;",  // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
-  "Landroid/content/UriMatcher;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/database/CursorWindow;",  // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
-  "Landroid/database/sqlite/SQLiteConnection;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/database/sqlite/SQLiteConnection$Operation;",  // Requires SimpleDateFormat -> java.util.Locale.
-  "Landroid/database/sqlite/SQLiteDatabaseConfiguration;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/database/sqlite/SQLiteDebug;",  // Calls android.util.Log.isLoggable.
-  "Landroid/database/sqlite/SQLiteOpenHelper;",  // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
-  "Landroid/database/sqlite/SQLiteQueryBuilder;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/drm/DrmManagerClient;",  // Calls System.loadLibrary.
-  "Landroid/graphics/drawable/AnimatedRotateDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/AnimationDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/BitmapDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/ClipDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/ColorDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/Drawable;",  // Requires android.graphics.Rect.
-  "Landroid/graphics/drawable/DrawableContainer;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/GradientDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/LayerDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/NinePatchDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/RotateDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/ScaleDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/ShapeDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/StateListDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/drawable/TransitionDrawable;",  // Sub-class of Drawable.
-  "Landroid/graphics/Matrix;",  // Calls android.graphics.Matrix.native_create.
-  "Landroid/graphics/Matrix$1;",  // Requires Matrix.
-  "Landroid/graphics/PixelFormat;",  // Calls android.graphics.PixelFormat.nativeClassInit().
-  "Landroid/graphics/Rect;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/graphics/SurfaceTexture;",  // Calls android.graphics.SurfaceTexture.nativeClassInit().
-  "Landroid/graphics/Typeface;",  // Calls android.graphics.Typeface.nativeCreate.
-  "Landroid/inputmethodservice/ExtractEditText;",  // Requires android.widget.TextView.
-  "Landroid/media/AmrInputStream;",  // Calls OsConstants.initConstants.
-  "Landroid/media/CamcorderProfile;",  // Calls OsConstants.initConstants.
-  "Landroid/media/CameraProfile;",  // Calls System.loadLibrary.
-  "Landroid/media/DecoderCapabilities;",  // Calls System.loadLibrary.
-  "Landroid/media/EncoderCapabilities;",  // Calls OsConstants.initConstants.
-  "Landroid/media/ExifInterface;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaCodec;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaCodecList;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaCrypto;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaDrm;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaExtractor;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaFile;",  // Requires DecoderCapabilities.
-  "Landroid/media/MediaMetadataRetriever;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaMuxer;",  // Calls OsConstants.initConstants.
-  "Landroid/media/MediaPlayer;",  // Calls System.loadLibrary.
-  "Landroid/media/MediaRecorder;",  // Calls System.loadLibrary.
-  "Landroid/media/MediaScanner;",  // Calls System.loadLibrary.
-  "Landroid/media/ResampleInputStream;",  // Calls OsConstants.initConstants.
-  "Landroid/media/SoundPool;",  // Calls OsConstants.initConstants.
-  "Landroid/media/videoeditor/MediaArtistNativeHelper;",  // Calls OsConstants.initConstants.
-  "Landroid/media/videoeditor/VideoEditorProfile;",  // Calls OsConstants.initConstants.
-  "Landroid/mtp/MtpDatabase;",  // Calls OsConstants.initConstants.
-  "Landroid/mtp/MtpDevice;",  // Calls OsConstants.initConstants.
-  "Landroid/mtp/MtpServer;",  // Calls OsConstants.initConstants.
-  "Landroid/net/NetworkInfo;",  // Calls java.util.EnumMap.<init> -> java.lang.Enum.getSharedConstants -> System.identityHashCode.
-  "Landroid/net/Proxy;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/net/SSLCertificateSocketFactory;",  // Requires javax.net.ssl.HttpsURLConnection.
-  "Landroid/net/Uri$AbstractHierarchicalUri;",  // Requires Uri.
-  "Landroid/net/Uri$HierarchicalUri;",  // Requires Uri.
-  "Landroid/net/Uri$OpaqueUri;",  // Requires Uri.
-  "Landroid/net/Uri$StringUri;",  // Requires Uri.
-  "Landroid/net/Uri;",  // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
-  "Landroid/net/WebAddress;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/net/wifi/WifiNative;",  // Calls new LocalLog -> new Time -> TimeZone -> Pattern.compile.
-  "Landroid/nfc/NdefRecord;",  // Calls String.getBytes -> java.nio.charset.Charset.
-  "Landroid/opengl/EGL14;",  // Calls android.opengl.EGL14._nativeClassInit.
-  "Landroid/opengl/GLES10;",  // Calls android.opengl.GLES10._nativeClassInit.
-  "Landroid/opengl/GLES10Ext;",  // Calls android.opengl.GLES10Ext._nativeClassInit.
-  "Landroid/opengl/GLES11;",  // Requires GLES10.
-  "Landroid/opengl/GLES11Ext;",  // Calls android.opengl.GLES11Ext._nativeClassInit.
-  "Landroid/opengl/GLES20;",  // Calls android.opengl.GLES20._nativeClassInit.
-  "Landroid/opengl/GLUtils;",  // Calls android.opengl.GLUtils.nativeClassInit.
-  "Landroid/os/Build;",  // Calls -..-> android.os.SystemProperties.native_get.
-  "Landroid/os/Build$VERSION;",  // Requires Build.
-  "Landroid/os/Bundle;",  // Calls android.os.Parcel.obtain -..> Parcel.nativeCreate.
-  "Landroid/os/Debug;",  // Requires android.os.Environment.
-  "Landroid/os/Environment;",  // Calls System.getenv.
-  "Landroid/os/FileUtils;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/os/StrictMode;",  // Calls android.util.Log.isLoggable.
-  "Landroid/os/StrictMode$VmPolicy;",  // Requires StrictMode.
-  "Landroid/os/Trace;",  // Calls android.os.Trace.nativeGetEnabledTags.
-  "Landroid/os/UEventObserver;",  // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
-  "Landroid/provider/ContactsContract;",  // Calls OsConstants.initConstants.
-  "Landroid/provider/Settings$Global;",  // Calls OsConstants.initConstants.
-  "Landroid/provider/Settings$Secure;",  // Requires android.net.Uri.
-  "Landroid/provider/Settings$System;",  // Requires android.net.Uri.
-  "Landroid/renderscript/RenderScript;",  // Calls System.loadLibrary.
-  "Landroid/server/BluetoothService;",  // Calls android.server.BluetoothService.classInitNative.
-  "Landroid/server/BluetoothEventLoop;",  // Calls android.server.BluetoothEventLoop.classInitNative.
-  "Landroid/telephony/PhoneNumberUtils;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/telephony/TelephonyManager;",  // Calls OsConstants.initConstants.
-  "Landroid/text/AutoText;",  // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
-  "Landroid/text/Layout;",  // Calls com.android.internal.util.ArrayUtils.emptyArray -> System.identityHashCode.
-  "Landroid/text/BoringLayout;",  // Requires Layout.
-  "Landroid/text/DynamicLayout;",  // Requires Layout.
-  "Landroid/text/Html$HtmlParser;",  // Calls -..-> String.toLowerCase -> java.util.Locale.
-  "Landroid/text/StaticLayout;",  // Requires Layout.
-  "Landroid/text/TextUtils;",  // Requires android.util.DisplayMetrics.
-  "Landroid/util/DisplayMetrics;",  // Calls SystemProperties.native_get_int.
-  "Landroid/util/Patterns;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/view/Choreographer;",  // Calls SystemProperties.native_get_boolean.
-  "Landroid/util/Patterns;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/view/GLES20Canvas;",  // Calls GLES20Canvas.nIsAvailable().
-  "Landroid/view/GLES20RecordingCanvas;",  // Requires android.view.GLES20Canvas.
-  "Landroid/view/GestureDetector;",  // Calls android.view.GLES20Canvas.nIsAvailable.
-  "Landroid/view/HardwareRenderer$Gl20Renderer;",  // Requires SystemProperties.native_get.
-  "Landroid/view/HardwareRenderer$GlRenderer;",  // Requires SystemProperties.native_get.
-  "Landroid/view/InputEventConsistencyVerifier;",  // Requires android.os.Build.
-  "Landroid/view/Surface;",  // Requires SystemProperties.native_get.
-  "Landroid/view/SurfaceControl;",  // Calls OsConstants.initConstants.
-  "Landroid/view/animation/AlphaAnimation;",  // Requires Animation.
-  "Landroid/view/animation/Animation;",  // Calls SystemProperties.native_get_boolean.
-  "Landroid/view/animation/AnimationSet;",  // Calls OsConstants.initConstants.
-  "Landroid/view/textservice/SpellCheckerSubtype;",  // Calls Class.getDex().
-  "Landroid/webkit/JniUtil;",  // Calls System.loadLibrary.
-  "Landroid/webkit/PluginManager;",  // // Calls OsConstants.initConstants.
-  "Landroid/webkit/WebViewCore;",  // Calls System.loadLibrary.
-  "Landroid/webkit/WebViewFactory;",  // Calls -..-> android.os.SystemProperties.native_get.
-  "Landroid/webkit/WebViewFactory$Preloader;",  // Calls to Class.forName.
-  "Landroid/webkit/WebViewInputDispatcher;",  // Calls Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/webkit/URLUtil;",  // Calls Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Landroid/widget/AutoCompleteTextView;",  // Requires TextView.
-  "Landroid/widget/Button;",  // Requires TextView.
-  "Landroid/widget/CheckBox;",  // Requires TextView.
-  "Landroid/widget/CheckedTextView;",  // Requires TextView.
-  "Landroid/widget/CompoundButton;",  // Requires TextView.
-  "Landroid/widget/EditText;",  // Requires TextView.
-  "Landroid/widget/NumberPicker;",  // Requires java.util.Locale.
-  "Landroid/widget/ScrollBarDrawable;",  // Sub-class of Drawable.
-  "Landroid/widget/SearchView$SearchAutoComplete;",  // Requires TextView.
-  "Landroid/widget/Switch;",  // Requires TextView.
-  "Landroid/widget/TextView;",  // Calls Paint.<init> -> Paint.native_init.
-  "Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Lcom/android/i18n/phonenumbers/MetadataManager;",  // Calls OsConstants.initConstants.
-  "Lcom/android/i18n/phonenumbers/PhoneNumberMatcher;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Lcom/android/i18n/phonenumbers/PhoneNumberUtil;",  // Requires java.util.logging.LogManager.
-  "Lcom/android/i18n/phonenumbers/geocoding/AreaCodeMap;",  // Calls OsConstants.initConstants.
-  "Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;",  // Calls OsConstants.initConstants.
-  "Lcom/android/internal/os/SamplingProfilerIntegration;",  // Calls SystemProperties.native_get_int.
-  "Lcom/android/internal/policy/impl/PhoneWindow;",  // Calls android.os.Binder.init.
-  "Lcom/android/internal/view/menu/ActionMenuItemView;",  // Requires TextView.
-  "Lcom/android/internal/widget/DialogTitle;",  // Requires TextView.
-  "Lcom/android/org/bouncycastle/asn1/StreamUtil;",  // Calls Runtime.getRuntime().maxMemory().
-  "Lcom/android/org/bouncycastle/asn1/pkcs/MacData;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/asn1/pkcs/RSASSAPSSparams;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/asn1/cms/SignedData;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/asn1/x509/GeneralSubtree;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/asn1/x9/X9ECParameters;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$MD5;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA1;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA256;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA384;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA512;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/bouncycastle/crypto/engines/RSABlindedEngine;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/crypto/generators/DHParametersGenerator;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/crypto/generators/DHParametersHelper;",  // Calls System.getenv -> OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/crypto/generators/DSAKeyPairGenerator;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/crypto/generators/DSAParametersGenerator;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/crypto/generators/RSAKeyPairGenerator;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$EC;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECDH;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECDHC;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECDSA;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECMQV;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi$BCPKCS12KeyStore;",  // Calls Thread.currentThread.
-  "Lcom/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi;",  // Calls Thread.currentThread.
-  "Lcom/android/org/bouncycastle/jce/PKCS10CertificationRequest;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/jce/provider/CertBlacklist;",  // Calls System.getenv -> OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/jce/provider/JCERSAPrivateKey;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi;",  // Calls System.getenv -> OsConstants.initConstants.
-  "Lcom/android/org/bouncycastle/math/ec/ECConstants;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/math/ec/Tnaf;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/util/BigIntegers;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/bouncycastle/x509/X509Util;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lcom/android/org/conscrypt/CipherSuite;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/FileClientSessionCache$CacheFile;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/HandshakeIODataStream;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/Logger;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/NativeCrypto;",  // Calls native NativeCrypto.clinit().
-  "Lcom/android/org/conscrypt/OpenSSLECKeyPairGenerator;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/OpenSSLEngine;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/conscrypt/OpenSSLMac$HmacMD5;",  // Calls native NativeCrypto.clinit().
-  "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA1;",  // Calls native NativeCrypto.clinit().
-  "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA256;",  // Calls native NativeCrypto.clinit().
-  "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA384;",  // Calls native NativeCrypto.clinit().
-  "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA512;",  // Calls native NativeCrypto.clinit().
-  "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$MD5;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA1;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA256;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA384;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA512;",  // Requires com.android.org.conscrypt.NativeCrypto.
-  "Lcom/android/org/conscrypt/OpenSSLX509CertPath;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/PRF;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/SSLSessionImpl;",  // Calls OsConstants.initConstants.
-  "Lcom/android/org/conscrypt/TrustedCertificateStore;",  // Calls System.getenv -> OsConstants.initConstants.
-  "Lcom/android/okhttp/ConnectionPool;",  // Calls OsConstants.initConstants.
-  "Lcom/android/okhttp/OkHttpClient;",  // Calls OsConstants.initConstants.
-  "Lcom/android/okhttp/internal/DiskLruCache;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Lcom/android/okhttp/internal/Util;",  // Calls OsConstants.initConstants.
-  "Lcom/android/okhttp/internal/http/HttpsURLConnectionImpl;",  // Calls VMClassLoader.getBootClassPathSize.
-  "Lcom/android/okhttp/internal/spdy/SpdyConnection;",  // Calls OsConstants.initConstants.
-  "Lcom/android/okhttp/internal/spdy/SpdyReader;",  // Calls OsConstants.initConstants.
-  "Lcom/android/okhttp/internal/tls/OkHostnameVerifier;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Lcom/google/android/gles_jni/EGLContextImpl;",  // Calls com.google.android.gles_jni.EGLImpl._nativeClassInit.
-  "Lcom/google/android/gles_jni/EGLImpl;",  // Calls com.google.android.gles_jni.EGLImpl._nativeClassInit.
-  "Lcom/google/android/gles_jni/GLImpl;",  // Calls com.google.android.gles_jni.GLImpl._nativeClassInit.
-  "Lgov/nist/core/GenericObject;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/core/Host;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/core/HostPort;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/core/NameValue;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/core/net/DefaultNetworkLayer;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/Utils;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/address/AddressImpl;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/address/Authority;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/address/GenericURI;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/address/NetObject;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/address/SipUri;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/address/TelephoneNumber;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/address/UserInfo;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Accept;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/AcceptEncoding;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/AcceptLanguage;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/AddressParametersHeader;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/AlertInfoList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/AllowEvents;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/AllowEventsList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/AuthenticationInfo;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Authorization;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/CSeq;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/CallIdentifier;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Challenge;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ContactList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ContentEncoding;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ContentEncodingList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ContentLanguageList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ContentType;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Credentials;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ErrorInfoList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Expires;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/From;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/MimeVersion;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/NameMap;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Priority;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Protocol;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ProxyAuthenticate;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ProxyAuthenticateList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ProxyAuthorizationList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ProxyRequire;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ProxyRequireList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/RSeq;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/RecordRoute;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ReferTo;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/RequestLine;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Require;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/RetryAfter;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/SIPETag;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/SIPHeader;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/SIPHeaderNamesCache;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/StatusLine;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/SubscriptionState;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/TimeStamp;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/UserAgent;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Unsupported;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/Warning;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ViaList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/extensions/Join;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/extensions/References;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/extensions/Replaces;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PAccessNetworkInfo;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PAssertedIdentity;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PAssertedIdentityList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PAssociatedURI;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PCalledPartyID;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PChargingVector;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PPreferredIdentity;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PVisitedNetworkIDList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/PathList;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/SecurityAgree;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/SecurityClient;",  // Calls OsConstants.initConstants.
-  "Lgov/nist/javax/sip/header/ims/ServiceRoute;",  // Calls OsConstants.initConstants.
-  "Ljava/io/Console;",  // Has FileDescriptor(s).
-  "Ljava/io/File;",  // Calls to Random.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
-  "Ljava/io/FileDescriptor;",  // Requires libcore.io.OsConstants.
-  "Ljava/io/ObjectInputStream;",  // Requires java.lang.ClassLoader$SystemClassLoader.
-  "Ljava/io/ObjectStreamClass;",  // Calls to Class.forName -> java.io.FileDescriptor.
-  "Ljava/io/ObjectStreamConstants;",  // Instance of non-image class SerializablePermission.
-  "Ljava/lang/ClassLoader$SystemClassLoader;",  // Calls System.getProperty -> OsConstants.initConstants.
-  "Ljava/lang/HexStringParser;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Ljava/lang/ProcessManager;",  // Calls Thread.currentThread.
-  "Ljava/lang/Runtime;",  // Calls System.getProperty -> OsConstants.initConstants.
-  "Ljava/lang/System;",  // Calls OsConstants.initConstants.
-  "Ljava/math/BigDecimal;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Ljava/math/BigInteger;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Ljava/math/Primality;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Ljava/math/Multiplication;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Ljava/net/InetAddress;",  // Requires libcore.io.OsConstants.
-  "Ljava/net/Inet4Address;",  // Sub-class of InetAddress.
-  "Ljava/net/Inet6Address;",  // Sub-class of InetAddress.
-  "Ljava/net/InetUnixAddress;",  // Sub-class of InetAddress.
-  "Ljava/net/NetworkInterface;",  // Calls to Random.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
-  "Ljava/net/StandardSocketOptions;",  // Call System.identityHashCode.
-  "Ljava/nio/charset/Charset;",  // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants.
-  "Ljava/nio/charset/CharsetICU;",  // Sub-class of Charset.
-  "Ljava/nio/charset/Charsets;",  // Calls Charset.forName.
-  "Ljava/nio/charset/StandardCharsets;",  // Calls OsConstants.initConstants.
-  "Ljava/security/AlgorithmParameterGenerator;",  // Calls OsConstants.initConstants.
-  "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;",  // Calls OsConstants.initConstants.
-  "Ljava/security/KeyPairGenerator;",  // Calls OsConstants.initConstants.
-  "Ljava/security/Security;",  // Tries to do disk IO for "security.properties".
-  "Ljava/security/spec/RSAKeyGenParameterSpec;",  // java.math.NativeBN.BN_new()
-  "Ljava/sql/Date;",  // Calls OsConstants.initConstants.
-  "Ljava/sql/DriverManager;",  // Calls OsConstants.initConstants.
-  "Ljava/sql/Time;",  // Calls OsConstants.initConstants.
-  "Ljava/sql/Timestamp;",  // Calls OsConstants.initConstants.
-  "Ljava/util/Date;",  // Calls Date.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
-  "Ljava/util/ListResourceBundle;",  // Calls OsConstants.initConstants.
-  "Ljava/util/Locale;",  // Calls System.getProperty -> OsConstants.initConstants.
-  "Ljava/util/PropertyResourceBundle;",  // Calls OsConstants.initConstants.
-  "Ljava/util/ResourceBundle;",  // Calls OsConstants.initConstants.
-  "Ljava/util/ResourceBundle$MissingBundle;",  // Calls OsConstants.initConstants.
-  "Ljava/util/Scanner;",  // regex.Pattern.compileImpl.
-  "Ljava/util/SimpleTimeZone;",  // Sub-class of TimeZone.
-  "Ljava/util/TimeZone;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-  "Ljava/util/concurrent/ConcurrentHashMap;",  // Calls Runtime.getRuntime().availableProcessors().
-  "Ljava/util/concurrent/ConcurrentHashMap$Segment;",  // Calls Runtime.getRuntime().availableProcessors().
-  "Ljava/util/concurrent/ConcurrentSkipListMap;",  // Calls Random() -> OsConstants.initConstants.
-  "Ljava/util/concurrent/Exchanger;",  // Calls Runtime.getRuntime().availableProcessors().
-  "Ljava/util/concurrent/ForkJoinPool;",  // Makes a thread pool ..-> calls OsConstants.initConstants.
-  "Ljava/util/concurrent/LinkedTransferQueue;",  // Calls Runtime.getRuntime().availableProcessors().
-  "Ljava/util/concurrent/Phaser;",  // Calls Runtime.getRuntime().availableProcessors().
-  "Ljava/util/concurrent/ScheduledThreadPoolExecutor;",  // Calls AtomicLong.VMSupportsCS8()
-  "Ljava/util/concurrent/SynchronousQueue;",  // Calls Runtime.getRuntime().availableProcessors().
-  "Ljava/util/concurrent/atomic/AtomicLong;",  // Calls AtomicLong.VMSupportsCS8()
-  "Ljava/util/logging/LogManager;",  // Calls System.getProperty -> OsConstants.initConstants.
-  "Ljava/util/prefs/AbstractPreferences;",  // Calls OsConstants.initConstants.
-  "Ljava/util/prefs/FilePreferencesImpl;",  // Calls OsConstants.initConstants.
-  "Ljava/util/prefs/FilePreferencesFactoryImpl;",  // Calls OsConstants.initConstants.
-  "Ljava/util/prefs/Preferences;",  // Calls OsConstants.initConstants.
-  "Ljavax/crypto/KeyAgreement;",  // Calls OsConstants.initConstants.
-  "Ljavax/crypto/KeyGenerator;",  // Calls OsConstants.initConstants.
-  "Ljavax/security/cert/X509Certificate;",  // Calls VMClassLoader.getBootClassPathSize.
-  "Ljavax/security/cert/X509Certificate$1;",  // Calls VMClassLoader.getBootClassPathSize.
-  "Ljavax/microedition/khronos/egl/EGL10;",  // Requires EGLContext.
-  "Ljavax/microedition/khronos/egl/EGLContext;",  // Requires com.google.android.gles_jni.EGLImpl.
-  "Ljavax/xml/datatype/DatatypeConstants;",  // Calls OsConstants.initConstants.
-  "Ljavax/xml/datatype/FactoryFinder;",  // Calls OsConstants.initConstants.
-  "Ljavax/xml/namespace/QName;",  // Calls OsConstants.initConstants.
-  "Ljavax/xml/validation/SchemaFactoryFinder;",  // Calls OsConstants.initConstants.
-  "Ljavax/xml/xpath/XPathConstants;",  // Calls OsConstants.initConstants.
-  "Ljavax/xml/xpath/XPathFactoryFinder;",  // Calls OsConstants.initConstants.
-  "Llibcore/icu/LocaleData;",  // Requires java.util.Locale.
-  "Llibcore/icu/TimeZoneNames;",  // Requires java.util.TimeZone.
-  "Llibcore/io/IoUtils;",  // Calls Random.<init> -> System.currentTimeMillis -> FileDescriptor -> OsConstants.initConstants.
-  "Llibcore/io/OsConstants;",  // Platform specific.
-  "Llibcore/net/MimeUtils;",  // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty.
-  "Llibcore/reflect/Types;",  // Calls OsConstants.initConstants.
-  "Llibcore/util/ZoneInfo;",  // Sub-class of TimeZone.
-  "Llibcore/util/ZoneInfoDB;",  // Calls System.getenv -> OsConstants.initConstants.
-  "Lorg/apache/commons/logging/LogFactory;",  // Calls System.getProperty.
-  "Lorg/apache/commons/logging/impl/LogFactoryImpl;",  // Calls OsConstants.initConstants.
-  "Lorg/apache/harmony/security/fortress/Services;",  // Calls ClassLoader.getSystemClassLoader -> System.getProperty.
-  "Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;",  // Requires java.nio.charsets.Charsets.
-  "Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;",  // Requires java.io.File.
-  "Lorg/apache/harmony/security/utils/AlgNameMapper;",  // Requires java.util.Locale.
-  "Lorg/apache/harmony/security/pkcs10/CertificationRequest;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/pkcs10/CertificationRequestInfo;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/pkcs7/AuthenticatedAttributes;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/pkcs7/SignedData;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/pkcs7/SignerInfo;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/pkcs8/PrivateKeyInfo;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl;",  // Calls OsConstants.initConstants.
-  "Lorg/apache/harmony/security/x501/AttributeTypeAndValue;",  // Calls IntegralToString.convertInt -> Thread.currentThread.
-  "Lorg/apache/harmony/security/x501/DirectoryString;",  // Requires BigInteger.
-  "Lorg/apache/harmony/security/x501/Name;",  // Requires org.apache.harmony.security.x501.AttributeTypeAndValue.
-  "Lorg/apache/harmony/security/x509/AccessDescription;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/AuthorityKeyIdentifier;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/CRLDistributionPoints;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/Certificate;",  // Requires org.apache.harmony.security.x509.TBSCertificate.
-  "Lorg/apache/harmony/security/x509/CertificateIssuer;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/CertificateList;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/DistributionPoint;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/DistributionPointName;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/EDIPartyName;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lorg/apache/harmony/security/x509/GeneralName;",  // Requires org.apache.harmony.security.x501.Name.
-  "Lorg/apache/harmony/security/x509/GeneralNames;",  // Requires GeneralName.
-  "Lorg/apache/harmony/security/x509/GeneralSubtree;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/GeneralSubtrees;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/InfoAccessSyntax;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/IssuingDistributionPoint;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/NameConstraints;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/TBSCertList$RevokedCertificate;",  // Calls NativeBN.BN_new().
-  "Lorg/apache/harmony/security/x509/TBSCertList;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/security/x509/TBSCertificate;",  // Requires org.apache.harmony.security.x501.Name.
-  "Lorg/apache/harmony/security/x509/Time;",  // Calls native ... -> java.math.NativeBN.BN_new().
-  "Lorg/apache/harmony/security/x509/Validity;",  // Requires x509.Time.
-  "Lorg/apache/harmony/security/x509/tsp/TSTInfo;",  // Calls Thread.currentThread.
-  "Lorg/apache/harmony/xml/ExpatParser;",  // Calls native ExpatParser.staticInitialize.
-  "Lorg/apache/harmony/xml/ExpatParser$EntityParser;",  // Calls ExpatParser.staticInitialize.
-  "Lorg/apache/http/conn/params/ConnRouteParams;",  // Requires java.util.Locale.
-  "Lorg/apache/http/conn/ssl/SSLSocketFactory;",  // Calls java.security.Security.getProperty.
-  "Lorg/apache/http/conn/util/InetAddressUtils;",  // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-};
-
 static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index)
     LOCKS_EXCLUDED(Locks::mutator_lock_) {
   ATRACE_CALL();
@@ -2251,33 +1743,49 @@
         manager->GetClassLinker()->EnsureInitialized(klass, false, true);
         if (!klass->IsInitialized()) {
           // We need to initialize static fields, we only do this for image classes that aren't
-          // black listed or marked with the $NoPreloadHolder.
+          // marked with the $NoPreloadHolder (which implies this should not be initialized early).
           bool can_init_static_fields = manager->GetCompiler()->IsImage() &&
-              manager->GetCompiler()->IsImageClass(descriptor);
+              manager->GetCompiler()->IsImageClass(descriptor) &&
+              !StringPiece(descriptor).ends_with("$NoPreloadHolder;");
           if (can_init_static_fields) {
-            // NoPreloadHolder inner class implies this should not be initialized early.
-            bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;");
-            if (!is_black_listed) {
-              for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
-                if (strcmp(descriptor, class_initializer_black_list[i]) == 0) {
-                  is_black_listed = true;
-                  break;
-                }
+            VLOG(compiler) << "Initializing: " << descriptor;
+            if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
+              // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
+              ObjectLock<mirror::Class> lock(soa.Self(), &klass);
+              mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
+              CHECK_EQ(fields->GetLength(), 1);
+              fields->Get(0)->SetObj<false>(klass.get(),
+                                                     manager->GetClassLinker()->FindPrimitiveClass('V'));
+              klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
+            } else {
+              // TODO multithreading support. We should ensure the current compilation thread has
+              // exclusive access to the runtime and the transaction. To achieve this, we could use
+              // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
+              // checks in Thread::AssertThreadSuspensionIsAllowable.
+              Runtime* const runtime = Runtime::Current();
+              Transaction transaction;
+
+              // Run the class initializer in transaction mode.
+              runtime->EnterTransactionMode(&transaction);
+              const mirror::Class::Status old_status = klass->GetStatus();
+              bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true);
+              // TODO we detach transaction from runtime to indicate we quit the transactional
+              // mode which prevents the GC from visiting objects modified during the transaction.
+              // Ensure GC is not run so don't access freed objects when aborting transaction.
+              const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end");
+              runtime->ExitTransactionMode();
+
+              if (!success) {
+                CHECK(soa.Self()->IsExceptionPending());
+                ThrowLocation throw_location;
+                mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
+                VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
+                               << exception->Dump();
+                soa.Self()->ClearException();
+                transaction.Abort();
+                CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
               }
-            }
-            if (!is_black_listed) {
-              VLOG(compiler) << "Initializing: " << descriptor;
-              if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
-                // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
-                ObjectLock<mirror::Class> lock(soa.Self(), &klass);
-                mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
-                CHECK_EQ(fields->GetLength(), 1);
-                fields->Get(0)->SetObj(klass.get(),
-                                       manager->GetClassLinker()->FindPrimitiveClass('V'));
-                klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
-              } else {
-                manager->GetClassLinker()->EnsureInitialized(klass, true, true);
-              }
+              soa.Self()->EndAssertNoThreadSuspension(old_casue);
             }
           }
         }
@@ -2295,18 +1803,20 @@
 void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
                                        ThreadPool& thread_pool, TimingLogger& timings) {
   timings.NewSplit("InitializeNoClinit");
-#ifndef NDEBUG
-  // Sanity check blacklist descriptors.
-  if (IsImage()) {
-    for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
-      const char* descriptor = class_initializer_black_list[i];
-      CHECK(IsValidDescriptor(descriptor)) << descriptor;
-    }
-  }
-#endif
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
-  context.ForAll(0, dex_file.NumClassDefs(), InitializeClass, thread_count_);
+  size_t thread_count;
+  if (IsImage()) {
+    // TODO: remove this when transactional mode supports multithreading.
+    thread_count = 1U;
+  } else {
+    thread_count = thread_count_;
+  }
+  context.ForAll(0, dex_file.NumClassDefs(), InitializeClass, thread_count);
+  if (IsImage()) {
+    // Prune garbage objects created during aborted transactions.
+    Runtime::Current()->GetHeap()->CollectGarbage(true);
+  }
 }
 
 void CompilerDriver::InitializeClasses(jobject class_loader,
@@ -2417,7 +1927,7 @@
   uint64_t start_ns = NanoTime();
 
   if ((access_flags & kAccNative) != 0) {
-    compiled_method = (*jni_compiler_)(*this, access_flags, method_idx, dex_file);
+    compiled_method = compiler_backend_->JniCompile(*this, access_flags, method_idx, dex_file);
     CHECK(compiled_method != NULL);
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
@@ -2425,19 +1935,10 @@
     bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags);
 
     if (compile) {
-      CompilerFn compiler = compiler_;
-#ifdef ART_SEA_IR_MODE
-      bool use_sea = Runtime::Current()->IsSeaIRMode();
-      use_sea = use_sea &&
-          (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
-      if (use_sea) {
-        compiler = sea_ir_compiler_;
-        LOG(INFO) << "Using SEA IR to compile..." << std::endl;
-      }
-#endif
       // NOTE: if compiler declines to compile this method, it will return NULL.
-      compiled_method = (*compiler)(*this, code_item, access_flags, invoke_type, class_def_idx,
-                                    method_idx, class_loader, dex_file);
+      compiled_method = compiler_backend_->Compile(
+          *this, code_item, access_flags, invoke_type, class_def_idx,
+          method_idx, class_loader, dex_file);
     } else if (dex_to_dex_compilation_level != kDontDexToDexCompile) {
       // TODO: add a mode to disable DEX-to-DEX compilation ?
       (*dex_to_dex_compiler_)(*this, code_item, access_flags,
@@ -2447,12 +1948,7 @@
     }
   }
   uint64_t duration_ns = NanoTime() - start_ns;
-#ifdef ART_USE_PORTABLE_COMPILER
-  const uint64_t kWarnMilliSeconds = 1000;
-#else
-  const uint64_t kWarnMilliSeconds = 100;
-#endif
-  if (duration_ns > MsToNs(kWarnMilliSeconds)) {
+  if (duration_ns > MsToNs(compiler_backend_->GetMaximumCompilationTimeBeforeWarning())) {
     LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file)
                  << " took " << PrettyDuration(duration_ns);
   }
@@ -2549,11 +2045,7 @@
                               OatWriter& oat_writer,
                               art::File* file)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(ART_USE_PORTABLE_COMPILER)
-  return art::ElfWriterMclinker::Create(file, oat_writer, dex_files, android_root, is_host, *this);
-#else
-  return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, *this);
-#endif
+  return compiler_backend_->WriteElf(file, oat_writer, dex_files, android_root, is_host, *this);
 }
 void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
                                                 std::string& target_triple,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index c4ac9db..da4b69d 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -26,8 +26,8 @@
 #include "class_reference.h"
 #include "compiled_class.h"
 #include "compiled_method.h"
+#include "compiler_backend.h"
 #include "dex_file.h"
-#include "dex/arena_allocator.h"
 #include "instruction_set.h"
 #include "invoke_type.h"
 #include "method_reference.h"
@@ -35,6 +35,7 @@
 #include "runtime.h"
 #include "safe_map.h"
 #include "thread_pool.h"
+#include "utils/arena_allocator.h"
 #include "utils/dedupe_set.h"
 
 namespace art {
@@ -44,21 +45,15 @@
 }  // namespace verifier
 
 class AOTCompilationStats;
-class ParallelCompilationManager;
 class DexCompilationUnit;
 class DexFileToMethodInlinerMap;
 class InlineIGetIPutData;
 class OatWriter;
+class ParallelCompilationManager;
 class TimingLogger;
 class VerificationResults;
 class VerifiedMethod;
 
-enum CompilerBackend {
-  kQuick,
-  kPortable,
-  kNoBackend
-};
-
 enum EntryPointCallingConvention {
   // ABI of invocations to a method's interpreter entry point.
   kInterpreterAbi,
@@ -101,7 +96,8 @@
   // classes.
   explicit CompilerDriver(VerificationResults* verification_results,
                           DexFileToMethodInlinerMap* method_inliner_map,
-                          CompilerBackend compiler_backend, InstructionSet instruction_set,
+                          CompilerBackend::Kind compiler_backend_kind,
+                          InstructionSet instruction_set,
                           InstructionSetFeatures instruction_set_features,
                           bool image, DescriptorSet* image_classes,
                           size_t thread_count, bool dump_stats, bool dump_passes,
@@ -133,8 +129,8 @@
     return instruction_set_features_;
   }
 
-  CompilerBackend GetCompilerBackend() const {
-    return compiler_backend_;
+  CompilerBackend* GetCompilerBackend() const {
+    return compiler_backend_.get();
   }
 
   // Are we compiling and creating an image file?
@@ -560,7 +556,7 @@
   VerificationResults* verification_results_;
   DexFileToMethodInlinerMap* method_inliner_map_;
 
-  CompilerBackend compiler_backend_;
+  UniquePtr<CompilerBackend> compiler_backend_;
 
   const InstructionSet instruction_set_;
   const InstructionSetFeatures instruction_set_features_;
@@ -601,32 +597,16 @@
 
   void* compiler_library_;
 
-  typedef CompiledMethod* (*CompilerFn)(CompilerDriver& driver,
-                                        const DexFile::CodeItem* code_item,
-                                        uint32_t access_flags, InvokeType invoke_type,
-                                        uint32_t class_dex_idx, uint32_t method_idx,
-                                        jobject class_loader, const DexFile& dex_file);
-
   typedef void (*DexToDexCompilerFn)(CompilerDriver& driver,
                                      const DexFile::CodeItem* code_item,
                                      uint32_t access_flags, InvokeType invoke_type,
                                      uint32_t class_dex_idx, uint32_t method_idx,
                                      jobject class_loader, const DexFile& dex_file,
                                      DexToDexCompilationLevel dex_to_dex_compilation_level);
-  CompilerFn compiler_;
-#ifdef ART_SEA_IR_MODE
-  CompilerFn sea_ir_compiler_;
-#endif
-
   DexToDexCompilerFn dex_to_dex_compiler_;
 
   void* compiler_context_;
 
-  typedef CompiledMethod* (*JniCompilerFn)(CompilerDriver& driver,
-                                           uint32_t access_flags, uint32_t method_idx,
-                                           const DexFile& dex_file);
-  JniCompilerFn jni_compiler_;
-
   pthread_key_t tls_key_;
 
   // Arena pool used by the compiler.
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index e5dfb9d..60beebb 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -408,25 +408,25 @@
                                                                class_linker->GetDexCaches().size());
   int i = 0;
   for (DexCache* dex_cache : class_linker->GetDexCaches()) {
-    dex_caches->Set(i++, dex_cache);
+    dex_caches->Set<false>(i++, dex_cache);
   }
 
   // build an Object[] of the roots needed to restore the runtime
   SirtRef<ObjectArray<Object> > image_roots(
       self, ObjectArray<Object>::Alloc(self, object_array_class.get(), ImageHeader::kImageRootsMax));
-  image_roots->Set(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
-  image_roots->Set(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod());
-  image_roots->Set(ImageHeader::kDefaultImt, runtime->GetDefaultImt());
-  image_roots->Set(ImageHeader::kCalleeSaveMethod,
-                   runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
-  image_roots->Set(ImageHeader::kRefsOnlySaveMethod,
-                   runtime->GetCalleeSaveMethod(Runtime::kRefsOnly));
-  image_roots->Set(ImageHeader::kRefsAndArgsSaveMethod,
-                   runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
-  image_roots->Set(ImageHeader::kOatLocation,
-                   String::AllocFromModifiedUtf8(self, oat_file_->GetLocation().c_str()));
-  image_roots->Set(ImageHeader::kDexCaches, dex_caches);
-  image_roots->Set(ImageHeader::kClassRoots, class_linker->GetClassRoots());
+  image_roots->Set<false>(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
+  image_roots->Set<false>(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod());
+  image_roots->Set<false>(ImageHeader::kDefaultImt, runtime->GetDefaultImt());
+  image_roots->Set<false>(ImageHeader::kCalleeSaveMethod,
+                          runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
+  image_roots->Set<false>(ImageHeader::kRefsOnlySaveMethod,
+                          runtime->GetCalleeSaveMethod(Runtime::kRefsOnly));
+  image_roots->Set<false>(ImageHeader::kRefsAndArgsSaveMethod,
+                          runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
+  image_roots->Set<false>(ImageHeader::kOatLocation,
+                          String::AllocFromModifiedUtf8(self, oat_file_->GetLocation().c_str()));
+  image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches);
+  image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots());
   for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
     CHECK(image_roots->Get(i) != NULL);
   }
@@ -663,7 +663,7 @@
 void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
   for (int32_t i = 0; i < orig->GetLength(); ++i) {
     Object* element = orig->Get(i);
-    copy->SetWithoutChecksAndWriteBarrier(i, GetImageAddress(element));
+    copy->SetWithoutChecksAndWriteBarrier<false>(i, GetImageAddress(element));
   }
 }
 
@@ -693,7 +693,7 @@
       Object* ref = orig->GetFieldObject<Object>(byte_offset, false);
       // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
       // image.
-      copy->SetFieldObjectWithoutWriteBarrier(byte_offset, GetImageAddress(ref), false);
+      copy->SetFieldObjectWithoutWriteBarrier<false>(byte_offset, GetImageAddress(ref), false);
       ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
     }
   } else {
@@ -715,7 +715,7 @@
         Object* ref = orig->GetFieldObject<Object>(field_offset, false);
         // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
         // image.
-        copy->SetFieldObjectWithoutWriteBarrier(field_offset, GetImageAddress(ref), false);
+        copy->SetFieldObjectWithoutWriteBarrier<false>(field_offset, GetImageAddress(ref), false);
       }
     }
   }
@@ -726,7 +726,7 @@
     Object* ref = orig->GetFieldObject<Object>(field_offset, false);
     // Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
     // image.
-    copy->SetFieldObjectWithoutWriteBarrier(field_offset, GetImageAddress(ref), false);
+    copy->SetFieldObjectWithoutWriteBarrier<false>(field_offset, GetImageAddress(ref), false);
   }
 }
 
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index 6563eb5..a5acd2a 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -39,12 +39,12 @@
 
 namespace art {
 void CompileOneMethod(CompilerDriver& driver,
-                      const CompilerBackend compilerBackend,
+                      CompilerBackend* compilerBackend,
                       const DexFile::CodeItem* code_item,
                       uint32_t access_flags, InvokeType invoke_type,
                       uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
                       const DexFile& dex_file,
-                      llvm::LlvmCompilationUnit* llvm_info);
+                      void* llvm_info);
 }
 
 namespace llvm {
@@ -142,7 +142,7 @@
   cunit->SetCompilerDriver(compiler_driver_);
   // TODO: consolidate ArtCompileMethods
   CompileOneMethod(*compiler_driver_,
-                   kPortable,
+                   compiler_driver_->GetCompilerBackend(),
                    dex_compilation_unit->GetCodeItem(),
                    dex_compilation_unit->GetAccessFlags(),
                    invoke_type,
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index f6b511c..10d2c5c 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -15,6 +15,7 @@
  */
 
 #include "compiler/oat_writer.h"
+#include "compiler/compiler_backend.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/object_array-inl.h"
@@ -84,12 +85,14 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
 
   // TODO: make selectable.
-  CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick;
+  CompilerBackend::Kind compiler_backend = kUsePortableCompiler
+      ? CompilerBackend::kPortable
+      : CompilerBackend::kQuick;
   InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
 
   InstructionSetFeatures insn_features;
   verification_results_.reset(new VerificationResults);
-  method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
+  method_inliner_map_.reset(new DexFileToMethodInlinerMap);
   callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
   timer_.reset(new CumulativeLogger("Compilation times"));
   compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
new file mode 100644
index 0000000..2c1091c
--- /dev/null
+++ b/compiler/optimizing/builder.cc
@@ -0,0 +1,64 @@
+/*
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex_instruction.h"
+#include "builder.h"
+#include "nodes.h"
+
+namespace art {
+
+HGraph* HGraphBuilder::BuildGraph(const uint16_t* code_ptr, const uint16_t* code_end) {
+  graph_ = new (arena_) HGraph(arena_);
+
+  entry_block_ = new (arena_) HBasicBlock(graph_);
+  graph_->AddBlock(entry_block_);
+
+  exit_block_ = new (arena_) HBasicBlock(graph_);
+  // The exit block is added at the end of this method to ensure
+  // its id is the greatest. This is needed for dominator computation.
+
+  entry_block_->AddInstruction(new (arena_) HGoto(entry_block_));
+
+  current_block_ = new (arena_) HBasicBlock(graph_);
+  graph_->AddBlock(current_block_);
+  entry_block_->AddSuccessor(current_block_);
+
+  while (code_ptr < code_end) {
+    const Instruction& instruction = *Instruction::At(code_ptr);
+    if (!AnalyzeDexInstruction(instruction)) return nullptr;
+    code_ptr += instruction.SizeInCodeUnits();
+  }
+
+  exit_block_->AddInstruction(new (arena_) HExit(exit_block_));
+  graph_->AddBlock(exit_block_);
+  return graph_;
+}
+
+bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction) {
+  switch (instruction.Opcode()) {
+    case Instruction::RETURN_VOID:
+      current_block_->AddInstruction(new (arena_) HReturnVoid(current_block_));
+      current_block_->AddSuccessor(exit_block_);
+      current_block_ = nullptr;
+      break;
+    default:
+      return false;
+  }
+  return true;
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
new file mode 100644
index 0000000..3e94fba
--- /dev/null
+++ b/compiler/optimizing/builder.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_BUILDER_H_
+#define ART_COMPILER_OPTIMIZING_BUILDER_H_
+
+#include "utils/allocation.h"
+
+namespace art {
+
+class ArenaAllocator;
+class Instruction;
+class HBasicBlock;
+class HGraph;
+
+class HGraphBuilder : public ValueObject {
+ public:
+  explicit HGraphBuilder(ArenaAllocator* arena)
+      : arena_(arena),
+        entry_block_(nullptr),
+        exit_block_(nullptr),
+        current_block_(nullptr),
+        graph_(nullptr) { }
+
+  HGraph* BuildGraph(const uint16_t* start, const uint16_t* end);
+
+ private:
+  // Analyzes the dex instruction and adds HInstruction to the graph
+  // to execute that instruction. Returns whether the instruction can
+  // be handled.
+  bool AnalyzeDexInstruction(const Instruction& instruction);
+
+  ArenaAllocator* const arena_;
+  HBasicBlock* entry_block_;
+  HBasicBlock* exit_block_;
+  HBasicBlock* current_block_;
+  HGraph* graph_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphBuilder);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_BUILDER_H_
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
new file mode 100644
index 0000000..e7e9f47
--- /dev/null
+++ b/compiler/optimizing/nodes.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "nodes.h"
+#include "utils/growable_array.h"
+
+namespace art {
+
+void HGraph::AddBlock(HBasicBlock* block) {
+  block->set_block_id(blocks_.Size());
+  blocks_.Add(block);
+}
+
+void HBasicBlock::AddInstruction(HInstruction* instruction) {
+  if (first_instruction_ == nullptr) {
+    DCHECK(last_instruction_ == nullptr);
+    first_instruction_ = last_instruction_ = instruction;
+  } else {
+    last_instruction_->next_ = instruction;
+    instruction->previous_ = last_instruction_;
+    last_instruction_ = instruction;
+  }
+}
+
+#define DEFINE_ACCEPT(name)                                                    \
+void H##name::Accept(HGraphVisitor* visitor) {                                 \
+  visitor->Visit##name(this);                                                  \
+}
+
+FOR_EACH_INSTRUCTION(DEFINE_ACCEPT)
+
+#undef DEFINE_ACCEPT
+
+void HGraphVisitor::VisitInsertionOrder() {
+  const GrowableArray<HBasicBlock*>* blocks = graph_->blocks();
+  for (size_t i = 0 ; i < blocks->Size(); i++) {
+    VisitBasicBlock(blocks->Get(i));
+  }
+}
+
+void HGraphVisitor::VisitBasicBlock(HBasicBlock* block) {
+  for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
+    it.Current()->Accept(this);
+  }
+}
+
+}  // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
new file mode 100644
index 0000000..3d1c25e
--- /dev/null
+++ b/compiler/optimizing/nodes.h
@@ -0,0 +1,276 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_NODES_H_
+#define ART_COMPILER_OPTIMIZING_NODES_H_
+
+#include "utils/allocation.h"
+#include "utils/growable_array.h"
+
+namespace art {
+
+class HBasicBlock;
+class HInstruction;
+class HGraphVisitor;
+
+static const int kDefaultNumberOfBlocks = 8;
+static const int kDefaultNumberOfSuccessors = 2;
+static const int kDefaultNumberOfPredecessors = 2;
+
+// Control-flow graph of a method. Contains a list of basic blocks.
+class HGraph : public ArenaObject {
+ public:
+  explicit HGraph(ArenaAllocator* arena)
+      : arena_(arena),
+        blocks_(arena, kDefaultNumberOfBlocks) { }
+
+  ArenaAllocator* arena() const { return arena_; }
+  const GrowableArray<HBasicBlock*>* blocks() const { return &blocks_; }
+
+  void AddBlock(HBasicBlock* block);
+
+ private:
+  ArenaAllocator* const arena_;
+  GrowableArray<HBasicBlock*> blocks_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraph);
+};
+
+// A block in a method. Contains the list of instructions represented
+// as a double linked list. Each block knows its predecessors and
+// successors.
+class HBasicBlock : public ArenaObject {
+ public:
+  explicit HBasicBlock(HGraph* graph)
+      : graph_(graph),
+        predecessors_(graph->arena(), kDefaultNumberOfPredecessors),
+        successors_(graph->arena(), kDefaultNumberOfSuccessors),
+        first_instruction_(nullptr),
+        last_instruction_(nullptr),
+        block_id_(-1) { }
+
+  const GrowableArray<HBasicBlock*>* predecessors() const {
+    return &predecessors_;
+  }
+
+  const GrowableArray<HBasicBlock*>* successors() const {
+    return &successors_;
+  }
+
+  HGraph* graph() const { return graph_; }
+
+  int block_id() const { return block_id_; }
+  void set_block_id(int id) { block_id_ = id; }
+
+  HInstruction* first_instruction() const { return first_instruction_; }
+  HInstruction* last_instruction() const { return last_instruction_; }
+
+  void AddSuccessor(HBasicBlock* block) {
+    successors_.Add(block);
+    block->predecessors_.Add(this);
+  }
+
+  void AddInstruction(HInstruction* instruction);
+
+ private:
+  HGraph* const graph_;
+  GrowableArray<HBasicBlock*> predecessors_;
+  GrowableArray<HBasicBlock*> successors_;
+  HInstruction* first_instruction_;
+  HInstruction* last_instruction_;
+  int block_id_;
+
+  DISALLOW_COPY_AND_ASSIGN(HBasicBlock);
+};
+
+#define FOR_EACH_INSTRUCTION(M)                            \
+  M(Exit)                                                  \
+  M(Goto)                                                  \
+  M(ReturnVoid)                                            \
+
+#define DECLARE_INSTRUCTION(type)                          \
+  virtual void Accept(HGraphVisitor* visitor);             \
+  virtual const char* DebugName() const { return #type; }  \
+
+class HInstruction : public ArenaObject {
+ public:
+  explicit HInstruction(HBasicBlock* block)
+      : previous_(nullptr),
+        next_(nullptr) { }
+  virtual ~HInstruction() { }
+
+  HInstruction* next() const { return next_; }
+  HInstruction* previous() const { return previous_; }
+
+  virtual intptr_t InputCount() const  = 0;
+  virtual HInstruction* InputAt(intptr_t i) const = 0;
+
+  virtual void Accept(HGraphVisitor* visitor) = 0;
+  virtual const char* DebugName() const = 0;
+
+ private:
+  HInstruction* previous_;
+  HInstruction* next_;
+
+  friend class HBasicBlock;
+
+  DISALLOW_COPY_AND_ASSIGN(HInstruction);
+};
+
+class HInstructionIterator : public ValueObject {
+ public:
+  explicit HInstructionIterator(HBasicBlock* block)
+      : instruction_(block->first_instruction()) {
+    next_ = Done() ? nullptr : instruction_->next();
+  }
+
+  inline bool Done() const { return instruction_ == nullptr; }
+  inline HInstruction* Current() { return instruction_; }
+  inline void Advance() {
+    instruction_ = next_;
+    next_ = Done() ? nullptr : instruction_->next();
+  }
+
+ private:
+  HInstruction* instruction_;
+  HInstruction* next_;
+};
+
+// An embedded container with N elements of type T.  Used (with partial
+// specialization for N=0) because embedded arrays cannot have size 0.
+template<typename T, intptr_t N>
+class EmbeddedArray {
+ public:
+  EmbeddedArray() : elements_() { }
+
+  intptr_t length() const { return N; }
+
+  const T& operator[](intptr_t i) const {
+    ASSERT(i < length());
+    return elements_[i];
+  }
+
+  T& operator[](intptr_t i) {
+    ASSERT(i < length());
+    return elements_[i];
+  }
+
+  const T& At(intptr_t i) const {
+    return (*this)[i];
+  }
+
+  void SetAt(intptr_t i, const T& val) {
+    (*this)[i] = val;
+  }
+
+ private:
+  T elements_[N];
+};
+
+template<typename T>
+class EmbeddedArray<T, 0> {
+ public:
+  intptr_t length() const { return 0; }
+  const T& operator[](intptr_t i) const {
+    LOG(FATAL) << "Unreachable";
+    static T sentinel = 0;
+    return sentinel;
+  }
+  T& operator[](intptr_t i) {
+    LOG(FATAL) << "Unreachable";
+    static T sentinel = 0;
+    return sentinel;
+  }
+};
+
+template<intptr_t N>
+class HTemplateInstruction: public HInstruction {
+ public:
+  HTemplateInstruction<N>(HBasicBlock* block)
+      : HInstruction(block),
+        inputs_() { }
+  virtual ~HTemplateInstruction() { }
+
+  virtual intptr_t InputCount() const { return N; }
+  virtual HInstruction* InputAt(intptr_t i) const { return inputs_[i]; }
+
+ private:
+  EmbeddedArray<HInstruction*, N> inputs_;
+};
+
+// Represents dex's RETURN_VOID opcode. A HReturnVoid is a control flow
+// instruction that branches to the exit block.
+class HReturnVoid : public HTemplateInstruction<0> {
+ public:
+  explicit HReturnVoid(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+
+  DECLARE_INSTRUCTION(ReturnVoid)
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HReturnVoid);
+};
+
+// The exit instruction is the only instruction of the exit block.
+// Instructions aborting the method (HTrow and HReturn) must branch to the
+// exit block.
+class HExit : public HTemplateInstruction<0> {
+ public:
+  explicit HExit(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+
+  DECLARE_INSTRUCTION(Exit)
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HExit);
+};
+
+// Jumps from one block to another.
+class HGoto : public HTemplateInstruction<0> {
+ public:
+  explicit HGoto(HBasicBlock* block) : HTemplateInstruction<0>(block) { }
+
+  DECLARE_INSTRUCTION(Goto)
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HGoto);
+};
+
+class HGraphVisitor : public ValueObject {
+ public:
+  explicit HGraphVisitor(HGraph* graph) : graph_(graph) { }
+  virtual ~HGraphVisitor() { }
+
+  virtual void VisitInstruction(HInstruction* instruction) { }
+  virtual void VisitBasicBlock(HBasicBlock* block);
+
+  void VisitInsertionOrder();
+
+  // Visit functions for instruction classes.
+#define DECLARE_VISIT_INSTRUCTION(name)                                        \
+  virtual void Visit##name(H##name* instr) { VisitInstruction(instr); }
+
+  FOR_EACH_INSTRUCTION(DECLARE_VISIT_INSTRUCTION)
+
+#undef DECLARE_VISIT_INSTRUCTION
+
+ private:
+  HGraph* graph_;
+
+  DISALLOW_COPY_AND_ASSIGN(HGraphVisitor);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_NODES_H_
diff --git a/compiler/optimizing/pretty_printer.h b/compiler/optimizing/pretty_printer.h
new file mode 100644
index 0000000..62a5a2c
--- /dev/null
+++ b/compiler/optimizing/pretty_printer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_OPTIMIZING_PRETTY_PRINTER_H_
+#define ART_COMPILER_OPTIMIZING_PRETTY_PRINTER_H_
+
+#include "nodes.h"
+
+namespace art {
+
+class HPrettyPrinter : public HGraphVisitor {
+ public:
+  explicit HPrettyPrinter(HGraph* graph) : HGraphVisitor(graph) { }
+
+  virtual void VisitInstruction(HInstruction* instruction) {
+    PrintString("  ");
+    PrintString(instruction->DebugName());
+    PrintNewLine();
+  }
+
+  virtual void VisitBasicBlock(HBasicBlock* block) {
+    PrintString("BasicBlock ");
+    PrintInt(block->block_id());
+    PrintNewLine();
+    HGraphVisitor::VisitBasicBlock(block);
+  }
+
+  virtual void PrintNewLine() = 0;
+  virtual void PrintInt(int value) = 0;
+  virtual void PrintString(const char* value) = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(HPrettyPrinter);
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_OPTIMIZING_PRETTY_PRINTER_H_
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
new file mode 100644
index 0000000..81a0d91
--- /dev/null
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "base/stringprintf.h"
+#include "builder.h"
+#include "dex_instruction.h"
+#include "nodes.h"
+#include "pretty_printer.h"
+#include "utils/arena_allocator.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+const uint16_t data[] = { Instruction::RETURN_VOID };
+
+const char* expected =
+    "BasicBlock 0\n"
+    "  Goto\n"
+    "BasicBlock 1\n"
+    "  ReturnVoid\n"
+    "BasicBlock 2\n"
+    "  Exit\n";
+
+class StringPrettyPrinter : public HPrettyPrinter {
+ public:
+  explicit StringPrettyPrinter(HGraph* graph) : HPrettyPrinter(graph), str_("") { }
+
+  virtual void PrintInt(int value) {
+    str_ += StringPrintf("%d", value);
+  }
+
+  virtual void PrintString(const char* value) {
+    str_ += value;
+  }
+
+  virtual void PrintNewLine() {
+    str_ += '\n';
+  }
+
+  void Clear() { str_.clear(); }
+
+  std::string str() const { return str_; }
+
+ private:
+  std::string str_;
+  DISALLOW_COPY_AND_ASSIGN(StringPrettyPrinter);
+};
+
+TEST(OptimizerTest, ReturnVoid) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HGraphBuilder builder(&allocator);
+  HGraph* graph = builder.BuildGraph(data, data + 1);
+  ASSERT_NE(graph, nullptr);
+  StringPrettyPrinter printer(graph);
+  printer.VisitInsertionOrder();
+  ASSERT_STREQ(expected, printer.str().c_str());
+
+  const GrowableArray<HBasicBlock*>* blocks = graph->blocks();
+  ASSERT_EQ(blocks->Get(0)->predecessors()->Size(), (size_t)0);
+  ASSERT_EQ(blocks->Get(1)->predecessors()->Size(), (size_t)1);
+  ASSERT_EQ(blocks->Get(1)->predecessors()->Get(0), blocks->Get(0));
+  ASSERT_EQ(blocks->Get(2)->predecessors()->Size(), (size_t)1);
+  ASSERT_EQ(blocks->Get(2)->predecessors()->Get(0), blocks->Get(1));
+
+  ASSERT_EQ(blocks->Get(0)->successors()->Size(), (size_t)1);
+  ASSERT_EQ(blocks->Get(1)->successors()->Get(0), blocks->Get(2));
+  ASSERT_EQ(blocks->Get(1)->successors()->Size(), (size_t)1);
+  ASSERT_EQ(blocks->Get(1)->successors()->Get(0), blocks->Get(2));
+  ASSERT_EQ(blocks->Get(2)->successors()->Size(), (size_t)0);
+}
+
+}  // namespace art
diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc
index 6c779c8..b57007b 100644
--- a/compiler/sea_ir/frontend.cc
+++ b/compiler/sea_ir/frontend.cc
@@ -38,15 +38,12 @@
 namespace art {
 
 static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler,
-                                     const CompilerBackend compiler_backend,
+                                     CompilerBackend* compiler_backend,
                                      const DexFile::CodeItem* code_item,
                                      uint32_t method_access_flags, InvokeType invoke_type,
                                      uint16_t class_def_idx, uint32_t method_idx,
-                                     jobject class_loader, const DexFile& dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
-                                     , llvm::LlvmCompilationUnit* llvm_compilation_unit
-#endif
-) {
+                                     jobject class_loader, const DexFile& dex_file,
+                                     void* llvm_compilation_unit) {
   LOG(INFO) << "Compiling " << PrettyMethod(method_idx, dex_file) << ".";
   sea_ir::SeaGraph* ir_graph = sea_ir::SeaGraph::GetGraph(dex_file);
   std::string symbol = "dex_" + MangleForJni(PrettyMethod(method_idx, dex_file));
@@ -65,7 +62,7 @@
 }
 
 CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler,
-                                 const CompilerBackend backend,
+                                 CompilerBackend* backend,
                                  const DexFile::CodeItem* code_item,
                                  uint32_t method_access_flags,
                                  InvokeType invoke_type,
@@ -73,13 +70,9 @@
                                  uint32_t method_idx,
                                  jobject class_loader,
                                  const DexFile& dex_file,
-                                 llvm::LlvmCompilationUnit* llvm_compilation_unit) {
+                                 void* llvm_compilation_unit) {
   return CompileMethodWithSeaIr(compiler, backend, code_item, method_access_flags, invoke_type,
-      class_def_idx, method_idx, class_loader, dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
-                       , llvm_compilation_unit
-#endif
-                       );  // NOLINT
+      class_def_idx, method_idx, class_loader, dex_file, llvm_compilation_unit);
 }
 
 extern "C" art::CompiledMethod*
@@ -90,7 +83,7 @@
                           const art::DexFile& dex_file) {
   // TODO: Check method fingerprint here to determine appropriate backend type.
   //       Until then, use build default
-  art::CompilerBackend backend = compiler.GetCompilerBackend();
+  art::CompilerBackend* backend = compiler.GetCompilerBackend();
   return art::SeaIrCompileOneMethod(compiler, backend, code_item, method_access_flags, invoke_type,
                                class_def_idx, method_idx, class_loader, dex_file,
                                NULL /* use thread llvm_info */);
diff --git a/compiler/utils/allocation.h b/compiler/utils/allocation.h
new file mode 100644
index 0000000..07cd397
--- /dev/null
+++ b/compiler/utils/allocation.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_COMPILER_UTILS_ALLOCATION_H_
+#define ART_COMPILER_UTILS_ALLOCATION_H_
+
+#include "arena_allocator.h"
+#include "base/logging.h"
+
+namespace art {
+
+class ArenaObject {
+ public:
+  // Allocate a new ArenaObject of 'size' bytes in the Arena.
+  void* operator new(size_t size, ArenaAllocator* allocator) {
+    return allocator->Alloc(size, ArenaAllocator::kAllocMisc);
+  }
+
+  void operator delete(void*, size_t) {
+    LOG(FATAL) << "UNREACHABLE";
+  }
+};
+
+class ValueObject {
+ public:
+  void* operator new(size_t size) {
+    LOG(FATAL) << "UNREACHABLE";
+    abort();
+  }
+  void operator delete(void*, size_t) {
+    LOG(FATAL) << "UNREACHABLE";
+  }
+};
+
+}  // namespace art
+
+#endif  // ART_COMPILER_UTILS_ALLOCATION_H_
diff --git a/compiler/dex/arena_allocator.cc b/compiler/utils/arena_allocator.cc
similarity index 98%
rename from compiler/dex/arena_allocator.cc
rename to compiler/utils/arena_allocator.cc
index 8d24439..ec41293 100644
--- a/compiler/dex/arena_allocator.cc
+++ b/compiler/utils/arena_allocator.cc
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#include "compiler_internals.h"
-#include "dex_file-inl.h"
 #include "arena_allocator.h"
 #include "base/logging.h"
 #include "base/mutex.h"
diff --git a/compiler/dex/arena_allocator.h b/compiler/utils/arena_allocator.h
similarity index 95%
rename from compiler/dex/arena_allocator.h
rename to compiler/utils/arena_allocator.h
index d11d67c..56cedfe 100644
--- a/compiler/dex/arena_allocator.h
+++ b/compiler/utils/arena_allocator.h
@@ -14,14 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DEX_ARENA_ALLOCATOR_H_
-#define ART_COMPILER_DEX_ARENA_ALLOCATOR_H_
+#ifndef ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
+#define ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
 
 #include <stdint.h>
 #include <stddef.h>
 
 #include "base/mutex.h"
-#include "compiler_enums.h"
 #include "mem_map.h"
 
 namespace art {
@@ -155,4 +154,4 @@
 
 }  // namespace art
 
-#endif  // ART_COMPILER_DEX_ARENA_ALLOCATOR_H_
+#endif  // ART_COMPILER_UTILS_ARENA_ALLOCATOR_H_
diff --git a/compiler/dex/arena_allocator_test.cc b/compiler/utils/arena_allocator_test.cc
similarity index 92%
rename from compiler/dex/arena_allocator_test.cc
rename to compiler/utils/arena_allocator_test.cc
index 63dc615..b76fe74 100644
--- a/compiler/dex/arena_allocator_test.cc
+++ b/compiler/utils/arena_allocator_test.cc
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-#include "arena_allocator.h"
-#include "arena_bit_vector.h"
+#include "dex/arena_bit_vector.h"
 #include "gtest/gtest.h"
+#include "utils/arena_allocator.h"
 
 namespace art {
 
diff --git a/compiler/dex/growable_array.h b/compiler/utils/growable_array.h
similarity index 91%
rename from compiler/dex/growable_array.h
rename to compiler/utils/growable_array.h
index 6ed207c..b591870 100644
--- a/compiler/dex/growable_array.h
+++ b/compiler/utils/growable_array.h
@@ -14,18 +14,15 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_DEX_GROWABLE_ARRAY_H_
-#define ART_COMPILER_DEX_GROWABLE_ARRAY_H_
+#ifndef ART_COMPILER_UTILS_GROWABLE_ARRAY_H_
+#define ART_COMPILER_UTILS_GROWABLE_ARRAY_H_
 
 #include <stdint.h>
 #include <stddef.h>
-#include "compiler_enums.h"
 #include "arena_allocator.h"
 
 namespace art {
 
-struct CompilationUnit;
-
 // Type of growable list for memory tuning.
 enum OatListKind {
   kGrowableArrayMisc = 0,
@@ -109,7 +106,20 @@
         Resize(num_used_ + 1);
       }
       elem_list_[num_used_++] = elem;
-    };
+    }
+
+    void InsertAt(size_t index, T elem) {
+      DCHECK(index <= Size());
+      Insert(elem);
+      for (size_t i = Size() - 1; i > index; --i) {
+        elem_list_[i] = elem_list_[i - 1];
+      }
+      elem_list_[index] = elem;
+    }
+
+    void Add(T elem) {
+      Insert(elem);
+    }
 
     T Get(size_t index) const {
       DCHECK_LT(index, num_used_);
@@ -173,4 +183,4 @@
 
 }  // namespace art
 
-#endif  // ART_COMPILER_DEX_GROWABLE_ARRAY_H_
+#endif  // ART_COMPILER_UTILS_GROWABLE_ARRAY_H_
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 98c64aa..7f88471 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -30,6 +30,7 @@
 #include "base/timing_logger.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
+#include "compiler_backend.h"
 #include "compiler_callbacks.h"
 #include "dex_file-inl.h"
 #include "dex/verification_results.h"
@@ -163,7 +164,7 @@
  public:
   static bool Create(Dex2Oat** p_dex2oat,
                      Runtime::Options& options,
-                     CompilerBackend compiler_backend,
+                     CompilerBackend::Kind compiler_backend,
                      InstructionSet instruction_set,
                      InstructionSetFeatures instruction_set_features,
                      size_t thread_count)
@@ -286,7 +287,7 @@
                                                         dump_passes,
                                                         &compiler_phases_timings));
 
-    if (compiler_backend_ == kPortable) {
+    if (compiler_backend_ == CompilerBackend::kPortable) {
       driver->SetBitcodeFileName(bitcode_filename);
     }
 
@@ -365,7 +366,7 @@
       virtual bool MethodVerified(verifier::MethodVerifier* verifier)
           SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
         bool result = verification_results_->ProcessVerifiedMethod(verifier);
-        if (result && method_inliner_map_ != nullptr) {
+        if (result) {
           MethodReference ref = verifier->GetMethodReference();
           method_inliner_map_->GetMethodInliner(ref.dex_file)
               ->AnalyseMethodCode(verifier);
@@ -381,7 +382,7 @@
       DexFileToMethodInlinerMap* method_inliner_map_;
   };
 
-  explicit Dex2Oat(CompilerBackend compiler_backend,
+  explicit Dex2Oat(CompilerBackend::Kind compiler_backend,
                    InstructionSet instruction_set,
                    InstructionSetFeatures instruction_set_features,
                    size_t thread_count)
@@ -389,7 +390,7 @@
         instruction_set_(instruction_set),
         instruction_set_features_(instruction_set_features),
         verification_results_(new VerificationResults),
-        method_inliner_map_(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr),
+        method_inliner_map_(new DexFileToMethodInlinerMap),
         callbacks_(verification_results_.get(), method_inliner_map_.get()),
         runtime_(nullptr),
         thread_count_(thread_count),
@@ -449,7 +450,7 @@
     return false;
   }
 
-  const CompilerBackend compiler_backend_;
+  const CompilerBackend::Kind compiler_backend_;
 
   const InstructionSet instruction_set_;
   const InstructionSetFeatures instruction_set_features_;
@@ -688,7 +689,9 @@
   std::string android_root;
   std::vector<const char*> runtime_args;
   int thread_count = sysconf(_SC_NPROCESSORS_CONF);
-  CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick;
+  CompilerBackend::Kind compiler_backend = kUsePortableCompiler
+      ? CompilerBackend::kPortable
+      : CompilerBackend::kQuick;
 
   // Take the default set of instruction features from the build.
   InstructionSetFeatures instruction_set_features =
@@ -788,9 +791,9 @@
     } else if (option.starts_with("--compiler-backend=")) {
       StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
       if (backend_str == "Quick") {
-        compiler_backend = kQuick;
+        compiler_backend = CompilerBackend::kQuick;
       } else if (backend_str == "Portable") {
-        compiler_backend = kPortable;
+        compiler_backend = CompilerBackend::kPortable;
       }
     } else if (option == "--host") {
       is_host = true;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 73c75fb..1e5a681 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -136,6 +136,7 @@
 	thread_pool.cc \
 	throw_location.cc \
 	trace.cc \
+	transaction.cc \
 	profiler.cc \
 	utf.cc \
 	utils.cc \
diff --git a/runtime/arch/arm/context_arm.h b/runtime/arch/arm/context_arm.h
index 020cae0..4a0d082 100644
--- a/runtime/arch/arm/context_arm.h
+++ b/runtime/arch/arm/context_arm.h
@@ -45,6 +45,11 @@
     SetGPR(PC, new_pc);
   }
 
+  virtual uintptr_t* GetGPRAddress(uint32_t reg) {
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters));
+    return gprs_[reg];
+  }
+
   virtual uintptr_t GetGPR(uint32_t reg) {
     DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters));
     return *gprs_[reg];
diff --git a/runtime/arch/context.h b/runtime/arch/context.h
index 3d11178..83bbb11 100644
--- a/runtime/arch/context.h
+++ b/runtime/arch/context.h
@@ -49,6 +49,9 @@
   // Set the program counter value
   virtual void SetPC(uintptr_t new_pc) = 0;
 
+  // Gets the given GPRs address.
+  virtual uintptr_t* GetGPRAddress(uint32_t reg) = 0;
+
   // Read the given GPR
   virtual uintptr_t GetGPR(uint32_t reg) = 0;
 
diff --git a/runtime/arch/mips/context_mips.h b/runtime/arch/mips/context_mips.h
index 4145cd3..d5f27ae 100644
--- a/runtime/arch/mips/context_mips.h
+++ b/runtime/arch/mips/context_mips.h
@@ -43,6 +43,11 @@
     SetGPR(RA, new_pc);
   }
 
+  virtual uintptr_t* GetGPRAddress(uint32_t reg) {
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters));
+    return gprs_[reg];
+  }
+
   virtual uintptr_t GetGPR(uint32_t reg) {
     CHECK_LT(reg, static_cast<uint32_t>(kNumberOfCoreRegisters));
     return *gprs_[reg];
diff --git a/runtime/arch/x86/context_x86.cc b/runtime/arch/x86/context_x86.cc
index d7dca64..5cf3001 100644
--- a/runtime/arch/x86/context_x86.cc
+++ b/runtime/arch/x86/context_x86.cc
@@ -26,7 +26,7 @@
 static const uintptr_t gZero = 0;
 
 void X86Context::Reset() {
-  for (int i = 0; i < kNumberOfCpuRegisters; i++) {
+  for (size_t  i = 0; i < kNumberOfCpuRegisters; i++) {
     gprs_[i] = NULL;
   }
   gprs_[ESP] = &esp_;
diff --git a/runtime/arch/x86/context_x86.h b/runtime/arch/x86/context_x86.h
index 598314d..1c51026 100644
--- a/runtime/arch/x86/context_x86.h
+++ b/runtime/arch/x86/context_x86.h
@@ -43,9 +43,13 @@
     eip_ = new_pc;
   }
 
+  virtual uintptr_t* GetGPRAddress(uint32_t reg) {
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters));
+    return gprs_[reg];
+  }
+
   virtual uintptr_t GetGPR(uint32_t reg) {
-    const uint32_t kNumberOfCpuRegisters = 8;
-    DCHECK_LT(reg, kNumberOfCpuRegisters);
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters));
     return *gprs_[reg];
   }
 
diff --git a/runtime/arch/x86_64/context_x86_64.cc b/runtime/arch/x86_64/context_x86_64.cc
index 4d1131c..1310402 100644
--- a/runtime/arch/x86_64/context_x86_64.cc
+++ b/runtime/arch/x86_64/context_x86_64.cc
@@ -26,7 +26,7 @@
 static const uintptr_t gZero = 0;
 
 void X86_64Context::Reset() {
-  for (int i = 0; i < kNumberOfCpuRegisters; i++) {
+  for (size_t i = 0; i < kNumberOfCpuRegisters; i++) {
     gprs_[i] = NULL;
   }
   gprs_[RSP] = &rsp_;
diff --git a/runtime/arch/x86_64/context_x86_64.h b/runtime/arch/x86_64/context_x86_64.h
index 3e49165..78ef89c 100644
--- a/runtime/arch/x86_64/context_x86_64.h
+++ b/runtime/arch/x86_64/context_x86_64.h
@@ -43,9 +43,13 @@
     rip_ = new_pc;
   }
 
+  virtual uintptr_t* GetGPRAddress(uint32_t reg) {
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters));
+    return gprs_[reg];
+  }
+
   virtual uintptr_t GetGPR(uint32_t reg) {
-    const uint32_t kNumberOfCpuRegisters = 8;
-    DCHECK_LT(reg, kNumberOfCpuRegisters);
+    DCHECK_LT(reg, static_cast<uint32_t>(kNumberOfCpuRegisters));
     return *gprs_[reg];
   }
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index fac1e14..f8a20d0 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1120,14 +1120,13 @@
 // reinit references to when reinitializing a ClassLinker from a
 // mapped image.
 void ClassLinker::VisitRoots(RootCallback* callback, void* arg, bool only_dirty, bool clean_dirty) {
-  class_roots_ = down_cast<mirror::ObjectArray<mirror::Class>*>(
-      callback(class_roots_, arg, 0, kRootVMInternal));
+  callback(reinterpret_cast<mirror::Object**>(&class_roots_), arg, 0, kRootVMInternal);
   Thread* self = Thread::Current();
   {
     ReaderMutexLock mu(self, dex_lock_);
     if (!only_dirty || dex_caches_dirty_) {
       for (mirror::DexCache*& dex_cache : dex_caches_) {
-        dex_cache = down_cast<mirror::DexCache*>(callback(dex_cache, arg, 0, kRootVMInternal));
+        callback(reinterpret_cast<mirror::Object**>(&dex_cache), arg, 0, kRootVMInternal);
         DCHECK(dex_cache != nullptr);
       }
       if (clean_dirty) {
@@ -1135,25 +1134,21 @@
       }
     }
   }
-
   {
     WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
     if (!only_dirty || class_table_dirty_) {
       for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
-        it.second = down_cast<mirror::Class*>(callback(it.second, arg, 0, kRootStickyClass));
+        callback(reinterpret_cast<mirror::Object**>(&it.second), arg, 0, kRootStickyClass);
         DCHECK(it.second != nullptr);
       }
       if (clean_dirty) {
         class_table_dirty_ = false;
       }
     }
-
     // We deliberately ignore the class roots in the image since we
     // handle image roots by using the MS/CMS rescanning of dirty cards.
   }
-
-  array_iftable_ = reinterpret_cast<mirror::IfTable*>(callback(array_iftable_, arg, 0,
-                                                               kRootVMInternal));
+  callback(reinterpret_cast<mirror::Object**>(&array_iftable_), arg, 0, kRootVMInternal);
   DCHECK(array_iftable_ != nullptr);
 }
 
@@ -2832,8 +2827,8 @@
       return nullptr;
     }
 
-    interfaces_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
-    throws_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+    interfaces_sfield->SetObject<false>(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+    throws_sfield->SetObject<false>(klass.get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
     klass->SetStatus(mirror::Class::kStatusInitialized, self);
   }
 
@@ -3144,7 +3139,11 @@
       SafeMap<uint32_t, mirror::ArtField*> field_map;
       ConstructFieldMap(dex_file, *dex_class_def, klass.get(), field_map);
       for (size_t i = 0; it.HasNext(); i++, it.Next()) {
-        it.ReadValueToField(field_map.Get(i));
+        if (Runtime::Current()->IsActiveTransaction()) {
+          it.ReadValueToField<true>(field_map.Get(i));
+        } else {
+          it.ReadValueToField<false>(field_map.Get(i));
+        }
       }
     }
   }
@@ -3530,7 +3529,7 @@
                                 super_mh.GetDeclaringClassDescriptor());
               return false;
             }
-            vtable->Set(j, local_method);
+            vtable->Set<false>(j, local_method);
             local_method->SetMethodIndex(j);
             break;
           } else {
@@ -3542,7 +3541,7 @@
       }
       if (j == actual_count) {
         // Not overriding, append.
-        vtable->Set(actual_count, local_method);
+        vtable->Set<false>(actual_count, local_method);
         local_method->SetMethodIndex(actual_count);
         actual_count += 1;
       }
@@ -3576,7 +3575,7 @@
     }
     for (size_t i = 0; i < num_virtual_methods; ++i) {
       mirror::ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i);
-      vtable->Set(i, virtual_method);
+      vtable->Set<false>(i, virtual_method);
       virtual_method->SetMethodIndex(i & 0xFFFF);
     }
     klass->SetVTable(vtable.get());
@@ -3745,14 +3744,14 @@
                                       PrettyMethod(interface_method).c_str());
               return false;
             }
-            method_array->Set(j, vtable_method);
+            method_array->Set<false>(j, vtable_method);
             // Place method in imt if entry is empty, place conflict otherwise.
             uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize;
             if (imtable->Get(imt_index) == NULL) {
-              imtable->Set(imt_index, vtable_method);
+              imtable->Set<false>(imt_index, vtable_method);
               imtable_changed = true;
             } else {
-              imtable->Set(imt_index, Runtime::Current()->GetImtConflictMethod());
+              imtable->Set<false>(imt_index, Runtime::Current()->GetImtConflictMethod());
             }
             break;
           }
@@ -3777,7 +3776,7 @@
             // TODO: If a methods move then the miranda_list may hold stale references.
             miranda_list.push_back(miranda_method.get());
           }
-          method_array->Set(j, miranda_method.get());
+          method_array->Set<false>(j, miranda_method.get());
         }
       }
     }
@@ -3787,7 +3786,7 @@
     mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
     for (size_t i = 0; i < kImtSize; i++) {
       if (imtable->Get(i) == NULL) {
-        imtable->Set(i, imt_conflict_method);
+        imtable->Set<false>(i, imt_conflict_method);
       }
     }
     klass->SetImTable(imtable.get());
@@ -3823,7 +3822,7 @@
       method->SetAccessFlags(method->GetAccessFlags() | kAccMiranda);
       method->SetMethodIndex(0xFFFF & (old_vtable_count + i));
       klass->SetVirtualMethod(old_method_count + i, method);
-      vtable->Set(old_vtable_count + i, method);
+      vtable->Set<false>(old_vtable_count + i, method);
     }
     // TODO: do not assign to the vtable field until it is fully constructed.
     klass->SetVTable(vtable.get());
@@ -3929,7 +3928,7 @@
     }
     grouped_and_sorted_fields.pop_front();
     num_reference_fields++;
-    fields->Set(current_field, field);
+    fields->Set<false>(current_field, field);
     field->SetOffset(field_offset);
     field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t));
   }
@@ -3946,7 +3945,7 @@
       if (type == Primitive::kPrimLong || type == Primitive::kPrimDouble) {
         continue;
       }
-      fields->Set(current_field++, field);
+      fields->Set<false>(current_field++, field);
       field->SetOffset(field_offset);
       // drop the consumed field
       grouped_and_sorted_fields.erase(grouped_and_sorted_fields.begin() + i);
@@ -3965,7 +3964,7 @@
     FieldHelper fh(field);
     Primitive::Type type = fh.GetTypeAsPrimitiveType();
     CHECK(type != Primitive::kPrimNot);  // should only be working on primitive types
-    fields->Set(current_field, field);
+    fields->Set<false>(current_field, field);
     field->SetOffset(field_offset);
     field_offset = MemberOffset(field_offset.Uint32Value() +
                                 ((type == Primitive::kPrimLong || type == Primitive::kPrimDouble)
@@ -4418,7 +4417,7 @@
 
   DCHECK(class_roots_ != NULL);
   DCHECK(class_roots_->Get(class_root) == NULL);
-  class_roots_->Set(class_root, klass);
+  class_roots_->Set<false>(class_root, klass);
 }
 
 }  // namespace art
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index d9ef0c1..ebf02fe 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -339,9 +339,8 @@
     }
   }
 
-  static mirror::Object* TestRootVisitor(mirror::Object* root, void*, uint32_t, RootType) {
-    EXPECT_TRUE(root != NULL);
-    return root;
+  static void TestRootVisitor(mirror::Object** root, void*, uint32_t, RootType) {
+    EXPECT_TRUE(*root != NULL);
   }
 };
 
@@ -867,55 +866,56 @@
   EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor(), "Ljava/lang/reflect/ArtField;");
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean);
   EXPECT_EQ(true, s0->GetBoolean(statics.get()));
-  s0->SetBoolean(statics.get(), false);
+  s0->SetBoolean<false>(statics.get(), false);
 
   mirror::ArtField* s1 = statics->FindStaticField("s1", "B");
   fh.ChangeField(s1);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimByte);
   EXPECT_EQ(5, s1->GetByte(statics.get()));
-  s1->SetByte(statics.get(), 6);
+  s1->SetByte<false>(statics.get(), 6);
 
   mirror::ArtField* s2 = statics->FindStaticField("s2", "C");
   fh.ChangeField(s2);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimChar);
   EXPECT_EQ('a', s2->GetChar(statics.get()));
-  s2->SetChar(statics.get(), 'b');
+  s2->SetChar<false>(statics.get(), 'b');
 
   mirror::ArtField* s3 = statics->FindStaticField("s3", "S");
   fh.ChangeField(s3);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimShort);
   EXPECT_EQ(-536, s3->GetShort(statics.get()));
-  s3->SetShort(statics.get(), -535);
+  s3->SetShort<false>(statics.get(), -535);
 
   mirror::ArtField* s4 = statics->FindStaticField("s4", "I");
   fh.ChangeField(s4);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimInt);
   EXPECT_EQ(2000000000, s4->GetInt(statics.get()));
-  s4->SetInt(statics.get(), 2000000001);
+  s4->SetInt<false>(statics.get(), 2000000001);
 
   mirror::ArtField* s5 = statics->FindStaticField("s5", "J");
   fh.ChangeField(s5);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimLong);
   EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.get()));
-  s5->SetLong(statics.get(), 0x34567890abcdef12LL);
+  s5->SetLong<false>(statics.get(), 0x34567890abcdef12LL);
 
   mirror::ArtField* s6 = statics->FindStaticField("s6", "F");
   fh.ChangeField(s6);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat);
   EXPECT_EQ(0.5, s6->GetFloat(statics.get()));
-  s6->SetFloat(statics.get(), 0.75);
+  s6->SetFloat<false>(statics.get(), 0.75);
 
   mirror::ArtField* s7 = statics->FindStaticField("s7", "D");
   fh.ChangeField(s7);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimDouble);
   EXPECT_EQ(16777217, s7->GetDouble(statics.get()));
-  s7->SetDouble(statics.get(), 16777219);
+  s7->SetDouble<false>(statics.get(), 16777219);
 
   mirror::ArtField* s8 = statics->FindStaticField("s8", "Ljava/lang/String;");
   fh.ChangeField(s8);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimNot);
   EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("android"));
-  s8->SetObject(s8->GetDeclaringClass(), mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"));
+  s8->SetObject<false>(s8->GetDeclaringClass(),
+                       mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"));
 
   // TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ
   // http://code.google.com/p/googletest/issues/detail?id=322
diff --git a/runtime/common_test.h b/runtime/common_test.h
index f7859ea..7f9b6b1 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -25,6 +25,7 @@
 #include <fstream>
 
 #include "../../external/icu4c/common/unicode/uvernum.h"
+#include "../compiler/compiler_backend.h"
 #include "../compiler/dex/quick/dex_file_to_method_inliner_map.h"
 #include "../compiler/dex/verification_results.h"
 #include "../compiler/driver/compiler_driver.h"
@@ -380,7 +381,16 @@
       // $ANDROID_ROOT is set on the device, but not on the host.
       // We need to set this so that icu4c can find its locale data.
       std::string root;
-      root += getenv("ANDROID_BUILD_TOP");
+      const char* android_build_top = getenv("ANDROID_BUILD_TOP");
+      if (android_build_top != nullptr) {
+        root += android_build_top;
+      } else {
+        // Not set by build server, so default to current directory
+        char* cwd = getcwd(nullptr, 0);
+        setenv("ANDROID_BUILD_TOP", cwd, 1);
+        root += cwd;
+        free(cwd);
+      }
 #if defined(__linux__)
       root += "/out/host/linux-x86";
 #elif defined(__APPLE__)
@@ -390,6 +400,11 @@
 #endif
       setenv("ANDROID_ROOT", root.c_str(), 1);
       setenv("LD_LIBRARY_PATH", ":", 0);  // Required by java.lang.System.<clinit>.
+
+      // Not set by build server, so default
+      if (getenv("ANDROID_HOST_OUT") == nullptr) {
+        setenv("ANDROID_HOST_OUT", root.c_str(), 1);
+      }
     }
 
     // On target, Cannot use /mnt/sdcard because it is mounted noexec, so use subdir of dalvik-cache
@@ -416,7 +431,7 @@
 
  protected:
   static bool IsHost() {
-    return (getenv("ANDROID_BUILD_TOP") != NULL);
+    return !kIsTargetBuild;
   }
 
   virtual void SetUp() {
@@ -439,10 +454,12 @@
     std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));
 
     // TODO: make selectable
-    CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick;
+    CompilerBackend::Kind compiler_backend = kUsePortableCompiler
+        ? CompilerBackend::kPortable
+        : CompilerBackend::kQuick;
 
     verification_results_.reset(new VerificationResults);
-    method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
+    method_inliner_map_.reset(new DexFileToMethodInlinerMap);
     callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
     Runtime::Options options;
     options.push_back(std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_)));
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 733e843..20ad372 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1149,7 +1149,7 @@
       if (o == ObjectRegistry::kInvalidObject) {
         return JDWP::ERR_INVALID_OBJECT;
       }
-      oa->Set(offset + i, o);
+      oa->Set<false>(offset + i, o);
     }
   }
 
@@ -1582,10 +1582,12 @@
   if (IsPrimitiveTag(tag)) {
     if (tag == JDWP::JT_DOUBLE || tag == JDWP::JT_LONG) {
       CHECK_EQ(width, 8);
-      f->Set64(o, value);
+      // Debugging can't use transactional mode (runtime only).
+      f->Set64<false>(o, value);
     } else {
       CHECK_LE(width, 4);
-      f->Set32(o, value);
+      // Debugging can't use transactional mode (runtime only).
+      f->Set32<false>(o, value);
     }
   } else {
     mirror::Object* v = gRegistry->Get<mirror::Object*>(value);
@@ -1598,7 +1600,8 @@
         return JDWP::ERR_INVALID_OBJECT;
       }
     }
-    f->SetObject(o, v);
+    // Debugging can't use transactional mode (runtime only).
+    f->SetObject<false>(o, v);
   }
 
   return JDWP::ERR_NONE;
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index eaba7eb..5e2b9ff 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -1082,33 +1082,36 @@
   ptr_ += width;
 }
 
+template<bool kTransactionActive>
 void EncodedStaticFieldValueIterator::ReadValueToField(mirror::ArtField* field) const {
   switch (type_) {
-    case kBoolean: field->SetBoolean(field->GetDeclaringClass(), jval_.z); break;
-    case kByte:    field->SetByte(field->GetDeclaringClass(), jval_.b); break;
-    case kShort:   field->SetShort(field->GetDeclaringClass(), jval_.s); break;
-    case kChar:    field->SetChar(field->GetDeclaringClass(), jval_.c); break;
-    case kInt:     field->SetInt(field->GetDeclaringClass(), jval_.i); break;
-    case kLong:    field->SetLong(field->GetDeclaringClass(), jval_.j); break;
-    case kFloat:   field->SetFloat(field->GetDeclaringClass(), jval_.f); break;
-    case kDouble:  field->SetDouble(field->GetDeclaringClass(), jval_.d); break;
-    case kNull:    field->SetObject(field->GetDeclaringClass(), NULL); break;
+    case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z); break;
+    case kByte:    field->SetByte<kTransactionActive>(field->GetDeclaringClass(), jval_.b); break;
+    case kShort:   field->SetShort<kTransactionActive>(field->GetDeclaringClass(), jval_.s); break;
+    case kChar:    field->SetChar<kTransactionActive>(field->GetDeclaringClass(), jval_.c); break;
+    case kInt:     field->SetInt<kTransactionActive>(field->GetDeclaringClass(), jval_.i); break;
+    case kLong:    field->SetLong<kTransactionActive>(field->GetDeclaringClass(), jval_.j); break;
+    case kFloat:   field->SetFloat<kTransactionActive>(field->GetDeclaringClass(), jval_.f); break;
+    case kDouble:  field->SetDouble<kTransactionActive>(field->GetDeclaringClass(), jval_.d); break;
+    case kNull:    field->SetObject<kTransactionActive>(field->GetDeclaringClass(), NULL); break;
     case kString: {
       CHECK(!kMovingFields);
       mirror::String* resolved = linker_->ResolveString(dex_file_, jval_.i, *dex_cache_);
-      field->SetObject(field->GetDeclaringClass(), resolved);
+      field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
       break;
     }
     case kType: {
       CHECK(!kMovingFields);
       mirror::Class* resolved = linker_->ResolveType(dex_file_, jval_.i, *dex_cache_,
                                                      *class_loader_);
-      field->SetObject(field->GetDeclaringClass(), resolved);
+      field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
       break;
     }
     default: UNIMPLEMENTED(FATAL) << ": type " << type_;
   }
 }
+template void EncodedStaticFieldValueIterator::ReadValueToField<true>(mirror::ArtField* field) const;
+template void EncodedStaticFieldValueIterator::ReadValueToField<false>(mirror::ArtField* field) const;
 
 CatchHandlerIterator::CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address) {
   handler_.address_ = -1;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 46df455..e9d18b5 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -1142,6 +1142,7 @@
                                   ClassLinker* linker, const DexFile::ClassDef& class_def)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template<bool kTransactionActive>
   void ReadValueToField(mirror::ArtField* field) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool HasNext() { return pos_ < array_size_; }
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 4e58a72..4078cac 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -162,7 +162,7 @@
           CHECK(soa.Self()->IsExceptionPending());
           return zero;
         }
-        soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set(i, val);
+        soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set<false>(i, val);
       }
     }
   }
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 20532f4..8b94b5a 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -136,6 +136,7 @@
     gc::Heap* heap = Runtime::Current()->GetHeap();
     return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
   }
+  DCHECK(klass != nullptr);
   return klass->Alloc<kInstrumented>(self, allocator_type);
 }
 
@@ -377,10 +378,11 @@
 #undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
 
 template<InvokeType type, bool access_check>
-static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object* this_object,
+static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
+                                                    mirror::Object* this_object,
                                                     mirror::ArtMethod* referrer, Thread* self) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  SirtRef<mirror::Object> sirt_this(self, this_object);
+  SirtRef<mirror::Object> sirt_this(self, type == kStatic ? nullptr : this_object);
   mirror::ArtMethod* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type);
   if (UNLIKELY(resolved_method == nullptr)) {
     DCHECK(self->IsExceptionPending());  // Throw exception and unwind.
diff --git a/runtime/entrypoints/portable/portable_field_entrypoints.cc b/runtime/entrypoints/portable/portable_field_entrypoints.cc
index 0b54b9c..f48f1a9 100644
--- a/runtime/entrypoints/portable/portable_field_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_field_entrypoints.cc
@@ -30,13 +30,15 @@
                                StaticPrimitiveWrite,
                                sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
-    field->Set32(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(field->GetDeclaringClass(), new_value);
     return 0;
   }
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
                                                         sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
-    field->Set32(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(field->GetDeclaringClass(), new_value);
     return 0;
   }
   return -1;
@@ -48,13 +50,15 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
-    field->Set64(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(field->GetDeclaringClass(), new_value);
     return 0;
   }
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
                                                         sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
-    field->Set64(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(field->GetDeclaringClass(), new_value);
     return 0;
   }
   return -1;
@@ -67,13 +71,15 @@
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectWrite,
                                           sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != NULL)) {
-    field->SetObj(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->SetObj<false>(field->GetDeclaringClass(), new_value);
     return 0;
   }
   field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, Thread::Current(),
                                                      sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != NULL)) {
-    field->SetObj(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->SetObj<false>(field->GetDeclaringClass(), new_value);
     return 0;
   }
   return -1;
@@ -131,13 +137,15 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
-    field->Set32(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(obj, new_value);
     return 0;
   }
   field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
                                                           sizeof(uint32_t));
   if (LIKELY(field != NULL)) {
-    field->Set32(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(obj, new_value);
     return 0;
   }
   return -1;
@@ -149,13 +157,15 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
-    field->Set64(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(obj, new_value);
     return 0;
   }
   field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
                                                           sizeof(uint64_t));
   if (LIKELY(field != NULL)) {
-    field->Set64(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(obj, new_value);
     return 0;
   }
   return -1;
@@ -169,13 +179,15 @@
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
                                           sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != NULL)) {
-    field->SetObj(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->SetObj<false>(obj, new_value);
     return 0;
   }
   field = FindFieldFromCode<InstanceObjectWrite, true>(field_idx, referrer, Thread::Current(),
                                                        sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != NULL)) {
-    field->SetObj(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->SetObj<false>(obj, new_value);
     return 0;
   }
   return -1;
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index 93ff7aa..2d5c07d 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -154,13 +154,15 @@
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
                                           sizeof(int32_t));
   if (LIKELY(field != NULL)) {
-    field->Set32(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int32_t));
   if (LIKELY(field != NULL)) {
-    field->Set32(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
   }
   return -1;  // failure
@@ -172,13 +174,15 @@
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
                                           sizeof(int64_t));
   if (LIKELY(field != NULL)) {
-    field->Set64(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
   field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
   if (LIKELY(field != NULL)) {
-    field->Set64(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
   }
   return -1;  // failure
@@ -192,7 +196,8 @@
                                           sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != NULL)) {
     if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
-      field->SetObj(field->GetDeclaringClass(), new_value);
+      // Compiled code can't use transactional mode.
+      field->SetObj<false>(field->GetDeclaringClass(), new_value);
       return 0;  // success
     }
   }
@@ -200,7 +205,8 @@
   field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, self,
                                                      sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != NULL)) {
-    field->SetObj(field->GetDeclaringClass(), new_value);
+    // Compiled code can't use transactional mode.
+    field->SetObj<false>(field->GetDeclaringClass(), new_value);
     return 0;  // success
   }
   return -1;  // failure
@@ -213,7 +219,8 @@
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
                                           sizeof(int32_t));
   if (LIKELY(field != NULL && obj != NULL)) {
-    field->Set32(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->Set32<false>(obj, new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -224,7 +231,8 @@
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
-      field->Set32(obj, new_value);
+      // Compiled code can't use transactional mode.
+      field->Set32<false>(obj, new_value);
       return 0;  // success
     }
   }
@@ -240,7 +248,8 @@
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
                                           sizeof(int64_t));
   if (LIKELY(field != NULL  && obj != NULL)) {
-    field->Set64(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->Set64<false>(obj, new_value);
     return 0;  // success
   }
   *sp = callee_save;
@@ -252,7 +261,8 @@
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
-      field->Set64(obj, new_value);
+      // Compiled code can't use transactional mode.
+      field->Set64<false>(obj, new_value);
       return 0;  // success
     }
   }
@@ -267,7 +277,8 @@
   mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
                                           sizeof(mirror::HeapReference<mirror::Object>));
   if (LIKELY(field != NULL && obj != NULL)) {
-    field->SetObj(obj, new_value);
+    // Compiled code can't use transactional mode.
+    field->SetObj<false>(obj, new_value);
     return 0;  // success
   }
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -278,7 +289,8 @@
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
     } else {
-      field->SetObj(obj, new_value);
+      // Compiled code can't use transactional mode.
+      field->SetObj<false>(obj, new_value);
       return 0;  // success
     }
   }
diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
index c081768..e024a90 100644
--- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
@@ -147,8 +147,8 @@
 uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
                          mirror::ArtMethod* caller_method,
                          Thread* self, mirror::ArtMethod** sp) {
-  mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method,
-                                                  access_check, type);
+  mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
+                                             type);
   if (UNLIKELY(method == NULL)) {
     FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
     method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, self);
diff --git a/runtime/entrypoints/quick/quick_lock_entrypoints.cc b/runtime/entrypoints/quick/quick_lock_entrypoints.cc
index 540abb3..5bc7f4c 100644
--- a/runtime/entrypoints/quick/quick_lock_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_lock_entrypoints.cc
@@ -30,10 +30,8 @@
     return -1;  // Failure.
   } else {
     if (kIsDebugBuild) {
-      // GC may move the obj, need Sirt for the following DCHECKs.
-      SirtRef<mirror::Object> sirt_obj(self, obj);
-      obj->MonitorEnter(self);  // May block
-      CHECK(self->HoldsLock(sirt_obj.get()));
+      obj = obj->MonitorEnter(self);  // May block
+      CHECK(self->HoldsLock(obj));
       CHECK(!self->IsExceptionPending());
     } else {
       obj->MonitorEnter(self);  // May block
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index f9486c3..012dabb 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -558,7 +558,7 @@
       // We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
       // of the sharpened method.
       if (called->GetDexCacheResolvedMethods() == caller->GetDexCacheResolvedMethods()) {
-        caller->GetDexCacheResolvedMethods()->Set(called->GetDexMethodIndex(), called);
+        caller->GetDexCacheResolvedMethods()->Set<false>(called->GetDexMethodIndex(), called);
       } else {
         // Calling from one dex file to another, need to compute the method index appropriate to
         // the caller's dex file. Since we get here only if the original called was a runtime
@@ -567,7 +567,7 @@
         uint32_t method_index =
             MethodHelper(called).FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
         if (method_index != DexFile::kDexNoIndex) {
-          caller->GetDexCacheResolvedMethods()->Set(method_index, called);
+          caller->GetDexCacheResolvedMethods()->Set<false>(method_index, called);
         }
       }
     }
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index aad214a..06127c1 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -70,7 +70,7 @@
 
 class ModUnionUpdateObjectReferencesVisitor {
  public:
-  ModUnionUpdateObjectReferencesVisitor(RootCallback* callback, void* arg)
+  ModUnionUpdateObjectReferencesVisitor(MarkObjectCallback* callback, void* arg)
     : callback_(callback),
       arg_(arg) {
   }
@@ -80,23 +80,27 @@
                   bool /* is_static */) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // Only add the reference if it is non null and fits our criteria.
     if (ref != nullptr) {
-      Object* new_ref = callback_(ref, arg_, 0, kRootVMInternal);
+      Object* new_ref = callback_(ref, arg_);
       if (new_ref != ref) {
         // Use SetFieldObjectWithoutWriteBarrier to avoid card mark as an optimization which
         // reduces dirtied pages and improves performance.
-        obj->SetFieldObjectWithoutWriteBarrier(offset, new_ref, true);
+        if (Runtime::Current()->IsActiveTransaction()) {
+          obj->SetFieldObjectWithoutWriteBarrier<true>(offset, new_ref, true);
+        } else {
+          obj->SetFieldObjectWithoutWriteBarrier<false>(offset, new_ref, true);
+        }
       }
     }
   }
 
  private:
-  RootCallback* const callback_;
+  MarkObjectCallback* const callback_;
   void* arg_;
 };
 
 class ModUnionScanImageRootVisitor {
  public:
-  ModUnionScanImageRootVisitor(RootCallback* callback, void* arg)
+  ModUnionScanImageRootVisitor(MarkObjectCallback* callback, void* arg)
       : callback_(callback), arg_(arg) {}
 
   void operator()(Object* root) const
@@ -108,7 +112,7 @@
   }
 
  private:
-  RootCallback* const callback_;
+  MarkObjectCallback* const callback_;
   void* const arg_;
 };
 
@@ -261,7 +265,8 @@
   }
 }
 
-void ModUnionTableReferenceCache::UpdateAndMarkReferences(RootCallback* callback, void* arg) {
+void ModUnionTableReferenceCache::UpdateAndMarkReferences(MarkObjectCallback* callback,
+                                                          void* arg) {
   Heap* heap = GetHeap();
   CardTable* card_table = heap->GetCardTable();
 
@@ -296,7 +301,7 @@
     for (mirror::HeapReference<Object>* obj_ptr : ref.second) {
       Object* obj = obj_ptr->AsMirrorPtr();
       if (obj != nullptr) {
-        Object* new_obj = callback(obj, arg, 0, kRootVMInternal);
+        Object* new_obj = callback(obj, arg);
         // Avoid dirtying pages in the image unless necessary.
         if (new_obj != obj) {
           obj_ptr->Assign(new_obj);
@@ -318,7 +323,7 @@
 }
 
 // Mark all references to the alloc space(s).
-void ModUnionTableCardCache::UpdateAndMarkReferences(RootCallback* callback, void* arg) {
+void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectCallback* callback, void* arg) {
   CardTable* card_table = heap_->GetCardTable();
   ModUnionScanImageRootVisitor scan_visitor(callback, arg);
   SpaceBitmap* bitmap = space_->GetLiveBitmap();
diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h
index 7d5d8d2..2e22a11 100644
--- a/runtime/gc/accounting/mod_union_table.h
+++ b/runtime/gc/accounting/mod_union_table.h
@@ -69,7 +69,7 @@
   // Update the mod-union table using data stored by ClearCards. There may be multiple ClearCards
   // before a call to update, for example, back-to-back sticky GCs. Also mark references to other
   // spaces which are stored in the mod-union table.
-  virtual void UpdateAndMarkReferences(RootCallback* callback, void* arg) = 0;
+  virtual void UpdateAndMarkReferences(MarkObjectCallback* callback, void* arg) = 0;
 
   // Verification, sanity checks that we don't have clean cards which conflict with out cached data
   // for said cards. Exclusive lock is required since verify sometimes uses
@@ -106,7 +106,7 @@
   void ClearCards();
 
   // Update table based on cleared cards and mark all references to the other spaces.
-  void UpdateAndMarkReferences(RootCallback* callback, void* arg)
+  void UpdateAndMarkReferences(MarkObjectCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
@@ -142,7 +142,7 @@
   void ClearCards();
 
   // Mark all references to the alloc space(s).
-  void UpdateAndMarkReferences(RootCallback* callback, void* arg)
+  void UpdateAndMarkReferences(MarkObjectCallback* callback, void* arg)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index dbbc115..006c271 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -273,7 +273,7 @@
       TimingLogger::ScopedSplit split(name, &timings_);
       accounting::ModUnionTable* mod_union_table = heap_->FindModUnionTableFromSpace(space);
       CHECK(mod_union_table != nullptr);
-      mod_union_table->UpdateAndMarkReferences(MarkRootCallback, this);
+      mod_union_table->UpdateAndMarkReferences(MarkObjectCallback, this);
     }
   }
 }
@@ -532,20 +532,25 @@
   }
 }
 
-mirror::Object* MarkSweep::MarkRootParallelCallback(mirror::Object* root, void* arg,
-                                                    uint32_t /*thread_id*/, RootType /*root_type*/) {
+void MarkSweep::MarkRootParallelCallback(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
+                                         RootType /*root_type*/) {
   DCHECK(root != NULL);
   DCHECK(arg != NULL);
-  reinterpret_cast<MarkSweep*>(arg)->MarkObjectNonNullParallel(root);
-  return root;
+  reinterpret_cast<MarkSweep*>(arg)->MarkObjectNonNullParallel(*root);
 }
 
-Object* MarkSweep::MarkRootCallback(Object* root, void* arg, uint32_t /*thread_id*/,
-                                    RootType /*root_type*/) {
+void MarkSweep::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
+                                 RootType /*root_type*/) {
   DCHECK(root != nullptr);
   DCHECK(arg != nullptr);
-  reinterpret_cast<MarkSweep*>(arg)->MarkObjectNonNull(root);
-  return root;
+  reinterpret_cast<MarkSweep*>(arg)->MarkObjectNonNull(*root);
+}
+
+mirror::Object* MarkSweep::MarkObjectCallback(mirror::Object* object, void* arg) {
+  DCHECK(object != nullptr);
+  DCHECK(arg != nullptr);
+  reinterpret_cast<MarkSweep*>(arg)->MarkObjectNonNull(object);
+  return object;
 }
 
 void MarkSweep::VerifyRootCallback(const Object* root, void* arg, size_t vreg,
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 8bc0bb5..6a48cf7 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -180,13 +180,18 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static mirror::Object* MarkRootCallback(mirror::Object* root, void* arg, uint32_t thread_id,
-                                          RootType root_type)
+  static void MarkRootCallback(mirror::Object** root, void* arg, uint32_t thread_id,
+                               RootType root_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
-  static mirror::Object* MarkRootParallelCallback(mirror::Object* root, void* arg,
-                                                  uint32_t thread_id, RootType root_type);
+  static mirror::Object* MarkObjectCallback(mirror::Object* object, void* arg)
+        SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+
+  static void MarkRootParallelCallback(mirror::Object** root, void* arg, uint32_t thread_id,
+                                       RootType root_type)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Marks an object.
   void MarkObject(const mirror::Object* obj)
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index b1122b9..d64ec61 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -239,7 +239,7 @@
             space->IsZygoteSpace() ? "UpdateAndMarkZygoteModUnionTable" :
                                      "UpdateAndMarkImageModUnionTable",
                                      &timings_);
-        table->UpdateAndMarkReferences(MarkRootCallback, this);
+        table->UpdateAndMarkReferences(MarkObjectCallback, this);
       } else {
         // If a bump pointer space only collection, the non-moving
         // space is added to the immune space. But the non-moving
@@ -580,11 +580,17 @@
   return ret;
 }
 
-Object* SemiSpace::MarkRootCallback(Object* root, void* arg, uint32_t /*thread_id*/,
-                                    RootType /*root_type*/) {
+void SemiSpace::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
+                                 RootType /*root_type*/) {
   DCHECK(root != nullptr);
   DCHECK(arg != nullptr);
-  return reinterpret_cast<SemiSpace*>(arg)->MarkObject(root);
+  *root = reinterpret_cast<SemiSpace*>(arg)->MarkObject(*root);
+}
+
+Object* SemiSpace::MarkObjectCallback(Object* object, void* arg) {
+  DCHECK(object != nullptr);
+  DCHECK(arg != nullptr);
+  return reinterpret_cast<SemiSpace*>(arg)->MarkObject(object);
 }
 
 // Marks all objects in the root set.
@@ -662,7 +668,9 @@
       // Don't need to mark the card since we updating the object address and not changing the
       // actual objects its pointing to. Using SetFieldObjectWithoutWriteBarrier is better in this
       // case since it does not dirty cards and use additional memory.
-      obj->SetFieldObjectWithoutWriteBarrier(offset, new_address, false);
+      // Since we do not change the actual object, we can safely use non-transactional mode. Also
+      // disable check as we could run inside a transaction.
+      obj->SetFieldObjectWithoutWriteBarrier<false, false>(offset, new_address, false);
     }
   }, kMovingClasses);
   mirror::Class* klass = obj->GetClass();
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 89e2002..89fe326 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -142,10 +142,13 @@
   static void VisitObjectReferencesAndClass(mirror::Object* obj, const Visitor& visitor)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
-  static mirror::Object* MarkRootCallback(mirror::Object* root, void* arg, uint32_t /*tid*/,
-                                          RootType /*root_type*/)
+  static void MarkRootCallback(mirror::Object** root, void* arg, uint32_t /*tid*/,
+                               RootType /*root_type*/)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
+  static mirror::Object* MarkObjectCallback(mirror::Object* objecgt, void* arg)
+        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+
   static mirror::Object* RecursiveMarkObjectCallback(mirror::Object* root, void* arg)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
 
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index f1126ef..061828c 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1703,13 +1703,12 @@
   gc_complete_cond_->Broadcast(self);
 }
 
-static mirror::Object* RootMatchesObjectVisitor(mirror::Object* root, void* arg,
-                                                uint32_t /*thread_id*/, RootType /*root_type*/) {
+static void RootMatchesObjectVisitor(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
+                                     RootType /*root_type*/) {
   mirror::Object* obj = reinterpret_cast<mirror::Object*>(arg);
-  if (root == obj) {
+  if (*root == obj) {
     LOG(INFO) << "Object " << obj << " is a root";
   }
-  return root;
 }
 
 class ScanVisitor {
@@ -1831,11 +1830,10 @@
     return heap_->IsLiveObjectLocked(obj, true, false, true);
   }
 
-  static mirror::Object* VerifyRoots(mirror::Object* root, void* arg, uint32_t /*thread_id*/,
-                                     RootType /*root_type*/) {
+  static void VerifyRoots(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
+                          RootType /*root_type*/) {
     VerifyReferenceVisitor* visitor = reinterpret_cast<VerifyReferenceVisitor*>(arg);
-    (*visitor)(nullptr, root, MemberOffset(0), true);
-    return root;
+    (*visitor)(nullptr, *root, MemberOffset(0), true);
   }
 
  private:
@@ -2072,7 +2070,7 @@
   }
 }
 
-static mirror::Object* IdentityRootCallback(mirror::Object* obj, void*, uint32_t, RootType) {
+static mirror::Object* IdentityMarkObjectCallback(mirror::Object* obj, void*) {
   return obj;
 }
 
@@ -2111,7 +2109,7 @@
     ReaderMutexLock reader_lock(self, *Locks::heap_bitmap_lock_);
     for (const auto& table_pair : mod_union_tables_) {
       accounting::ModUnionTable* mod_union_table = table_pair.second;
-      mod_union_table->UpdateAndMarkReferences(IdentityRootCallback, nullptr);
+      mod_union_table->UpdateAndMarkReferences(IdentityMarkObjectCallback, nullptr);
       mod_union_table->Verify();
     }
     thread_list->ResumeAll();
@@ -2335,7 +2333,7 @@
 void Heap::SetReferenceReferent(mirror::Object* reference, mirror::Object* referent) {
   DCHECK(reference != NULL);
   DCHECK_NE(reference_referent_offset_.Uint32Value(), 0U);
-  reference->SetFieldObject(reference_referent_offset_, referent, true);
+  reference->SetFieldObject<false, false>(reference_referent_offset_, referent, true);
 }
 
 mirror::Object* Heap::GetReferenceReferent(mirror::Object* reference) {
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 8af2725..b02b8bb 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -50,7 +50,7 @@
       for (size_t j = 0; j < 2048; ++j) {
         mirror::String* string = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!");
         // SIRT operator -> deferences the SIRT before running the method.
-        array->Set(j, string);
+        array->Set<false>(j, string);
       }
     }
   }
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index fae4cac..203701f 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -49,12 +49,21 @@
   DCHECK_NE(pending_next_offset.Uint32Value(), 0U);
   if (IsEmpty()) {
     // 1 element cyclic queue, ie: Reference ref = ..; ref.pendingNext = ref;
-    ref->SetFieldObject(pending_next_offset, ref, false);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      ref->SetFieldObject<true>(pending_next_offset, ref, false);
+    } else {
+      ref->SetFieldObject<false>(pending_next_offset, ref, false);
+    }
     list_ = ref;
   } else {
     mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false);
-    ref->SetFieldObject(pending_next_offset, head, false);
-    list_->SetFieldObject(pending_next_offset, ref, false);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      ref->SetFieldObject<true>(pending_next_offset, head, false);
+      list_->SetFieldObject<true>(pending_next_offset, ref, false);
+    } else {
+      ref->SetFieldObject<false>(pending_next_offset, head, false);
+      list_->SetFieldObject<false>(pending_next_offset, ref, false);
+    }
   }
 }
 
@@ -71,10 +80,18 @@
     list_ = nullptr;
   } else {
     mirror::Object* next = head->GetFieldObject<mirror::Object>(pending_next_offset, false);
-    list_->SetFieldObject(pending_next_offset, next, false);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      list_->SetFieldObject<true>(pending_next_offset, next, false);
+    } else {
+      list_->SetFieldObject<false>(pending_next_offset, next, false);
+    }
     ref = head;
   }
-  ref->SetFieldObject(pending_next_offset, nullptr, false);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    ref->SetFieldObject<true>(pending_next_offset, nullptr, false);
+  } else {
+    ref->SetFieldObject<false>(pending_next_offset, nullptr, false);
+  }
   return ref;
 }
 
@@ -131,7 +148,11 @@
         // If the referent is non-null the reference must queuable.
         DCHECK(heap_->IsEnqueuable(ref));
         // Move the updated referent to the zombie field.
-        ref->SetFieldObject(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
+        if (Runtime::Current()->IsActiveTransaction()) {
+          ref->SetFieldObject<true>(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
+        } else {
+          ref->SetFieldObject<false>(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
+        }
         heap_->ClearReferenceReferent(ref);
         cleared_references.EnqueueReference(ref);
       } else if (referent != forward_address) {
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index ae03dd9..c5a8328 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -496,12 +496,12 @@
   }
 
  private:
-  static mirror::Object* RootVisitor(mirror::Object* obj, void* arg, uint32_t thread_id,
-                                     RootType root_type)
+  static void RootVisitor(mirror::Object** obj, void* arg, uint32_t thread_id, RootType root_type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(arg != NULL);
-    reinterpret_cast<Hprof*>(arg)->VisitRoot(obj, thread_id, root_type);
-    return obj;
+    DCHECK(arg != nullptr);
+    DCHECK(obj != nullptr);
+    DCHECK(*obj != nullptr);
+    reinterpret_cast<Hprof*>(arg)->VisitRoot(*obj, thread_id, root_type);
   }
 
   static void VisitObjectCallback(mirror::Object* obj, void* arg)
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 4a02d74..54c7b6e 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -312,7 +312,7 @@
 void IndirectReferenceTable::VisitRoots(RootCallback* callback, void* arg, uint32_t tid,
                                         RootType root_type) {
   for (auto ref : *this) {
-    *ref = callback(const_cast<mirror::Object*>(*ref), arg, tid, root_type);
+    callback(ref, arg, tid, root_type);
     DCHECK(*ref != nullptr);
   }
 }
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 5693747..660efe4 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -28,29 +28,28 @@
 namespace art {
 
 InternTable::InternTable()
-    : intern_table_lock_("InternTable lock"), is_dirty_(false), allow_new_interns_(true),
-      new_intern_condition_("New intern condition", intern_table_lock_) {
+    : is_dirty_(false), allow_new_interns_(true),
+      new_intern_condition_("New intern condition", *Locks::intern_table_lock_) {
 }
 
 size_t InternTable::Size() const {
-  MutexLock mu(Thread::Current(), intern_table_lock_);
+  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   return strong_interns_.size() + weak_interns_.size();
 }
 
 void InternTable::DumpForSigQuit(std::ostream& os) const {
-  MutexLock mu(Thread::Current(), intern_table_lock_);
+  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   os << "Intern table: " << strong_interns_.size() << " strong; "
      << weak_interns_.size() << " weak\n";
 }
 
 void InternTable::VisitRoots(RootCallback* callback, void* arg,
                              bool only_dirty, bool clean_dirty) {
-  MutexLock mu(Thread::Current(), intern_table_lock_);
+  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   if (!only_dirty || is_dirty_) {
     for (auto& strong_intern : strong_interns_) {
-      strong_intern.second =
-          down_cast<mirror::String*>(callback(strong_intern.second, arg, 0,
-                                              kRootInternedString));
+      callback(reinterpret_cast<mirror::Object**>(&strong_intern.second), arg, 0,
+               kRootInternedString);
       DCHECK(strong_intern.second != nullptr);
     }
     if (clean_dirty) {
@@ -61,7 +60,7 @@
 }
 
 mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t hash_code) {
-  intern_table_lock_.AssertHeld(Thread::Current());
+  Locks::intern_table_lock_->AssertHeld(Thread::Current());
   for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
     mirror::String* existing_string = it->second;
     if (existing_string->Equals(s)) {
@@ -71,15 +70,38 @@
   return NULL;
 }
 
+mirror::String* InternTable::InsertStrong(mirror::String* s, uint32_t hash_code) {
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsActiveTransaction()) {
+    runtime->RecordStrongStringInsertion(s, hash_code);
+  }
+  return Insert(strong_interns_, s, hash_code);
+}
+
+mirror::String* InternTable::InsertWeak(mirror::String* s, uint32_t hash_code) {
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsActiveTransaction()) {
+    runtime->RecordWeakStringInsertion(s, hash_code);
+  }
+  return Insert(weak_interns_, s, hash_code);
+}
+
 mirror::String* InternTable::Insert(Table& table, mirror::String* s, uint32_t hash_code) {
-  intern_table_lock_.AssertHeld(Thread::Current());
+  Locks::intern_table_lock_->AssertHeld(Thread::Current());
   table.insert(std::make_pair(hash_code, s));
   return s;
 }
 
-void InternTable::Remove(Table& table, const mirror::String* s,
-                         uint32_t hash_code) {
-  intern_table_lock_.AssertHeld(Thread::Current());
+void InternTable::RemoveWeak(mirror::String* s, uint32_t hash_code) {
+  Runtime* runtime = Runtime::Current();
+  if (runtime->IsActiveTransaction()) {
+    runtime->RecordWeakStringRemoval(s, hash_code);
+  }
+  Remove(weak_interns_, s, hash_code);
+}
+
+void InternTable::Remove(Table& table, mirror::String* s, uint32_t hash_code) {
+  Locks::intern_table_lock_->AssertHeld(Thread::Current());
   for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
     if (it->second == s) {
       table.erase(it);
@@ -88,6 +110,24 @@
   }
 }
 
+// Insert/remove methods used to undo changes made during an aborted transaction.
+mirror::String* InternTable::InsertStrongFromTransaction(mirror::String* s, uint32_t hash_code) {
+  DCHECK(!Runtime::Current()->IsActiveTransaction());
+  return InsertStrong(s, hash_code);
+}
+mirror::String* InternTable::InsertWeakFromTransaction(mirror::String* s, uint32_t hash_code) {
+  DCHECK(!Runtime::Current()->IsActiveTransaction());
+  return InsertWeak(s, hash_code);
+}
+void InternTable::RemoveStrongFromTransaction(mirror::String* s, uint32_t hash_code) {
+  DCHECK(!Runtime::Current()->IsActiveTransaction());
+  Remove(strong_interns_, s, hash_code);
+}
+void InternTable::RemoveWeakFromTransaction(mirror::String* s, uint32_t hash_code) {
+  DCHECK(!Runtime::Current()->IsActiveTransaction());
+  Remove(weak_interns_, s, hash_code);
+}
+
 static mirror::String* LookupStringFromImage(mirror::String* s)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
@@ -115,20 +155,20 @@
 
 void InternTable::AllowNewInterns() {
   Thread* self = Thread::Current();
-  MutexLock mu(self, intern_table_lock_);
+  MutexLock mu(self, *Locks::intern_table_lock_);
   allow_new_interns_ = true;
   new_intern_condition_.Broadcast(self);
 }
 
 void InternTable::DisallowNewInterns() {
   Thread* self = Thread::Current();
-  MutexLock mu(self, intern_table_lock_);
+  MutexLock mu(self, *Locks::intern_table_lock_);
   allow_new_interns_ = false;
 }
 
 mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) {
   Thread* self = Thread::Current();
-  MutexLock mu(self, intern_table_lock_);
+  MutexLock mu(self, *Locks::intern_table_lock_);
 
   DCHECK(s != NULL);
   uint32_t hash_code = s->GetHashCode();
@@ -150,20 +190,20 @@
     // Check the image for a match.
     mirror::String* image = LookupStringFromImage(s);
     if (image != NULL) {
-      return Insert(strong_interns_, image, hash_code);
+      return InsertStrong(image, hash_code);
     }
 
     // There is no match in the strong table, check the weak table.
     mirror::String* weak = Lookup(weak_interns_, s, hash_code);
     if (weak != NULL) {
       // A match was found in the weak table. Promote to the strong table.
-      Remove(weak_interns_, weak, hash_code);
-      return Insert(strong_interns_, weak, hash_code);
+      RemoveWeak(weak, hash_code);
+      return InsertStrong(weak, hash_code);
     }
 
     // No match in the strong table or the weak table. Insert into the strong
     // table.
-    return Insert(strong_interns_, s, hash_code);
+    return InsertStrong(s, hash_code);
   }
 
   // Check the strong table for a match.
@@ -174,7 +214,7 @@
   // Check the image for a match.
   mirror::String* image = LookupStringFromImage(s);
   if (image != NULL) {
-    return Insert(weak_interns_, image, hash_code);
+    return InsertWeak(image, hash_code);
   }
   // Check the weak table for a match.
   mirror::String* weak = Lookup(weak_interns_, s, hash_code);
@@ -182,7 +222,7 @@
     return weak;
   }
   // Insert into the weak table.
-  return Insert(weak_interns_, s, hash_code);
+  return InsertWeak(s, hash_code);
 }
 
 mirror::String* InternTable::InternStrong(int32_t utf16_length,
@@ -211,13 +251,13 @@
 }
 
 bool InternTable::ContainsWeak(mirror::String* s) {
-  MutexLock mu(Thread::Current(), intern_table_lock_);
+  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   const mirror::String* found = Lookup(weak_interns_, s, s->GetHashCode());
   return found == s;
 }
 
 void InternTable::SweepInternTableWeaks(IsMarkedCallback* callback, void* arg) {
-  MutexLock mu(Thread::Current(), intern_table_lock_);
+  MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   for (auto it = weak_interns_.begin(), end = weak_interns_.end(); it != end;) {
     mirror::Object* object = it->second;
     mirror::Object* new_object = callback(object, arg);
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 9f09fb9..cc48480 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_INTERN_TABLE_H_
 
 #include "base/mutex.h"
+#include "locks.h"
 #include "object_callbacks.h"
 
 #include <map>
@@ -26,6 +27,7 @@
 namespace mirror {
 class String;
 }  // namespace mirror
+class Transaction;
 
 /**
  * Used to intern strings.
@@ -72,19 +74,38 @@
   typedef std::multimap<int32_t, mirror::String*> Table;
 
   mirror::String* Insert(mirror::String* s, bool is_strong)
+      LOCKS_EXCLUDED(Locks::intern_table_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::String* Lookup(Table& table, mirror::String* s, uint32_t hash_code)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::String* Insert(Table& table, mirror::String* s, uint32_t hash_code);
-  void Remove(Table& table, const mirror::String* s, uint32_t hash_code);
+  mirror::String* InsertStrong(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  mirror::String* InsertWeak(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  mirror::String* Insert(Table& table, mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  void RemoveWeak(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  void Remove(Table& table, mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
 
-  mutable Mutex intern_table_lock_;
-  bool is_dirty_ GUARDED_BY(intern_table_lock_);
-  bool allow_new_interns_ GUARDED_BY(intern_table_lock_);
-  ConditionVariable new_intern_condition_ GUARDED_BY(intern_table_lock_);
-  Table strong_interns_ GUARDED_BY(intern_table_lock_);
-  Table weak_interns_ GUARDED_BY(intern_table_lock_);
+  // Transaction rollback access.
+  mirror::String* InsertStrongFromTransaction(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  mirror::String* InsertWeakFromTransaction(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  void RemoveStrongFromTransaction(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  void RemoveWeakFromTransaction(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  friend class Transaction;
+
+  bool is_dirty_ GUARDED_BY(Locks::intern_table_lock_);
+  bool allow_new_interns_ GUARDED_BY(Locks::intern_table_lock_);
+  ConditionVariable new_intern_condition_ GUARDED_BY(Locks::intern_table_lock_);
+  Table strong_interns_ GUARDED_BY(Locks::intern_table_lock_);
+  Table weak_interns_ GUARDED_BY(Locks::intern_table_lock_);
 };
 
 }  // namespace art
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index c6faf44..cb9e2e8 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -15,6 +15,7 @@
  */
 
 #include "interpreter_common.h"
+#include <limits>
 
 namespace art {
 namespace interpreter {
@@ -23,6 +24,10 @@
 static void UnstartedRuntimeJni(Thread* self, ArtMethod* method,
                                 Object* receiver, uint32_t* args, JValue* result)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  DCHECK(Runtime::Current()->IsActiveTransaction()) << "Calling native method "
+                                                    << PrettyMethod(method)
+                                                    << " in unstarted runtime should only happen"
+                                                    << " in a transaction";
   std::string name(PrettyMethod(method));
   if (name == "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") {
     result->SetL(NULL);
@@ -64,22 +69,23 @@
   } else if (name == "java.lang.Object java.lang.Throwable.nativeFillInStackTrace()") {
     ScopedObjectAccessUnchecked soa(self);
     result->SetL(soa.Decode<Object*>(self->CreateInternalStackTrace(soa)));
+  } else if (name == "int java.lang.System.identityHashCode(java.lang.Object)") {
+    mirror::Object* obj = reinterpret_cast<Object*>(args[0]);
+    result->SetI((obj != nullptr) ? obj->IdentityHashCode() : 0);
   } else if (name == "boolean java.nio.ByteOrder.isLittleEndian()") {
-    result->SetJ(JNI_TRUE);
+    result->SetZ(JNI_TRUE);
   } else if (name == "boolean sun.misc.Unsafe.compareAndSwapInt(java.lang.Object, long, int, int)") {
     Object* obj = reinterpret_cast<Object*>(args[0]);
     jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
     jint expectedValue = args[3];
     jint newValue = args[4];
-    byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
-    volatile int32_t* address = reinterpret_cast<volatile int32_t*>(raw_addr);
-    // Note: android_atomic_release_cas() returns 0 on success, not failure.
-    int r = android_atomic_release_cas(expectedValue, newValue, address);
-    result->SetZ(r == 0);
+    bool success = obj->CasField32<true>(MemberOffset(offset), expectedValue, newValue);
+    result->SetZ(success ? JNI_TRUE : JNI_FALSE);
   } else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
     Object* obj = reinterpret_cast<Object*>(args[0]);
+    jlong offset = (static_cast<uint64_t>(args[2]) << 32) | args[1];
     Object* newValue = reinterpret_cast<Object*>(args[3]);
-    obj->SetFieldObject(MemberOffset((static_cast<uint64_t>(args[2]) << 32) | args[1]), newValue, false);
+    obj->SetFieldObject<true>(MemberOffset(offset), newValue, false);
   } else if (name == "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") {
     mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
     Primitive::Type primitive_type = component->GetPrimitiveType();
@@ -89,7 +95,11 @@
     Primitive::Type primitive_type = component->GetPrimitiveType();
     result->SetI(Primitive::ComponentSize(primitive_type));
   } else {
-    LOG(FATAL) << "Attempt to invoke native method in non-started runtime: " << name;
+    // Throw an exception so we can abort the transaction and undo every change.
+    ThrowLocation throw_location;
+    self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;",
+                             "Attempt to invoke native method in non-started runtime: %s",
+                             name.c_str());
   }
 }
 
@@ -293,21 +303,38 @@
   DCHECK(!shadow_frame.GetMethod()->IsAbstract());
   DCHECK(!shadow_frame.GetMethod()->IsNative());
 
+  bool transaction_active = Runtime::Current()->IsActiveTransaction();
   if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) {
     // Enter the "without access check" interpreter.
     if (kInterpreterImplKind == kSwitchImpl) {
-      return ExecuteSwitchImpl<false>(self, mh, code_item, shadow_frame, result_register);
+      if (transaction_active) {
+        return ExecuteSwitchImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+      } else {
+        return ExecuteSwitchImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+      }
     } else {
       DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
-      return ExecuteGotoImpl<false>(self, mh, code_item, shadow_frame, result_register);
+      if (transaction_active) {
+        return ExecuteGotoImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+      } else {
+        return ExecuteGotoImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+      }
     }
   } else {
     // Enter the "with access check" interpreter.
     if (kInterpreterImplKind == kSwitchImpl) {
-      return ExecuteSwitchImpl<true>(self, mh, code_item, shadow_frame, result_register);
+      if (transaction_active) {
+        return ExecuteSwitchImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+      } else {
+        return ExecuteSwitchImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+      }
     } else {
       DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
-      return ExecuteGotoImpl<true>(self, mh, code_item, shadow_frame, result_register);
+      if (transaction_active) {
+        return ExecuteGotoImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+      } else {
+        return ExecuteGotoImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+      }
     }
   }
 }
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 0b959fb..e37fb61 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -15,6 +15,7 @@
  */
 
 #include "interpreter_common.h"
+#include "mirror/array-inl.h"
 
 namespace art {
 namespace interpreter {
@@ -161,7 +162,7 @@
   return !self->IsExceptionPending();
 }
 
-template <bool is_range, bool do_access_check>
+template <bool is_range, bool do_access_check, bool transaction_active>
 bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
                       Thread* self, JValue* result) {
   DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY ||
@@ -212,9 +213,9 @@
   for (int32_t i = 0; i < length; ++i) {
     size_t src_reg = is_range ? vregC + i : arg[i];
     if (is_primitive_int_component) {
-      newArray->AsIntArray()->SetWithoutChecks(i, shadow_frame.GetVReg(src_reg));
+      newArray->AsIntArray()->SetWithoutChecks<transaction_active>(i, shadow_frame.GetVReg(src_reg));
     } else {
-      newArray->AsObjectArray<Object>()->SetWithoutChecks(i, shadow_frame.GetVRegReference(src_reg));
+      newArray->AsObjectArray<Object>()->SetWithoutChecks<transaction_active>(i, shadow_frame.GetVRegReference(src_reg));
     }
   }
 
@@ -222,6 +223,50 @@
   return true;
 }
 
+// TODO fix thread analysis: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+template<typename T>
+static void RecordArrayElementsInTransactionImpl(mirror::PrimitiveArray<T>* array, int32_t count)
+    NO_THREAD_SAFETY_ANALYSIS {
+  Runtime* runtime = Runtime::Current();
+  for (int32_t i = 0; i < count; ++i) {
+    runtime->RecordWriteArray(array, i, array->GetWithoutChecks(i));
+  }
+}
+
+void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  DCHECK(Runtime::Current()->IsActiveTransaction());
+  DCHECK(array != nullptr);
+  DCHECK_LE(count, array->GetLength());
+  Primitive::Type primitive_component_type = array->GetClass()->GetComponentType()->GetPrimitiveType();
+  switch (primitive_component_type) {
+    case Primitive::kPrimBoolean:
+      RecordArrayElementsInTransactionImpl(array->AsBooleanArray(), count);
+      break;
+    case Primitive::kPrimByte:
+      RecordArrayElementsInTransactionImpl(array->AsByteArray(), count);
+      break;
+    case Primitive::kPrimChar:
+      RecordArrayElementsInTransactionImpl(array->AsCharArray(), count);
+      break;
+    case Primitive::kPrimShort:
+      RecordArrayElementsInTransactionImpl(array->AsShortArray(), count);
+      break;
+    case Primitive::kPrimInt:
+    case Primitive::kPrimFloat:
+      RecordArrayElementsInTransactionImpl(array->AsIntArray(), count);
+      break;
+    case Primitive::kPrimLong:
+    case Primitive::kPrimDouble:
+      RecordArrayElementsInTransactionImpl(array->AsLongArray(), count);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported primitive type " << primitive_component_type
+                 << " in fill-array-data";
+      break;
+  }
+}
+
 static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
                                    const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
                                    JValue* result, size_t arg_offset) {
@@ -341,15 +386,19 @@
 #undef EXPLICIT_DO_CALL_TEMPLATE_DECL
 
 // Explicit DoFilledNewArray template function declarations.
-#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check)                \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                \
-  bool DoFilledNewArray<_is_range_, _check>(const Instruction* inst,                  \
-                                                     const ShadowFrame& shadow_frame, \
-                                                     Thread* self, JValue* result)
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false);
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true);
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false);
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true);
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active)       \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                            \
+  bool DoFilledNewArray<_is_range_, _check, _transaction_active>(const Instruction* inst,         \
+                                                                 const ShadowFrame& shadow_frame, \
+                                                                 Thread* self, JValue* result)
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active)       \
+  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false, _transaction_active);  \
+  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true, _transaction_active);   \
+  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false, _transaction_active);   \
+  EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true, _transaction_active)
+EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(false);
+EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(true);
+#undef EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL
 #undef EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL
 
 }  // namespace interpreter
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 768ca33..a03e420 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -65,12 +65,12 @@
 
 // External references to both interpreter implementations.
 
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
 extern JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh,
                                 const DexFile::CodeItem* code_item,
                                 ShadowFrame& shadow_frame, JValue result_register);
 
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
 extern JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh,
                               const DexFile::CodeItem* code_item,
                               ShadowFrame& shadow_frame, JValue result_register);
@@ -83,6 +83,9 @@
   ref->MonitorExit(self);
 }
 
+void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
 // Invokes the given method. This is part of the invocation support and is used by DoInvoke and
 // DoInvokeVirtualQuick functions.
 // Returns true on success, otherwise throws an exception and returns false.
@@ -228,7 +231,7 @@
 
 // Handles iput-XXX and sput-XXX instructions.
 // Returns true on success, otherwise throws an exception and returns false.
-template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, bool transaction_active>
 static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
                               const Instruction* inst, uint16_t inst_data) {
   bool do_assignability_check = do_access_check;
@@ -254,22 +257,22 @@
   uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
   switch (field_type) {
     case Primitive::kPrimBoolean:
-      f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
+      f->SetBoolean<transaction_active>(obj, shadow_frame.GetVReg(vregA));
       break;
     case Primitive::kPrimByte:
-      f->SetByte(obj, shadow_frame.GetVReg(vregA));
+      f->SetByte<transaction_active>(obj, shadow_frame.GetVReg(vregA));
       break;
     case Primitive::kPrimChar:
-      f->SetChar(obj, shadow_frame.GetVReg(vregA));
+      f->SetChar<transaction_active>(obj, shadow_frame.GetVReg(vregA));
       break;
     case Primitive::kPrimShort:
-      f->SetShort(obj, shadow_frame.GetVReg(vregA));
+      f->SetShort<transaction_active>(obj, shadow_frame.GetVReg(vregA));
       break;
     case Primitive::kPrimInt:
-      f->SetInt(obj, shadow_frame.GetVReg(vregA));
+      f->SetInt<transaction_active>(obj, shadow_frame.GetVReg(vregA));
       break;
     case Primitive::kPrimLong:
-      f->SetLong(obj, shadow_frame.GetVRegLong(vregA));
+      f->SetLong<transaction_active>(obj, shadow_frame.GetVRegLong(vregA));
       break;
     case Primitive::kPrimNot: {
       Object* reg = shadow_frame.GetVRegReference(vregA);
@@ -286,7 +289,7 @@
           return false;
         }
       }
-      f->SetObj(obj, reg);
+      f->SetObj<transaction_active>(obj, reg);
       break;
     }
     default:
@@ -297,7 +300,7 @@
 
 // Handles iput-quick, iput-wide-quick and iput-object-quick instructions.
 // Returns true on success, otherwise throws an exception and returns false.
-template<Primitive::Type field_type>
+template<Primitive::Type field_type, bool transaction_active>
 static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
   Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
   if (UNLIKELY(obj == nullptr)) {
@@ -311,13 +314,15 @@
   const uint32_t vregA = inst->VRegA_22c(inst_data);
   switch (field_type) {
     case Primitive::kPrimInt:
-      obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
+      obj->SetField32<transaction_active>(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
       break;
     case Primitive::kPrimLong:
-      obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
+      obj->SetField64<transaction_active>(field_offset, shadow_frame.GetVRegLong(vregA),
+                                          is_volatile);
       break;
     case Primitive::kPrimNot:
-      obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
+      obj->SetFieldObject<transaction_active>(field_offset, shadow_frame.GetVRegReference(vregA),
+                                              is_volatile);
       break;
     default:
       LOG(FATAL) << "Unreachable: " << field_type;
@@ -416,7 +421,7 @@
 
 // Handles filled-new-array and filled-new-array-range instructions.
 // Returns true on success, otherwise throws an exception and returns false.
-template <bool is_range, bool do_access_check>
+template <bool is_range, bool do_access_check, bool transaction_active>
 bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
                       Thread* self, JValue* result);
 
@@ -604,14 +609,16 @@
 #undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
 
 // Explicitly instantiate all DoFieldPut functions.
-#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check)                      \
+#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check, _transaction_active)                      \
   template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                                 \
-  bool DoFieldPut<_find_type, _field_type, _do_check>(Thread* self, const ShadowFrame& shadow_frame, \
-                                                      const Instruction* inst, uint16_t inst_data)
+  bool DoFieldPut<_find_type, _field_type, _do_check, _transaction_active>(Thread* self, const ShadowFrame& shadow_frame, \
+                                                                           const Instruction* inst, uint16_t inst_data)
 
 #define EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(_find_type, _field_type)  \
-    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false);  \
-    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true);
+    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, false);  \
+    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, false);  \
+    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, true);  \
+    EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, true);
 
 // iput-XXX
 EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimBoolean);
@@ -657,14 +664,20 @@
 #undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
 
 // Explicitly instantiate all DoIPutQuick functions.
-#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type)                                  \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \
-  bool DoIPutQuick<_field_type>(const ShadowFrame& shadow_frame, const Instruction* inst,  \
-                                uint16_t inst_data)
+#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, _transaction_active)        \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                  \
+  bool DoIPutQuick<_field_type, _transaction_active>(const ShadowFrame& shadow_frame, \
+                                                     const Instruction* inst,         \
+                                                     uint16_t inst_data)
 
-EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimInt);    // iget-quick.
-EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimLong);   // iget-wide-quick.
-EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimNot);    // iget-object-quick.
+#define EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(_field_type)   \
+  EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, false);     \
+  EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, true);
+
+EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimInt);    // iget-quick.
+EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimLong);   // iget-wide-quick.
+EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimNot);    // iget-object-quick.
+#undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL
 #undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL
 
 }  // namespace interpreter
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index e8504b7..d0bb001 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -109,7 +109,7 @@
  * ---------------------+---------------+
  *
  */
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
 JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                        ShadowFrame& shadow_frame, JValue result_register) {
   // Define handler tables:
@@ -536,15 +536,17 @@
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY) {
-    bool success = DoFilledNewArray<false, do_access_check>(inst, shadow_frame,
-                                                            self, &result_register);
+    bool success =
+        DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame,
+                                                                     self, &result_register);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY_RANGE) {
-    bool success = DoFilledNewArray<true, do_access_check>(inst, shadow_frame,
-                                                           self, &result_register);
+    bool success =
+        DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
+                                                                    self, &result_register);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
   }
   HANDLE_INSTRUCTION_END();
@@ -567,6 +569,9 @@
                                  array->GetLength(), payload->element_count);
         HANDLE_PENDING_EXCEPTION();
       } else {
+        if (transaction_active) {
+          RecordArrayElementsInTransaction(array, payload->element_count);
+        }
         uint32_t size_in_bytes = payload->element_count * payload->element_width;
         memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
         ADVANCE(3);
@@ -1060,7 +1065,7 @@
       int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
       BooleanArray* array = a->AsBooleanArray();
       if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks(index, val);
+        array->SetWithoutChecks<transaction_active>(index, val);
         ADVANCE(2);
       } else {
         HANDLE_PENDING_EXCEPTION();
@@ -1079,7 +1084,7 @@
       int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
       ByteArray* array = a->AsByteArray();
       if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks(index, val);
+        array->SetWithoutChecks<transaction_active>(index, val);
         ADVANCE(2);
       } else {
         HANDLE_PENDING_EXCEPTION();
@@ -1098,7 +1103,7 @@
       int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
       CharArray* array = a->AsCharArray();
       if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks(index, val);
+        array->SetWithoutChecks<transaction_active>(index, val);
         ADVANCE(2);
       } else {
         HANDLE_PENDING_EXCEPTION();
@@ -1117,7 +1122,7 @@
       int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
       ShortArray* array = a->AsShortArray();
       if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks(index, val);
+        array->SetWithoutChecks<transaction_active>(index, val);
         ADVANCE(2);
       } else {
         HANDLE_PENDING_EXCEPTION();
@@ -1136,7 +1141,7 @@
       int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
       IntArray* array = a->AsIntArray();
       if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks(index, val);
+        array->SetWithoutChecks<transaction_active>(index, val);
         ADVANCE(2);
       } else {
         HANDLE_PENDING_EXCEPTION();
@@ -1155,7 +1160,7 @@
       int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
       LongArray* array = a->AsLongArray();
       if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks(index, val);
+        array->SetWithoutChecks<transaction_active>(index, val);
         ADVANCE(2);
       } else {
         HANDLE_PENDING_EXCEPTION();
@@ -1174,7 +1179,7 @@
       Object* val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
       ObjectArray<Object>* array = a->AsObjectArray<Object>();
       if (LIKELY(array->CheckIsValidIndex(index) && array->CheckAssignable(val))) {
-        array->SetWithoutChecks(index, val);
+        array->SetWithoutChecks<transaction_active>(index, val);
         ADVANCE(2);
       } else {
         HANDLE_PENDING_EXCEPTION();
@@ -1286,103 +1291,103 @@
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_BOOLEAN) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_BYTE) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_CHAR) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_SHORT) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_WIDE) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_OBJECT) {
-    bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
+    bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_WIDE_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
+    bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(IPUT_OBJECT_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
+    bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SPUT_BOOLEAN) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SPUT_BYTE) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SPUT_CHAR) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SPUT_SHORT) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SPUT) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SPUT_WIDE) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
 
   HANDLE_INSTRUCTION_START(SPUT_OBJECT) {
-    bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+    bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
     POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
   }
   HANDLE_INSTRUCTION_END();
@@ -2390,13 +2395,21 @@
 
 // Explicit definitions of ExecuteGotoImpl.
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<true>(Thread* self, MethodHelper& mh,
-                             const DexFile::CodeItem* code_item,
-                             ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
+                                    const DexFile::CodeItem* code_item,
+                                    ShadowFrame& shadow_frame, JValue result_register);
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<false>(Thread* self, MethodHelper& mh,
-                              const DexFile::CodeItem* code_item,
-                              ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
+                                     const DexFile::CodeItem* code_item,
+                                     ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
+                                    const DexFile::CodeItem* code_item,
+                                    ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
+                                     const DexFile::CodeItem* code_item,
+                                     ShadowFrame& shadow_frame, JValue result_register);
 
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index e5d15b1..abee1db 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -50,7 +50,7 @@
 // Code to run before each dex instruction.
 #define PREAMBLE()
 
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
 JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
                                 ShadowFrame& shadow_frame, JValue result_register) {
   bool do_assignability_check = do_access_check;
@@ -449,15 +449,17 @@
       }
       case Instruction::FILLED_NEW_ARRAY: {
         PREAMBLE();
-        bool success = DoFilledNewArray<false, do_access_check>(inst, shadow_frame,
-                                                                self, &result_register);
+        bool success =
+            DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame, self,
+                                                                         &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
         break;
       }
       case Instruction::FILLED_NEW_ARRAY_RANGE: {
         PREAMBLE();
-        bool success = DoFilledNewArray<true, do_access_check>(inst, shadow_frame,
-                                                               self, &result_register);
+        bool success =
+            DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
+                                                                        self, &result_register);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
         break;
       }
@@ -482,6 +484,9 @@
           HANDLE_PENDING_EXCEPTION();
           break;
         }
+        if (transaction_active) {
+          RecordArrayElementsInTransaction(array, payload->element_count);
+        }
         uint32_t size_in_bytes = payload->element_count * payload->element_width;
         memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
         inst = inst->Next_3xx();
@@ -958,7 +963,7 @@
         int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
         BooleanArray* array = a->AsBooleanArray();
         if (LIKELY(array->CheckIsValidIndex(index))) {
-          array->SetWithoutChecks(index, val);
+          array->SetWithoutChecks<transaction_active>(index, val);
           inst = inst->Next_2xx();
         } else {
           HANDLE_PENDING_EXCEPTION();
@@ -977,7 +982,7 @@
         int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
         ByteArray* array = a->AsByteArray();
         if (LIKELY(array->CheckIsValidIndex(index))) {
-          array->SetWithoutChecks(index, val);
+          array->SetWithoutChecks<transaction_active>(index, val);
           inst = inst->Next_2xx();
         } else {
           HANDLE_PENDING_EXCEPTION();
@@ -996,7 +1001,7 @@
         int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
         CharArray* array = a->AsCharArray();
         if (LIKELY(array->CheckIsValidIndex(index))) {
-          array->SetWithoutChecks(index, val);
+          array->SetWithoutChecks<transaction_active>(index, val);
           inst = inst->Next_2xx();
         } else {
           HANDLE_PENDING_EXCEPTION();
@@ -1015,7 +1020,7 @@
         int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
         ShortArray* array = a->AsShortArray();
         if (LIKELY(array->CheckIsValidIndex(index))) {
-          array->SetWithoutChecks(index, val);
+          array->SetWithoutChecks<transaction_active>(index, val);
           inst = inst->Next_2xx();
         } else {
           HANDLE_PENDING_EXCEPTION();
@@ -1034,7 +1039,7 @@
         int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
         IntArray* array = a->AsIntArray();
         if (LIKELY(array->CheckIsValidIndex(index))) {
-          array->SetWithoutChecks(index, val);
+          array->SetWithoutChecks<transaction_active>(index, val);
           inst = inst->Next_2xx();
         } else {
           HANDLE_PENDING_EXCEPTION();
@@ -1053,7 +1058,7 @@
         int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
         LongArray* array = a->AsLongArray();
         if (LIKELY(array->CheckIsValidIndex(index))) {
-          array->SetWithoutChecks(index, val);
+          array->SetWithoutChecks<transaction_active>(index, val);
           inst = inst->Next_2xx();
         } else {
           HANDLE_PENDING_EXCEPTION();
@@ -1072,7 +1077,7 @@
         Object* val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
         ObjectArray<Object>* array = a->AsObjectArray<Object>();
         if (LIKELY(array->CheckIsValidIndex(index) && array->CheckAssignable(val))) {
-          array->SetWithoutChecks(index, val);
+          array->SetWithoutChecks<transaction_active>(index, val);
           inst = inst->Next_2xx();
         } else {
           HANDLE_PENDING_EXCEPTION();
@@ -1183,103 +1188,103 @@
       }
       case Instruction::IPUT_BOOLEAN: {
         PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_BYTE: {
         PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_CHAR: {
         PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_SHORT: {
         PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT: {
         PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_WIDE: {
         PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_OBJECT: {
         PREAMBLE();
-        bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_QUICK: {
         PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
+        bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_WIDE_QUICK: {
         PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
+        bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::IPUT_OBJECT_QUICK: {
         PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
+        bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::SPUT_BOOLEAN: {
         PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::SPUT_BYTE: {
         PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::SPUT_CHAR: {
         PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::SPUT_SHORT: {
         PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::SPUT: {
         PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::SPUT_WIDE: {
         PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
       case Instruction::SPUT_OBJECT: {
         PREAMBLE();
-        bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+        bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
         POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
         break;
       }
@@ -2137,13 +2142,21 @@
 
 // Explicit definitions of ExecuteSwitchImpl.
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<true>(Thread* self, MethodHelper& mh,
-                               const DexFile::CodeItem* code_item,
-                               ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteSwitchImpl<true, false>(Thread* self, MethodHelper& mh,
+                                      const DexFile::CodeItem* code_item,
+                                      ShadowFrame& shadow_frame, JValue result_register);
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<false>(Thread* self, MethodHelper& mh,
-                                const DexFile::CodeItem* code_item,
-                                ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteSwitchImpl<false, false>(Thread* self, MethodHelper& mh,
+                                       const DexFile::CodeItem* code_item,
+                                       ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteSwitchImpl<true, true>(Thread* self, MethodHelper& mh,
+                                     const DexFile::CodeItem* code_item,
+                                     ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteSwitchImpl<false, true>(Thread* self, MethodHelper& mh,
+                                      const DexFile::CodeItem* code_item,
+                                      ShadowFrame& shadow_frame, JValue result_register);
 
 }  // namespace interpreter
 }  // namespace art
diff --git a/runtime/jdwp/jdwp.h b/runtime/jdwp/jdwp.h
index 334dca4..e45cb6e 100644
--- a/runtime/jdwp/jdwp.h
+++ b/runtime/jdwp/jdwp.h
@@ -295,6 +295,10 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void SendBufferedRequest(uint32_t type, const std::vector<iovec>& iov);
 
+  void StartProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
+  void EndProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
+  void WaitForProcessingRequest() LOCKS_EXCLUDED(process_request_lock_);
+
  public:  // TODO: fix privacy
   const JdwpOptions* options_;
 
@@ -340,6 +344,12 @@
   ConditionVariable event_thread_cond_ GUARDED_BY(event_thread_lock_);
   ObjectId event_thread_id_;
 
+  // Used to synchronize request processing and event sending (to avoid sending an event before
+  // sending the reply of a command being processed).
+  Mutex process_request_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  ConditionVariable process_request_cond_ GUARDED_BY(process_request_lock_);
+  bool processing_request_ GUARDED_BY(process_request_lock_);
+
   bool ddm_is_active_;
 
   bool should_exit_;
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index e372c26..427350e 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -576,14 +576,6 @@
     Dbg::ExecuteMethod(pReq);
 
     pReq->error = ERR_NONE;
-
-    /* clear this before signaling */
-    pReq->invoke_needed = false;
-
-    VLOG(jdwp) << "invoke complete, signaling and self-suspending";
-    Thread* self = Thread::Current();
-    MutexLock mu(self, pReq->lock);
-    pReq->cond.Signal(self);
   }
 }
 
@@ -697,6 +689,11 @@
   Set1(buf+9, kJdwpEventCommandSet);
   Set1(buf+10, kJdwpCompositeCommand);
 
+  // Prevents from interleaving commands and events. Otherwise we could end up in sending an event
+  // before sending the reply of the command being processed and would lead to bad synchronization
+  // between the debugger and the debuggee.
+  WaitForProcessingRequest();
+
   SendRequest(pReq);
 
   expandBufFree(pReq);
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index a514e69..0ff78d0 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -1747,6 +1747,44 @@
   self->TransitionFromRunnableToSuspended(old_state);
 }
 
+/*
+ * Indicates a request is about to be processed. If a thread wants to send an event in the meantime,
+ * it will need to wait until we processed this request (see EndProcessingRequest).
+ */
+void JdwpState::StartProcessingRequest() {
+  Thread* self = Thread::Current();
+  CHECK_EQ(self, GetDebugThread()) << "Requests are only processed by debug thread";
+  MutexLock mu(self, process_request_lock_);
+  CHECK_EQ(processing_request_, false);
+  processing_request_ = true;
+}
+
+/*
+ * Indicates a request has been processed (and we sent its reply). All threads waiting for us (see
+ * WaitForProcessingRequest) are waken up so they can send events again.
+ */
+void JdwpState::EndProcessingRequest() {
+  Thread* self = Thread::Current();
+  CHECK_EQ(self, GetDebugThread()) << "Requests are only processed by debug thread";
+  MutexLock mu(self, process_request_lock_);
+  CHECK_EQ(processing_request_, true);
+  processing_request_ = false;
+  process_request_cond_.Broadcast(self);
+}
+
+/*
+ * Waits for any request being processed so we do not send an event in the meantime.
+ */
+void JdwpState::WaitForProcessingRequest() {
+  Thread* self = Thread::Current();
+  CHECK_NE(self, GetDebugThread()) << "Events should not be posted by debug thread";
+  MutexLock mu(self, process_request_lock_);
+  while (processing_request_) {
+    process_request_cond_.Wait(self);
+  }
+  CHECK_EQ(processing_request_, false);
+}
+
 }  // namespace JDWP
 
 }  // namespace art
diff --git a/runtime/jdwp/jdwp_main.cc b/runtime/jdwp/jdwp_main.cc
index 928f53d..ba49c45 100644
--- a/runtime/jdwp/jdwp_main.cc
+++ b/runtime/jdwp/jdwp_main.cc
@@ -218,6 +218,9 @@
       event_thread_lock_("JDWP event thread lock"),
       event_thread_cond_("JDWP event thread condition variable", event_thread_lock_),
       event_thread_id_(0),
+      process_request_lock_("JDWP process request lock"),
+      process_request_cond_("JDWP process request condition variable", process_request_lock_),
+      processing_request_(false),
       ddm_is_active_(false),
       should_exit_(false),
       exit_status_(0) {
@@ -383,9 +386,12 @@
   JdwpNetStateBase* netStateBase = reinterpret_cast<JdwpNetStateBase*>(netState);
   JDWP::Request request(netStateBase->input_buffer_, netStateBase->input_count_);
 
+  StartProcessingRequest();
   ExpandBuf* pReply = expandBufAlloc();
   ProcessRequest(request, pReply);
   ssize_t cc = netStateBase->WritePacket(pReply);
+  EndProcessingRequest();
+
   if (cc != (ssize_t) expandBufGetLength(pReply)) {
     PLOG(ERROR) << "Failed sending reply to debugger";
     expandBufFree(pReply);
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 94ae89e..362df8c 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -50,24 +50,6 @@
 #include "UniquePtr.h"
 #include "well_known_classes.h"
 
-using ::art::mirror::ArtField;
-using ::art::mirror::ArtMethod;
-using ::art::mirror::Array;
-using ::art::mirror::BooleanArray;
-using ::art::mirror::ByteArray;
-using ::art::mirror::CharArray;
-using ::art::mirror::Class;
-using ::art::mirror::ClassLoader;
-using ::art::mirror::DoubleArray;
-using ::art::mirror::FloatArray;
-using ::art::mirror::IntArray;
-using ::art::mirror::LongArray;
-using ::art::mirror::Object;
-using ::art::mirror::ObjectArray;
-using ::art::mirror::ShortArray;
-using ::art::mirror::String;
-using ::art::mirror::Throwable;
-
 namespace art {
 
 static const size_t kMonitorsInitial = 32;  // Arbitrary.
@@ -85,7 +67,7 @@
 static const size_t kWeakGlobalsInitial = 16;  // Arbitrary.
 static const size_t kWeakGlobalsMax = 51200;  // Arbitrary sanity check. (Must fit in 16 bits.)
 
-static jweak AddWeakGlobalReference(ScopedObjectAccess& soa, Object* obj)
+static jweak AddWeakGlobalReference(ScopedObjectAccess& soa, mirror::Object* obj)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return soa.Vm()->AddWeakGlobalReference(soa.Self(), obj);
 }
@@ -95,11 +77,10 @@
   return version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && version != JNI_VERSION_1_6;
 }
 
-static void CheckMethodArguments(ArtMethod* m, uint32_t* args)
+static void CheckMethodArguments(mirror::ArtMethod* m, uint32_t* args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  MethodHelper mh(m);
-  const DexFile::TypeList* params = mh.GetParameterTypeList();
-  if (params == NULL) {
+  const DexFile::TypeList* params = MethodHelper(m).GetParameterTypeList();
+  if (params == nullptr) {
     return;  // No arguments so nothing to check.
   }
   uint32_t offset = 0;
@@ -110,19 +91,19 @@
   }
   for (uint32_t i = 0; i < num_params; i++) {
     uint16_t type_idx = params->GetTypeItem(i).type_idx_;
-    Class* param_type = mh.GetClassFromTypeIdx(type_idx);
-    if (param_type == NULL) {
+    mirror::Class* param_type = MethodHelper(m).GetClassFromTypeIdx(type_idx);
+    if (param_type == nullptr) {
       Thread* self = Thread::Current();
       CHECK(self->IsExceptionPending());
       LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
-          << mh.GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
-          << self->GetException(NULL)->Dump();
+          << MethodHelper(m).GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
+          << self->GetException(nullptr)->Dump();
       self->ClearException();
       ++error_count;
     } else if (!param_type->IsPrimitive()) {
       // TODO: check primitives are in range.
-      Object* argument = reinterpret_cast<Object*>(args[i + offset]);
-      if (argument != NULL && !argument->InstanceOf(param_type)) {
+      mirror::Object* argument = reinterpret_cast<mirror::Object*>(args[i + offset]);
+      if (argument != nullptr && !argument->InstanceOf(param_type)) {
         LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
                    << PrettyTypeOf(argument) << " as argument " << (i + 1) << " to " << PrettyMethod(m);
         ++error_count;
@@ -134,11 +115,11 @@
   if (error_count > 0) {
     // TODO: pass the JNI function name (such as "CallVoidMethodV") through so we can call JniAbort
     // with an argument.
-    JniAbortF(NULL, "bad arguments passed to %s (see above for details)", PrettyMethod(m).c_str());
+    JniAbortF(nullptr, "bad arguments passed to %s (see above for details)", PrettyMethod(m).c_str());
   }
 }
 
-void InvokeWithArgArray(const ScopedObjectAccess& soa, ArtMethod* method,
+void InvokeWithArgArray(const ScopedObjectAccess& soa, mirror::ArtMethod* method,
                         ArgArray* arg_array, JValue* result, const char* shorty)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   uint32_t* args = arg_array->GetArray();
@@ -151,8 +132,8 @@
 static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj,
                                 jmethodID mid, va_list args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ArtMethod* method = soa.DecodeMethod(mid);
-  Object* receiver = method->IsStatic() ? NULL : soa.Decode<Object*>(obj);
+  mirror::ArtMethod* method = soa.DecodeMethod(mid);
+  mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
   MethodHelper mh(method);
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -161,7 +142,7 @@
   return result;
 }
 
-static ArtMethod* FindVirtualMethod(Object* receiver, ArtMethod* method)
+static mirror::ArtMethod* FindVirtualMethod(mirror::Object* receiver, mirror::ArtMethod* method)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method);
 }
@@ -169,8 +150,8 @@
 static JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa,
                                                   jobject obj, jmethodID mid, jvalue* args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Object* receiver = soa.Decode<Object*>(obj);
-  ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+  mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+  mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
   MethodHelper mh(method);
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -182,8 +163,8 @@
 static JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa,
                                                   jobject obj, jmethodID mid, va_list args)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Object* receiver = soa.Decode<Object*>(obj);
-  ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+  mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+  mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
   MethodHelper mh(method);
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -216,7 +197,7 @@
   return result;
 }
 
-static void ThrowNoSuchMethodError(ScopedObjectAccess& soa, Class* c,
+static void ThrowNoSuchMethodError(ScopedObjectAccess& soa, mirror::Class* c,
                                    const char* name, const char* sig, const char* kind)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
@@ -240,68 +221,66 @@
 static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
                               const char* name, const char* sig, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
+  mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class));
   if (c == nullptr) {
     return nullptr;
   }
-
-  ArtMethod* method = NULL;
+  mirror::ArtMethod* method = nullptr;
   if (is_static) {
     method = c->FindDirectMethod(name, sig);
   } else {
     method = c->FindVirtualMethod(name, sig);
-    if (method == NULL) {
+    if (method == nullptr) {
       // No virtual method matching the signature.  Search declared
       // private methods and constructors.
       method = c->FindDeclaredDirectMethod(name, sig);
     }
   }
-
-  if (method == NULL || method->IsStatic() != is_static) {
+  if (method == nullptr || method->IsStatic() != is_static) {
     ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
-    return NULL;
+    return nullptr;
   }
-
   return soa.EncodeMethod(method);
 }
 
-static ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
+static mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  ArtMethod* method = soa.Self()->GetCurrentMethod(NULL);
+  mirror::ArtMethod* method = soa.Self()->GetCurrentMethod(nullptr);
   // If we are running Runtime.nativeLoad, use the overriding ClassLoader it set.
   if (method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
     return soa.Self()->GetClassLoaderOverride();
   }
   // If we have a method, use its ClassLoader for context.
-  if (method != NULL) {
+  if (method != nullptr) {
     return method->GetDeclaringClass()->GetClassLoader();
   }
   // We don't have a method, so try to use the system ClassLoader.
-  ClassLoader* class_loader = soa.Decode<ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
-  if (class_loader != NULL) {
+  mirror::ClassLoader* class_loader =
+      soa.Decode<mirror::ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
+  if (class_loader != nullptr) {
     return class_loader;
   }
   // See if the override ClassLoader is set for gtests.
   class_loader = soa.Self()->GetClassLoaderOverride();
-  if (class_loader != NULL) {
+  if (class_loader != nullptr) {
     // If so, CommonTest should have set UseCompileTimeClassPath.
     CHECK(Runtime::Current()->UseCompileTimeClassPath());
     return class_loader;
   }
   // Use the BOOTCLASSPATH.
-  return NULL;
+  return nullptr;
 }
 
 static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, const char* name,
                             const char* sig, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
-  if (c == nullptr) {
+  SirtRef<mirror::Class> c(soa.Self(), EnsureInitialized(soa.Self(),
+                                                         soa.Decode<mirror::Class*>(jni_class)));
+  if (c.get() == nullptr) {
     return nullptr;
   }
-
-  ArtField* field = NULL;
-  Class* field_type;
+  mirror::ArtField* field = nullptr;
+  mirror::Class* field_type;
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   if (sig[1] != '\0') {
     SirtRef<mirror::ClassLoader> class_loader(soa.Self(), c->GetClassLoader());
@@ -309,49 +288,49 @@
   } else {
     field_type = class_linker->FindPrimitiveClass(*sig);
   }
-  if (field_type == NULL) {
+  if (field_type == nullptr) {
     // Failed to find type from the signature of the field.
     DCHECK(soa.Self()->IsExceptionPending());
     ThrowLocation throw_location;
-    SirtRef<Throwable> cause(soa.Self(), soa.Self()->GetException(&throw_location));
+    SirtRef<mirror::Throwable> cause(soa.Self(), soa.Self()->GetException(&throw_location));
     soa.Self()->ClearException();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
                                    "no type \"%s\" found and so no field \"%s\" could be found in class "
                                    "\"%s\" or its superclasses", sig, name,
-                                   ClassHelper(c).GetDescriptor());
-    soa.Self()->GetException(NULL)->SetCause(cause.get());
-    return NULL;
+                                   ClassHelper(c.get()).GetDescriptor());
+    soa.Self()->GetException(nullptr)->SetCause(cause.get());
+    return nullptr;
   }
   if (is_static) {
     field = c->FindStaticField(name, ClassHelper(field_type).GetDescriptor());
   } else {
     field = c->FindInstanceField(name, ClassHelper(field_type).GetDescriptor());
   }
-  if (field == NULL) {
+  if (field == nullptr) {
     ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
                                    "no \"%s\" field \"%s\" in class \"%s\" or its superclasses",
-                                   sig, name, ClassHelper(c).GetDescriptor());
-    return NULL;
+                                   sig, name, ClassHelper(c.get()).GetDescriptor());
+    return nullptr;
   }
   return soa.EncodeField(field);
 }
 
-static void PinPrimitiveArray(const ScopedObjectAccess& soa, Array* array)
+static void PinPrimitiveArray(const ScopedObjectAccess& soa, mirror::Array* array)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   JavaVMExt* vm = soa.Vm();
   MutexLock mu(soa.Self(), vm->pins_lock);
   vm->pin_table.Add(array);
 }
 
-static void UnpinPrimitiveArray(const ScopedObjectAccess& soa, Array* array)
+static void UnpinPrimitiveArray(const ScopedObjectAccess& soa, mirror::Array* array)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   JavaVMExt* vm = soa.Vm();
   MutexLock mu(soa.Self(), vm->pins_lock);
   vm->pin_table.Remove(array);
 }
 
-static void ThrowAIOOBE(ScopedObjectAccess& soa, Array* array, jsize start,
+static void ThrowAIOOBE(ScopedObjectAccess& soa, mirror::Array* array, jsize start,
                         jsize length, const char* identifier)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   std::string type(PrettyTypeOf(array));
@@ -374,19 +353,19 @@
     LOCKS_EXCLUDED(Locks::mutator_lock_) {
   // Turn the const char* into a java.lang.String.
   ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg));
-  if (msg != NULL && s.get() == NULL) {
+  if (msg != nullptr && s.get() == nullptr) {
     return JNI_ERR;
   }
 
   // Choose an appropriate constructor and set up the arguments.
   jvalue args[2];
   const char* signature;
-  if (msg == NULL && cause == NULL) {
+  if (msg == nullptr && cause == nullptr) {
     signature = "()V";
-  } else if (msg != NULL && cause == NULL) {
+  } else if (msg != nullptr && cause == nullptr) {
     signature = "(Ljava/lang/String;)V";
     args[0].l = s.get();
-  } else if (msg == NULL && cause != NULL) {
+  } else if (msg == nullptr && cause != nullptr) {
     signature = "(Ljava/lang/Throwable;)V";
     args[0].l = cause;
   } else {
@@ -395,31 +374,32 @@
     args[1].l = cause;
   }
   jmethodID mid = env->GetMethodID(exception_class, "<init>", signature);
-  if (mid == NULL) {
+  if (mid == nullptr) {
     ScopedObjectAccess soa(env);
     LOG(ERROR) << "No <init>" << signature << " in "
-        << PrettyClass(soa.Decode<Class*>(exception_class));
+        << PrettyClass(soa.Decode<mirror::Class*>(exception_class));
     return JNI_ERR;
   }
 
-  ScopedLocalRef<jthrowable> exception(env, reinterpret_cast<jthrowable>(env->NewObjectA(exception_class, mid, args)));
-  if (exception.get() == NULL) {
+  ScopedLocalRef<jthrowable> exception(
+      env, reinterpret_cast<jthrowable>(env->NewObjectA(exception_class, mid, args)));
+  if (exception.get() == nullptr) {
     return JNI_ERR;
   }
   ScopedObjectAccess soa(env);
   ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
-  soa.Self()->SetException(throw_location, soa.Decode<Throwable*>(exception.get()));
+  soa.Self()->SetException(throw_location, soa.Decode<mirror::Throwable*>(exception.get()));
   return JNI_OK;
 }
 
 static jint JII_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* raw_args, bool as_daemon) {
-  if (vm == NULL || p_env == NULL) {
+  if (vm == nullptr || p_env == nullptr) {
     return JNI_ERR;
   }
 
   // Return immediately if we're already attached.
   Thread* self = Thread::Current();
-  if (self != NULL) {
+  if (self != nullptr) {
     *p_env = self->GetJniEnv();
     return JNI_OK;
   }
@@ -433,9 +413,9 @@
   }
 
   JavaVMAttachArgs* args = static_cast<JavaVMAttachArgs*>(raw_args);
-  const char* thread_name = NULL;
-  jobject thread_group = NULL;
-  if (args != NULL) {
+  const char* thread_name = nullptr;
+  jobject thread_group = nullptr;
+  if (args != nullptr) {
     if (IsBadJniVersion(args->version)) {
       LOG(ERROR) << "Bad JNI version passed to "
                  << (as_daemon ? "AttachCurrentThreadAsDaemon" : "AttachCurrentThread") << ": "
@@ -447,7 +427,7 @@
   }
 
   if (!runtime->AttachCurrentThread(thread_name, as_daemon, thread_group, !runtime->IsCompiler())) {
-    *p_env = NULL;
+    *p_env = nullptr;
     return JNI_ERR;
   } else {
     *p_env = Thread::Current()->GetJniEnv();
@@ -457,7 +437,7 @@
 
 class SharedLibrary {
  public:
-  SharedLibrary(const std::string& path, void* handle, Object* class_loader)
+  SharedLibrary(const std::string& path, void* handle, mirror::Object* class_loader)
       : path_(path),
         handle_(handle),
         class_loader_(class_loader),
@@ -467,7 +447,7 @@
         jni_on_load_result_(kPending) {
   }
 
-  Object* GetClassLoader() {
+  mirror::Object* GetClassLoader() {
     return class_loader_;
   }
 
@@ -525,7 +505,7 @@
 
   void VisitRoots(RootCallback* visitor, void* arg) {
     if (class_loader_ != nullptr) {
-      class_loader_ = visitor(class_loader_, arg, 0, kRootVMInternal);
+      visitor(&class_loader_, arg, 0, kRootVMInternal);
     }
   }
 
@@ -543,7 +523,7 @@
   void* handle_;
 
   // The ClassLoader this library is associated with.
-  Object* class_loader_;
+  mirror::Object* class_loader_;
 
   // Guards remaining items.
   Mutex jni_on_load_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -582,7 +562,7 @@
 
   SharedLibrary* Get(const std::string& path) {
     auto it = libraries_.find(path);
-    return (it == libraries_.end()) ? NULL : it->second;
+    return (it == libraries_.end()) ? nullptr : it->second;
   }
 
   void Put(const std::string& path, SharedLibrary* library) {
@@ -590,11 +570,11 @@
   }
 
   // See section 11.3 "Linking Native Methods" of the JNI spec.
-  void* FindNativeMethod(ArtMethod* m, std::string& detail)
+  void* FindNativeMethod(mirror::ArtMethod* m, std::string& detail)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::string jni_short_name(JniShortName(m));
     std::string jni_long_name(JniLongName(m));
-    const ClassLoader* declaring_class_loader = m->GetDeclaringClass()->GetClassLoader();
+    const mirror::ClassLoader* declaring_class_loader = m->GetDeclaringClass()->GetClassLoader();
     for (const auto& lib : libraries_) {
       SharedLibrary* library = lib.second;
       if (library->GetClassLoader() != declaring_class_loader) {
@@ -603,10 +583,10 @@
       }
       // Try the short name then the long name...
       void* fn = library->FindSymbol(jni_short_name);
-      if (fn == NULL) {
+      if (fn == nullptr) {
         fn = library->FindSymbol(jni_long_name);
       }
-      if (fn != NULL) {
+      if (fn != nullptr) {
         VLOG(jni) << "[Found native code for " << PrettyMethod(m)
                   << " in \"" << library->GetPath() << "\"]";
         return fn;
@@ -616,7 +596,7 @@
     detail += PrettyMethod(m);
     detail += " (tried " + jni_short_name + " and " + jni_long_name + ")";
     LOG(ERROR) << detail;
-    return NULL;
+    return nullptr;
   }
 
   void VisitRoots(RootCallback* callback, void* arg) {
@@ -631,8 +611,8 @@
 
 JValue InvokeWithJValues(const ScopedObjectAccess& soa, jobject obj, jmethodID mid,
                          jvalue* args) {
-  ArtMethod* method = soa.DecodeMethod(mid);
-  Object* receiver = method->IsStatic() ? NULL : soa.Decode<Object*>(obj);
+  mirror::ArtMethod* method = soa.DecodeMethod(mid);
+  mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
   MethodHelper mh(method);
   JValue result;
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -642,12 +622,12 @@
 }
 
 #define CHECK_NON_NULL_ARGUMENT(fn, value) \
-  if (UNLIKELY(value == NULL)) { \
+  if (UNLIKELY(value == nullptr)) { \
     JniAbortF(#fn, #value " == null"); \
   }
 
 #define CHECK_NON_NULL_MEMCPY_ARGUMENT(fn, length, value) \
-  if (UNLIKELY(length != 0 && value == NULL)) { \
+  if (UNLIKELY(length != 0 && value == nullptr)) { \
     JniAbortF(#fn, #value " == null"); \
   }
 
@@ -659,7 +639,7 @@
 
   static jclass DefineClass(JNIEnv*, const char*, jobject, const jbyte*, jsize) {
     LOG(WARNING) << "JNI DefineClass is not supported";
-    return NULL;
+    return nullptr;
   }
 
   static jclass FindClass(JNIEnv* env, const char* name) {
@@ -668,7 +648,7 @@
     ClassLinker* class_linker = runtime->GetClassLinker();
     std::string descriptor(NormalizeJniClassDescriptor(name));
     ScopedObjectAccess soa(env);
-    Class* c = NULL;
+    mirror::Class* c = nullptr;
     if (runtime->IsStarted()) {
       SirtRef<mirror::ClassLoader> class_loader(soa.Self(), GetClassLoader(soa));
       c = class_linker->FindClass(descriptor.c_str(), class_loader);
@@ -681,10 +661,10 @@
   static jmethodID FromReflectedMethod(JNIEnv* env, jobject java_method) {
     CHECK_NON_NULL_ARGUMENT(FromReflectedMethod, java_method);
     ScopedObjectAccess soa(env);
-    jobject art_method = env->GetObjectField(java_method,
-                                             WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
-    ArtMethod* method = soa.Decode<ArtMethod*>(art_method);
-    DCHECK(method != NULL);
+    jobject art_method = env->GetObjectField(
+        java_method, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
+    mirror::ArtMethod* method = soa.Decode<mirror::ArtMethod*>(art_method);
+    DCHECK(method != nullptr);
     return soa.EncodeMethod(method);
   }
 
@@ -693,54 +673,51 @@
     ScopedObjectAccess soa(env);
     jobject art_field = env->GetObjectField(java_field,
                                             WellKnownClasses::java_lang_reflect_Field_artField);
-    ArtField* field = soa.Decode<ArtField*>(art_field);
-    DCHECK(field != NULL);
+    mirror::ArtField* field = soa.Decode<mirror::ArtField*>(art_field);
+    DCHECK(field != nullptr);
     return soa.EncodeField(field);
   }
 
   static jobject ToReflectedMethod(JNIEnv* env, jclass, jmethodID mid, jboolean) {
     CHECK_NON_NULL_ARGUMENT(ToReflectedMethod, mid);
     ScopedObjectAccess soa(env);
-    ArtMethod* m = soa.DecodeMethod(mid);
+    mirror::ArtMethod* m = soa.DecodeMethod(mid);
+    CHECK(!kMovingMethods);
     jobject art_method = soa.AddLocalReference<jobject>(m);
     jobject reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Method);
     if (env->ExceptionCheck()) {
-      return NULL;
+      return nullptr;
     }
-    SetObjectField(env,
-                   reflect_method,
-                   WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod,
-                   art_method);
+    SetObjectField(env, reflect_method,
+                   WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod, art_method);
     return reflect_method;
   }
 
   static jobject ToReflectedField(JNIEnv* env, jclass, jfieldID fid, jboolean) {
     CHECK_NON_NULL_ARGUMENT(ToReflectedField, fid);
     ScopedObjectAccess soa(env);
-    ArtField* f = soa.DecodeField(fid);
+    mirror::ArtField* f = soa.DecodeField(fid);
     jobject art_field = soa.AddLocalReference<jobject>(f);
     jobject reflect_field = env->AllocObject(WellKnownClasses::java_lang_reflect_Field);
     if (env->ExceptionCheck()) {
-      return NULL;
+      return nullptr;
     }
-    SetObjectField(env,
-                   reflect_field,
-                   WellKnownClasses::java_lang_reflect_Field_artField,
-                   art_field);
+    SetObjectField(env, reflect_field,
+                   WellKnownClasses::java_lang_reflect_Field_artField, art_field);
     return reflect_field;
   }
 
   static jclass GetObjectClass(JNIEnv* env, jobject java_object) {
     CHECK_NON_NULL_ARGUMENT(GetObjectClass, java_object);
     ScopedObjectAccess soa(env);
-    Object* o = soa.Decode<Object*>(java_object);
+    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     return soa.AddLocalReference<jclass>(o->GetClass());
   }
 
   static jclass GetSuperclass(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(GetSuperclass, java_class);
     ScopedObjectAccess soa(env);
-    Class* c = soa.Decode<Class*>(java_class);
+    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
     return soa.AddLocalReference<jclass>(c->GetSuperClass());
   }
 
@@ -748,28 +725,28 @@
     CHECK_NON_NULL_ARGUMENT(IsAssignableFrom, java_class1);
     CHECK_NON_NULL_ARGUMENT(IsAssignableFrom, java_class2);
     ScopedObjectAccess soa(env);
-    Class* c1 = soa.Decode<Class*>(java_class1);
-    Class* c2 = soa.Decode<Class*>(java_class2);
+    mirror::Class* c1 = soa.Decode<mirror::Class*>(java_class1);
+    mirror::Class* c2 = soa.Decode<mirror::Class*>(java_class2);
     return c1->IsAssignableFrom(c2) ? JNI_TRUE : JNI_FALSE;
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(IsInstanceOf, java_class);
-    if (jobj == NULL) {
+    if (jobj == nullptr) {
       // Note: JNI is different from regular Java instanceof in this respect
       return JNI_TRUE;
     } else {
       ScopedObjectAccess soa(env);
-      Object* obj = soa.Decode<Object*>(jobj);
-      Class* c = soa.Decode<Class*>(java_class);
+      mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+      mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
       return obj->InstanceOf(c) ? JNI_TRUE : JNI_FALSE;
     }
   }
 
   static jint Throw(JNIEnv* env, jthrowable java_exception) {
     ScopedObjectAccess soa(env);
-    Throwable* exception = soa.Decode<Throwable*>(java_exception);
-    if (exception == NULL) {
+    mirror::Throwable* exception = soa.Decode<mirror::Throwable*>(java_exception);
+    if (exception == nullptr) {
       return JNI_ERR;
     }
     ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
@@ -779,7 +756,7 @@
 
   static jint ThrowNew(JNIEnv* env, jclass c, const char* msg) {
     CHECK_NON_NULL_ARGUMENT(ThrowNew, c);
-    return ThrowNewException(env, c, msg, NULL);
+    return ThrowNewException(env, c, msg, nullptr);
   }
 
   static jboolean ExceptionCheck(JNIEnv* env) {
@@ -793,13 +770,13 @@
   static void ExceptionDescribe(JNIEnv* env) {
     ScopedObjectAccess soa(env);
 
-    SirtRef<Object> old_throw_this_object(soa.Self(), NULL);
-    SirtRef<ArtMethod> old_throw_method(soa.Self(), NULL);
-    SirtRef<Throwable> old_exception(soa.Self(), NULL);
+    SirtRef<mirror::Object> old_throw_this_object(soa.Self(), nullptr);
+    SirtRef<mirror::ArtMethod> old_throw_method(soa.Self(), nullptr);
+    SirtRef<mirror::Throwable> old_exception(soa.Self(), nullptr);
     uint32_t old_throw_dex_pc;
     {
       ThrowLocation old_throw_location;
-      Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
+      mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
       old_throw_this_object.reset(old_throw_location.GetThis());
       old_throw_method.reset(old_throw_location.GetMethod());
       old_exception.reset(old_exception_obj);
@@ -809,13 +786,13 @@
     ScopedLocalRef<jthrowable> exception(env, soa.AddLocalReference<jthrowable>(old_exception.get()));
     ScopedLocalRef<jclass> exception_class(env, env->GetObjectClass(exception.get()));
     jmethodID mid = env->GetMethodID(exception_class.get(), "printStackTrace", "()V");
-    if (mid == NULL) {
+    if (mid == nullptr) {
       LOG(WARNING) << "JNI WARNING: no printStackTrace()V in "
                    << PrettyTypeOf(old_exception.get());
     } else {
       env->CallVoidMethod(exception.get(), mid);
       if (soa.Self()->IsExceptionPending()) {
-        LOG(WARNING) << "JNI WARNING: " << PrettyTypeOf(soa.Self()->GetException(NULL))
+        LOG(WARNING) << "JNI WARNING: " << PrettyTypeOf(soa.Self()->GetException(nullptr))
                      << " thrown while calling printStackTrace";
         soa.Self()->ClearException();
       }
@@ -828,7 +805,7 @@
 
   static jthrowable ExceptionOccurred(JNIEnv* env) {
     ScopedObjectAccess soa(env);
-    Object* exception = soa.Self()->GetException(NULL);
+    mirror::Object* exception = soa.Self()->GetException(nullptr);
     return soa.AddLocalReference<jthrowable>(exception);
   }
 
@@ -846,7 +823,7 @@
 
   static jobject PopLocalFrame(JNIEnv* env, jobject java_survivor) {
     ScopedObjectAccess soa(env);
-    Object* survivor = soa.Decode<Object*>(java_survivor);
+    mirror::Object* survivor = soa.Decode<mirror::Object*>(java_survivor);
     soa.Env()->PopFrame();
     return soa.AddLocalReference<jobject>(survivor);
   }
@@ -857,7 +834,7 @@
 
   static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    Object* decoded_obj = soa.Decode<Object*>(obj);
+    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
     // Check for null after decoding the object to handle cleared weak globals.
     if (decoded_obj == nullptr) {
       return nullptr;
@@ -870,7 +847,7 @@
   }
 
   static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
-    if (obj == NULL) {
+    if (obj == nullptr) {
       return;
     }
     JavaVMExt* vm = reinterpret_cast<JNIEnvExt*>(env)->vm;
@@ -886,7 +863,7 @@
 
   static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    return AddWeakGlobalReference(soa, soa.Decode<Object*>(obj));
+    return AddWeakGlobalReference(soa, soa.Decode<mirror::Object*>(obj));
   }
 
   static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
@@ -898,7 +875,7 @@
 
   static jobject NewLocalRef(JNIEnv* env, jobject obj) {
     ScopedObjectAccess soa(env);
-    mirror::Object* decoded_obj = soa.Decode<Object*>(obj);
+    mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
     // Check for null after decoding the object to handle cleared weak globals.
     if (decoded_obj == nullptr) {
       return nullptr;
@@ -907,7 +884,7 @@
   }
 
   static void DeleteLocalRef(JNIEnv* env, jobject obj) {
-    if (obj == NULL) {
+    if (obj == nullptr) {
       return;
     }
     IndirectReferenceTable& locals = reinterpret_cast<JNIEnvExt*>(env)->locals;
@@ -929,14 +906,14 @@
       return JNI_TRUE;
     } else {
       ScopedObjectAccess soa(env);
-      return (soa.Decode<Object*>(obj1) == soa.Decode<Object*>(obj2)) ? JNI_TRUE : JNI_FALSE;
+      return (soa.Decode<mirror::Object*>(obj1) == soa.Decode<mirror::Object*>(obj2)) ? JNI_TRUE : JNI_FALSE;
     }
   }
 
   static jobject AllocObject(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(AllocObject, java_class);
     ScopedObjectAccess soa(env);
-    Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
@@ -957,42 +934,40 @@
     CHECK_NON_NULL_ARGUMENT(NewObjectV, java_class);
     CHECK_NON_NULL_ARGUMENT(NewObjectV, mid);
     ScopedObjectAccess soa(env);
-    Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
-    Object* result = c->AllocObject(soa.Self());
+    mirror::Object* result = c->AllocObject(soa.Self());
     if (result == nullptr) {
       return nullptr;
     }
     jobject local_result = soa.AddLocalReference<jobject>(result);
     CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
-    if (!soa.Self()->IsExceptionPending()) {
-      return local_result;
-    } else {
+    if (soa.Self()->IsExceptionPending()) {
       return nullptr;
     }
+    return local_result;
   }
 
   static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(NewObjectA, java_class);
     CHECK_NON_NULL_ARGUMENT(NewObjectA, mid);
     ScopedObjectAccess soa(env);
-    Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+    mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
     if (c == nullptr) {
       return nullptr;
     }
-    Object* result = c->AllocObject(soa.Self());
-    if (result == NULL) {
-      return NULL;
+    mirror::Object* result = c->AllocObject(soa.Self());
+    if (result == nullptr) {
+      return nullptr;
     }
     jobject local_result = soa.AddLocalReference<jobjectArray>(result);
     CallNonvirtualVoidMethodA(env, local_result, java_class, mid, args);
-    if (!soa.Self()->IsExceptionPending()) {
-      return local_result;
-    } else {
-      return NULL;
+    if (soa.Self()->IsExceptionPending()) {
+      return nullptr;
     }
+    return local_result;
   }
 
   static jmethodID GetMethodID(JNIEnv* env, jclass java_class, const char* name, const char* sig) {
@@ -1557,15 +1532,15 @@
     CHECK_NON_NULL_ARGUMENT(GetObjectField, obj);
     CHECK_NON_NULL_ARGUMENT(GetObjectField, fid);
     ScopedObjectAccess soa(env);
-    Object* o = soa.Decode<Object*>(obj);
-    ArtField* f = soa.DecodeField(fid);
+    mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+    mirror::ArtField* f = soa.DecodeField(fid);
     return soa.AddLocalReference<jobject>(f->GetObject(o));
   }
 
   static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
     CHECK_NON_NULL_ARGUMENT(GetStaticObjectField, fid);
     ScopedObjectAccess soa(env);
-    ArtField* f = soa.DecodeField(fid);
+    mirror::ArtField* f = soa.DecodeField(fid);
     return soa.AddLocalReference<jobject>(f->GetObject(f->GetDeclaringClass()));
   }
 
@@ -1573,47 +1548,47 @@
     CHECK_NON_NULL_ARGUMENT(SetObjectField, java_object);
     CHECK_NON_NULL_ARGUMENT(SetObjectField, fid);
     ScopedObjectAccess soa(env);
-    Object* o = soa.Decode<Object*>(java_object);
-    Object* v = soa.Decode<Object*>(java_value);
-    ArtField* f = soa.DecodeField(fid);
-    f->SetObject(o, v);
+    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+    mirror::ArtField* f = soa.DecodeField(fid);
+    f->SetObject<false>(o, v);
   }
 
   static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
     CHECK_NON_NULL_ARGUMENT(SetStaticObjectField, fid);
     ScopedObjectAccess soa(env);
-    Object* v = soa.Decode<Object*>(java_value);
-    ArtField* f = soa.DecodeField(fid);
-    f->SetObject(f->GetDeclaringClass(), v);
+    mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+    mirror::ArtField* f = soa.DecodeField(fid);
+    f->SetObject<false>(f->GetDeclaringClass(), v);
   }
 
 #define GET_PRIMITIVE_FIELD(fn, instance) \
   CHECK_NON_NULL_ARGUMENT(Get #fn Field, instance); \
   CHECK_NON_NULL_ARGUMENT(Get #fn Field, fid); \
   ScopedObjectAccess soa(env); \
-  Object* o = soa.Decode<Object*>(instance); \
-  ArtField* f = soa.DecodeField(fid); \
+  mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+  mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (o)
 
 #define GET_STATIC_PRIMITIVE_FIELD(fn) \
   CHECK_NON_NULL_ARGUMENT(GetStatic #fn Field, fid); \
   ScopedObjectAccess soa(env); \
-  ArtField* f = soa.DecodeField(fid); \
+  mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (f->GetDeclaringClass())
 
 #define SET_PRIMITIVE_FIELD(fn, instance, value) \
   CHECK_NON_NULL_ARGUMENT(Set #fn Field, instance); \
   CHECK_NON_NULL_ARGUMENT(Set #fn Field, fid); \
   ScopedObjectAccess soa(env); \
-  Object* o = soa.Decode<Object*>(instance); \
-  ArtField* f = soa.DecodeField(fid); \
-  f->Set ##fn(o, value)
+  mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+  mirror::ArtField* f = soa.DecodeField(fid); \
+  f->Set ##fn <false>(o, value)
 
 #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
   CHECK_NON_NULL_ARGUMENT(SetStatic #fn Field, fid); \
   ScopedObjectAccess soa(env); \
-  ArtField* f = soa.DecodeField(fid); \
-  f->Set ##fn(f->GetDeclaringClass(), value)
+  mirror::ArtField* f = soa.DecodeField(fid); \
+  f->Set ##fn <false>(f->GetDeclaringClass(), value)
 
   static jboolean GetBooleanField(JNIEnv* env, jobject obj, jfieldID fid) {
     GET_PRIMITIVE_FIELD(Boolean, obj);
@@ -1748,7 +1723,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     jobject local_result = soa.AddLocalReference<jobject>(result.GetL());
     va_end(ap);
     return local_result;
@@ -1757,14 +1732,14 @@
   static jobject CallStaticObjectMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethodV, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, args));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
   static jobject CallStaticObjectMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethodA, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithJValues(soa, NULL, mid, args));
+    JValue result(InvokeWithJValues(soa, nullptr, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
@@ -1773,7 +1748,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetZ();
   }
@@ -1781,13 +1756,13 @@
   static jboolean CallStaticBooleanMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetZ();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetZ();
   }
 
   static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetZ();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetZ();
   }
 
   static jbyte CallStaticByteMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1795,7 +1770,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticByteMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetB();
   }
@@ -1803,13 +1778,13 @@
   static jbyte CallStaticByteMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticByteMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetB();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetB();
   }
 
   static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticByteMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetB();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetB();
   }
 
   static jchar CallStaticCharMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1817,7 +1792,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticCharMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetC();
   }
@@ -1825,13 +1800,13 @@
   static jchar CallStaticCharMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticCharMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetC();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetC();
   }
 
   static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticCharMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetC();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetC();
   }
 
   static jshort CallStaticShortMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1839,7 +1814,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticShortMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetS();
   }
@@ -1847,13 +1822,13 @@
   static jshort CallStaticShortMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticShortMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetS();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetS();
   }
 
   static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticShortMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetS();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetS();
   }
 
   static jint CallStaticIntMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1861,7 +1836,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticIntMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetI();
   }
@@ -1869,13 +1844,13 @@
   static jint CallStaticIntMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticIntMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetI();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetI();
   }
 
   static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticIntMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetI();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetI();
   }
 
   static jlong CallStaticLongMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1883,7 +1858,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticLongMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetJ();
   }
@@ -1891,13 +1866,13 @@
   static jlong CallStaticLongMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticLongMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetJ();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetJ();
   }
 
   static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticLongMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetJ();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetJ();
   }
 
   static jfloat CallStaticFloatMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1905,7 +1880,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetF();
   }
@@ -1913,13 +1888,13 @@
   static jfloat CallStaticFloatMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetF();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetF();
   }
 
   static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetF();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetF();
   }
 
   static jdouble CallStaticDoubleMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1927,7 +1902,7 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethod, mid);
     ScopedObjectAccess soa(env);
-    JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+    JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
     return result.GetD();
   }
@@ -1935,13 +1910,13 @@
   static jdouble CallStaticDoubleMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethodV, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithVarArgs(soa, NULL, mid, args).GetD();
+    return InvokeWithVarArgs(soa, nullptr, mid, args).GetD();
   }
 
   static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethodA, mid);
     ScopedObjectAccess soa(env);
-    return InvokeWithJValues(soa, NULL, mid, args).GetD();
+    return InvokeWithJValues(soa, nullptr, mid, args).GetD();
   }
 
   static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1949,20 +1924,20 @@
     va_start(ap, mid);
     CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethod, mid);
     ScopedObjectAccess soa(env);
-    InvokeWithVarArgs(soa, NULL, mid, ap);
+    InvokeWithVarArgs(soa, nullptr, mid, ap);
     va_end(ap);
   }
 
   static void CallStaticVoidMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethodV, mid);
     ScopedObjectAccess soa(env);
-    InvokeWithVarArgs(soa, NULL, mid, args);
+    InvokeWithVarArgs(soa, nullptr, mid, args);
   }
 
   static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
     CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethodA, mid);
     ScopedObjectAccess soa(env);
-    InvokeWithJValues(soa, NULL, mid, args);
+    InvokeWithJValues(soa, nullptr, mid, args);
   }
 
   static jstring NewString(JNIEnv* env, const jchar* chars, jsize char_count) {
@@ -1975,36 +1950,36 @@
       return nullptr;
     }
     ScopedObjectAccess soa(env);
-    String* result = String::AllocFromUtf16(soa.Self(), char_count, chars);
+    mirror::String* result = mirror::String::AllocFromUtf16(soa.Self(), char_count, chars);
     return soa.AddLocalReference<jstring>(result);
   }
 
   static jstring NewStringUTF(JNIEnv* env, const char* utf) {
-    if (utf == NULL) {
-      return NULL;
+    if (utf == nullptr) {
+      return nullptr;
     }
     ScopedObjectAccess soa(env);
-    String* result = String::AllocFromModifiedUtf8(soa.Self(), utf);
+    mirror::String* result = mirror::String::AllocFromModifiedUtf8(soa.Self(), utf);
     return soa.AddLocalReference<jstring>(result);
   }
 
   static jsize GetStringLength(JNIEnv* env, jstring java_string) {
     CHECK_NON_NULL_ARGUMENT(GetStringLength, java_string);
     ScopedObjectAccess soa(env);
-    return soa.Decode<String*>(java_string)->GetLength();
+    return soa.Decode<mirror::String*>(java_string)->GetLength();
   }
 
   static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
     CHECK_NON_NULL_ARGUMENT(GetStringLength, java_string);
     ScopedObjectAccess soa(env);
-    return soa.Decode<String*>(java_string)->GetUtfLength();
+    return soa.Decode<mirror::String*>(java_string)->GetUtfLength();
   }
 
   static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                               jchar* buf) {
     CHECK_NON_NULL_ARGUMENT(GetStringRegion, java_string);
     ScopedObjectAccess soa(env);
-    String* s = soa.Decode<String*>(java_string);
+    mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
@@ -2018,7 +1993,7 @@
                                  char* buf) {
     CHECK_NON_NULL_ARGUMENT(GetStringUTFRegion, java_string);
     ScopedObjectAccess soa(env);
-    String* s = soa.Decode<String*>(java_string);
+    mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
@@ -2031,8 +2006,8 @@
   static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetStringChars, java_string);
     ScopedObjectAccess soa(env);
-    String* s = soa.Decode<String*>(java_string);
-    CharArray* chars = s->GetCharArray();
+    mirror::String* s = soa.Decode<mirror::String*>(java_string);
+    mirror::CharArray* chars = s->GetCharArray();
     PinPrimitiveArray(soa, chars);
     if (is_copy != nullptr) {
       *is_copy = JNI_TRUE;
@@ -2051,7 +2026,7 @@
     CHECK_NON_NULL_ARGUMENT(ReleaseStringChars, java_string);
     delete[] chars;
     ScopedObjectAccess soa(env);
-    UnpinPrimitiveArray(soa, soa.Decode<String*>(java_string)->GetCharArray());
+    UnpinPrimitiveArray(soa, soa.Decode<mirror::String*>(java_string)->GetCharArray());
   }
 
   static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* is_copy) {
@@ -2063,17 +2038,17 @@
   }
 
   static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
-    if (java_string == NULL) {
-      return NULL;
+    if (java_string == nullptr) {
+      return nullptr;
     }
-    if (is_copy != NULL) {
+    if (is_copy != nullptr) {
       *is_copy = JNI_TRUE;
     }
     ScopedObjectAccess soa(env);
-    String* s = soa.Decode<String*>(java_string);
+    mirror::String* s = soa.Decode<mirror::String*>(java_string);
     size_t byte_count = s->GetUtfLength();
     char* bytes = new char[byte_count + 1];
-    CHECK(bytes != NULL);  // bionic aborts anyway.
+    CHECK(bytes != nullptr);  // bionic aborts anyway.
     const uint16_t* chars = s->GetCharArray()->GetData() + s->GetOffset();
     ConvertUtf16ToModifiedUtf8(bytes, chars, s->GetLength());
     bytes[byte_count] = '\0';
@@ -2087,18 +2062,19 @@
   static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
     CHECK_NON_NULL_ARGUMENT(GetArrayLength, java_array);
     ScopedObjectAccess soa(env);
-    Object* obj = soa.Decode<Object*>(java_array);
+    mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
     if (UNLIKELY(!obj->IsArrayInstance())) {
       JniAbortF("GetArrayLength", "not an array: %s", PrettyTypeOf(obj).c_str());
     }
-    Array* array = obj->AsArray();
+    mirror::Array* array = obj->AsArray();
     return array->GetLength();
   }
 
   static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index) {
     CHECK_NON_NULL_ARGUMENT(GetObjectArrayElement, java_array);
     ScopedObjectAccess soa(env);
-    ObjectArray<Object>* array = soa.Decode<ObjectArray<Object>*>(java_array);
+    mirror::ObjectArray<mirror::Object>* array =
+        soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
     return soa.AddLocalReference<jobject>(array->Get(index));
   }
 
@@ -2106,44 +2082,45 @@
                                     jobject java_value) {
     CHECK_NON_NULL_ARGUMENT(SetObjectArrayElement, java_array);
     ScopedObjectAccess soa(env);
-    ObjectArray<Object>* array = soa.Decode<ObjectArray<Object>*>(java_array);
-    Object* value = soa.Decode<Object*>(java_value);
-    array->Set(index, value);
+    mirror::ObjectArray<mirror::Object>* array =
+        soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
+    mirror::Object* value = soa.Decode<mirror::Object*>(java_value);
+    array->Set<false>(index, value);
   }
 
   static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jbooleanArray, BooleanArray>(soa, length);
+    return NewPrimitiveArray<jbooleanArray, mirror::BooleanArray>(soa, length);
   }
 
   static jbyteArray NewByteArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jbyteArray, ByteArray>(soa, length);
+    return NewPrimitiveArray<jbyteArray, mirror::ByteArray>(soa, length);
   }
 
   static jcharArray NewCharArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jcharArray, CharArray>(soa, length);
+    return NewPrimitiveArray<jcharArray, mirror::CharArray>(soa, length);
   }
 
   static jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jdoubleArray, DoubleArray>(soa, length);
+    return NewPrimitiveArray<jdoubleArray, mirror::DoubleArray>(soa, length);
   }
 
   static jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jfloatArray, FloatArray>(soa, length);
+    return NewPrimitiveArray<jfloatArray, mirror::FloatArray>(soa, length);
   }
 
   static jintArray NewIntArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jintArray, IntArray>(soa, length);
+    return NewPrimitiveArray<jintArray, mirror::IntArray>(soa, length);
   }
 
   static jlongArray NewLongArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jlongArray, LongArray>(soa, length);
+    return NewPrimitiveArray<jlongArray, mirror::LongArray>(soa, length);
   }
 
   static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_jclass,
@@ -2155,9 +2132,9 @@
 
     // Compute the array class corresponding to the given element class.
     ScopedObjectAccess soa(env);
-    Class* array_class;
+    mirror::Class* array_class;
     {
-      Class* element_class = soa.Decode<Class*>(element_jclass);
+      mirror::Class* element_class = soa.Decode<mirror::Class*>(element_jclass);
       if (UNLIKELY(element_class->IsPrimitive())) {
         JniAbortF("NewObjectArray", "not an object type: %s",
                   PrettyDescriptor(element_class).c_str());
@@ -2176,9 +2153,10 @@
     }
 
     // Allocate and initialize if necessary.
-    ObjectArray<Object>* result = ObjectArray<Object>::Alloc(soa.Self(), array_class, length);
+    mirror::ObjectArray<mirror::Object>* result =
+        mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), array_class, length);
     if (result != nullptr && initial_element != nullptr) {
-      Object* initial_object = soa.Decode<Object*>(initial_element);
+      mirror::Object* initial_object = soa.Decode<mirror::Object*>(initial_element);
       if (initial_object != nullptr) {
         mirror::Class* element_class = result->GetClass()->GetComponentType();
         if (UNLIKELY(!element_class->IsAssignableFrom(initial_object->GetClass()))) {
@@ -2188,7 +2166,7 @@
 
         } else {
           for (jsize i = 0; i < length; ++i) {
-            result->SetWithoutChecks(i, initial_object);
+            result->SetWithoutChecks<false>(i, initial_object);
           }
         }
       }
@@ -2198,18 +2176,18 @@
 
   static jshortArray NewShortArray(JNIEnv* env, jsize length) {
     ScopedObjectAccess soa(env);
-    return NewPrimitiveArray<jshortArray, ShortArray>(soa, length);
+    return NewPrimitiveArray<jshortArray, mirror::ShortArray>(soa, length);
   }
 
   static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray java_array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetPrimitiveArrayCritical, java_array);
     ScopedObjectAccess soa(env);
-    Array* array = soa.Decode<Array*>(java_array);
+    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
     gc::Heap* heap = Runtime::Current()->GetHeap();
     if (heap->IsMovableObject(array)) {
       heap->IncrementDisableMovingGC(soa.Self());
       // Re-decode in case the object moved since IncrementDisableGC waits for GC to complete.
-      array = soa.Decode<Array*>(java_array);
+      array = soa.Decode<mirror::Array*>(java_array);
     }
     PinPrimitiveArray(soa, array);
     if (is_copy != nullptr) {
@@ -2226,49 +2204,49 @@
   static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetBooleanArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jbooleanArray, jboolean*, BooleanArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jbooleanArray, jboolean*, mirror::BooleanArray>(soa, array, is_copy);
   }
 
   static jbyte* GetByteArrayElements(JNIEnv* env, jbyteArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetByteArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jbyteArray, jbyte*, ByteArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jbyteArray, jbyte*, mirror::ByteArray>(soa, array, is_copy);
   }
 
   static jchar* GetCharArrayElements(JNIEnv* env, jcharArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetCharArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jcharArray, jchar*, CharArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jcharArray, jchar*, mirror::CharArray>(soa, array, is_copy);
   }
 
   static jdouble* GetDoubleArrayElements(JNIEnv* env, jdoubleArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetDoubleArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jdoubleArray, jdouble*, DoubleArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jdoubleArray, jdouble*, mirror::DoubleArray>(soa, array, is_copy);
   }
 
   static jfloat* GetFloatArrayElements(JNIEnv* env, jfloatArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetFloatArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jfloatArray, jfloat*, FloatArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jfloatArray, jfloat*, mirror::FloatArray>(soa, array, is_copy);
   }
 
   static jint* GetIntArrayElements(JNIEnv* env, jintArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetIntArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jintArray, jint*, IntArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jintArray, jint*, mirror::IntArray>(soa, array, is_copy);
   }
 
   static jlong* GetLongArrayElements(JNIEnv* env, jlongArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetLongArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jlongArray, jlong*, LongArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jlongArray, jlong*, mirror::LongArray>(soa, array, is_copy);
   }
 
   static jshort* GetShortArrayElements(JNIEnv* env, jshortArray array, jboolean* is_copy) {
     CHECK_NON_NULL_ARGUMENT(GetShortArrayElements, array);
     ScopedObjectAccess soa(env);
-    return GetPrimitiveArray<jshortArray, jshort*, ShortArray>(soa, array, is_copy);
+    return GetPrimitiveArray<jshortArray, jshort*, mirror::ShortArray>(soa, array, is_copy);
   }
 
   static void ReleaseBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* elements,
@@ -2310,97 +2288,102 @@
   static void GetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
                                     jboolean* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jbooleanArray, jboolean, BooleanArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start,
+                                                                           length, buf);
   }
 
   static void GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
                                  jbyte* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jbyteArray, jbyte, ByteArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
   }
 
   static void GetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
                                  jchar* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jcharArray, jchar, CharArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
   }
 
   static void GetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
                                    jdouble* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jdoubleArray, jdouble, DoubleArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length,
+                                                                        buf);
   }
 
   static void GetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
                                   jfloat* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jfloatArray, jfloat, FloatArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length,
+                                                                     buf);
   }
 
   static void GetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
                                 jint* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jintArray, jint, IntArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
   }
 
   static void GetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
                                  jlong* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jlongArray, jlong, LongArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
   }
 
   static void GetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
                                   jshort* buf) {
     ScopedObjectAccess soa(env);
-    GetPrimitiveArrayRegion<jshortArray, jshort, ShortArray>(soa, array, start, length, buf);
+    GetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+                                                                     buf);
   }
 
   static void SetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
                                     const jboolean* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jbooleanArray, jboolean, BooleanArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start, length, buf);
   }
 
   static void SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
                                  const jbyte* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jbyteArray, jbyte, ByteArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
   }
 
   static void SetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
                                  const jchar* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jcharArray, jchar, CharArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
   }
 
   static void SetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
                                    const jdouble* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jdoubleArray, jdouble, DoubleArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length, buf);
   }
 
   static void SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
                                   const jfloat* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jfloatArray, jfloat, FloatArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length, buf);
   }
 
   static void SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
                                 const jint* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jintArray, jint, IntArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
   }
 
   static void SetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
                                  const jlong* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jlongArray, jlong, LongArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
   }
 
   static void SetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
                                   const jshort* buf) {
     ScopedObjectAccess soa(env);
-    SetPrimitiveArrayRegion<jshortArray, jshort, ShortArray>(soa, array, start, length, buf);
+    SetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+                                                                     buf);
   }
 
   static jint RegisterNatives(JNIEnv* env, jclass java_class, const JNINativeMethod* methods,
@@ -2416,7 +2399,7 @@
     }
     CHECK_NON_NULL_ARGUMENT(RegisterNatives, java_class);
     ScopedObjectAccess soa(env);
-    Class* c = soa.Decode<Class*>(java_class);
+    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
     if (UNLIKELY(method_count == 0)) {
       LOG(WARNING) << "JNI RegisterNativeMethods: attempt to register 0 native methods for "
           << PrettyDescriptor(c);
@@ -2432,11 +2415,11 @@
         ++sig;
       }
 
-      ArtMethod* m = c->FindDirectMethod(name, sig);
-      if (m == NULL) {
+      mirror::ArtMethod* m = c->FindDirectMethod(name, sig);
+      if (m == nullptr) {
         m = c->FindVirtualMethod(name, sig);
       }
-      if (m == NULL) {
+      if (m == nullptr) {
         c->DumpClass(LOG(ERROR), mirror::Class::kDumpClassFullDetail);
         LOG(return_errors ? ERROR : FATAL) << "Failed to register native method "
             << PrettyDescriptor(c) << "." << name << sig << " in "
@@ -2461,18 +2444,18 @@
   static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(UnregisterNatives, java_class);
     ScopedObjectAccess soa(env);
-    Class* c = soa.Decode<Class*>(java_class);
+    mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
 
     VLOG(jni) << "[Unregistering JNI native methods for " << PrettyClass(c) << "]";
 
     for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
-      ArtMethod* m = c->GetDirectMethod(i);
+      mirror::ArtMethod* m = c->GetDirectMethod(i);
       if (m->IsNative()) {
         m->UnregisterNative(soa.Self());
       }
     }
     for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
-      ArtMethod* m = c->GetVirtualMethod(i);
+      mirror::ArtMethod* m = c->GetVirtualMethod(i);
       if (m->IsNative()) {
         m->UnregisterNative(soa.Self());
       }
@@ -2485,8 +2468,8 @@
       EXCLUSIVE_LOCK_FUNCTION(monitor_lock_) {
     CHECK_NON_NULL_ARGUMENT(MonitorEnter, java_object);
     ScopedObjectAccess soa(env);
-    Object* o = soa.Decode<Object*>(java_object);
-    o->MonitorEnter(soa.Self());
+    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+    o = o->MonitorEnter(soa.Self());
     if (soa.Self()->IsExceptionPending()) {
       return JNI_ERR;
     }
@@ -2498,7 +2481,7 @@
       UNLOCK_FUNCTION(monitor_lock_) {
     CHECK_NON_NULL_ARGUMENT(MonitorExit, java_object);
     ScopedObjectAccess soa(env);
-    Object* o = soa.Decode<Object*>(java_object);
+    mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     o->MonitorExit(soa.Self());
     if (soa.Self()->IsExceptionPending()) {
       return JNI_ERR;
@@ -2510,20 +2493,20 @@
   static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
     CHECK_NON_NULL_ARGUMENT(GetJavaVM, vm);
     Runtime* runtime = Runtime::Current();
-    if (runtime != NULL) {
+    if (runtime != nullptr) {
       *vm = runtime->GetJavaVM();
     } else {
-      *vm = NULL;
+      *vm = nullptr;
     }
-    return (*vm != NULL) ? JNI_OK : JNI_ERR;
+    return (*vm != nullptr) ? JNI_OK : JNI_ERR;
   }
 
   static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
     if (capacity < 0) {
       JniAbortF("NewDirectByteBuffer", "negative buffer capacity: %" PRId64, capacity);
     }
-    if (address == NULL && capacity != 0) {
-      JniAbortF("NewDirectByteBuffer", "non-zero capacity for NULL pointer: %" PRId64, capacity);
+    if (address == nullptr && capacity != 0) {
+      JniAbortF("NewDirectByteBuffer", "non-zero capacity for nullptr pointer: %" PRId64, capacity);
     }
 
     // At the moment, the Java side is limited to 32 bits.
@@ -2535,15 +2518,17 @@
     jobject result = env->NewObject(WellKnownClasses::java_nio_DirectByteBuffer,
                                     WellKnownClasses::java_nio_DirectByteBuffer_init,
                                     address_arg, capacity_arg);
-    return static_cast<JNIEnvExt*>(env)->self->IsExceptionPending() ? NULL : result;
+    return static_cast<JNIEnvExt*>(env)->self->IsExceptionPending() ? nullptr : result;
   }
 
   static void* GetDirectBufferAddress(JNIEnv* env, jobject java_buffer) {
-    return reinterpret_cast<void*>(env->GetLongField(java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress));
+    return reinterpret_cast<void*>(env->GetLongField(
+        java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress));
   }
 
   static jlong GetDirectBufferCapacity(JNIEnv* env, jobject java_buffer) {
-    return static_cast<jlong>(env->GetIntField(java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_capacity));
+    return static_cast<jlong>(env->GetIntField(
+        java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_capacity));
   }
 
   static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
@@ -2572,12 +2557,13 @@
         return JNIInvalidRefType;
       }
 
-      // If we're handing out direct pointers, check whether it's a direct pointer
-      // to a local reference.
+      // If we're handing out direct pointers, check whether it's a direct pointer to a local
+      // reference.
       {
         ScopedObjectAccess soa(env);
-        if (soa.Decode<Object*>(java_object) == reinterpret_cast<Object*>(java_object)) {
-          if (soa.Env()->locals.ContainsDirectPointer(reinterpret_cast<Object*>(java_object))) {
+        if (soa.Decode<mirror::Object*>(java_object) ==
+            reinterpret_cast<mirror::Object*>(java_object)) {
+          if (soa.Env()->locals.ContainsDirectPointer(reinterpret_cast<mirror::Object*>(java_object))) {
             return JNILocalRefType;
           }
         }
@@ -2644,7 +2630,7 @@
   template <typename ArrayT, typename ElementT>
   static void ReleasePrimitiveArray(JNIEnv* env, ArrayT java_array, ElementT* elements, jint mode) {
     ScopedObjectAccess soa(env);
-    Array* array = soa.Decode<Array*>(java_array);
+    mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
     size_t component_size = array->GetClass()->GetComponentSize();
     void* array_data = array->GetRawData(component_size, 0);
     gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -2709,10 +2695,10 @@
 };
 
 const JNINativeInterface gJniNativeInterface = {
-  NULL,  // reserved0.
-  NULL,  // reserved1.
-  NULL,  // reserved2.
-  NULL,  // reserved3.
+  nullptr,  // reserved0.
+  nullptr,  // reserved1.
+  nullptr,  // reserved2.
+  nullptr,  // reserved3.
   JNI::GetVersion,
   JNI::DefineClass,
   JNI::FindClass,
@@ -3032,7 +3018,7 @@
 
 extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize, jsize* vm_count) {
   Runtime* runtime = Runtime::Current();
-  if (runtime == NULL) {
+  if (runtime == nullptr) {
     *vm_count = 0;
   } else {
     *vm_count = 1;
@@ -3049,7 +3035,7 @@
 class JII {
  public:
   static jint DestroyJavaVM(JavaVM* vm) {
-    if (vm == NULL) {
+    if (vm == nullptr) {
       return JNI_ERR;
     }
     JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
@@ -3066,7 +3052,7 @@
   }
 
   static jint DetachCurrentThread(JavaVM* vm) {
-    if (vm == NULL || Thread::Current() == NULL) {
+    if (vm == nullptr || Thread::Current() == nullptr) {
       return JNI_ERR;
     }
     JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
@@ -3083,12 +3069,12 @@
       LOG(ERROR) << "Bad JNI version passed to GetEnv: " << version;
       return JNI_EVERSION;
     }
-    if (vm == NULL || env == NULL) {
+    if (vm == nullptr || env == nullptr) {
       return JNI_ERR;
     }
     Thread* thread = Thread::Current();
-    if (thread == NULL) {
-      *env = NULL;
+    if (thread == nullptr) {
+      *env = nullptr;
       return JNI_EDETACHED;
     }
     *env = thread->GetJniEnv();
@@ -3097,9 +3083,9 @@
 };
 
 const JNIInvokeInterface gJniInvokeInterface = {
-  NULL,  // reserved0
-  NULL,  // reserved1
-  NULL,  // reserved2
+  nullptr,  // reserved0
+  nullptr,  // reserved1
+  nullptr,  // reserved2
   JII::DestroyJavaVM,
   JII::AttachCurrentThread,
   JII::DetachCurrentThread,
@@ -3109,8 +3095,8 @@
 
 JavaVMExt::JavaVMExt(Runtime* runtime, Runtime::ParsedOptions* options)
     : runtime(runtime),
-      check_jni_abort_hook(NULL),
-      check_jni_abort_hook_data(NULL),
+      check_jni_abort_hook(nullptr),
+      check_jni_abort_hook_data(nullptr),
       check_jni(false),
       force_copy(false),  // TODO: add a way to enable this
       trace(options->jni_trace_),
@@ -3226,7 +3212,7 @@
 }
 
 bool JavaVMExt::LoadNativeLibrary(const std::string& path,
-                                  const SirtRef<ClassLoader>& class_loader,
+                                  const SirtRef<mirror::ClassLoader>& class_loader,
                                   std::string* detail) {
   detail->clear();
 
@@ -3241,7 +3227,7 @@
     MutexLock mu(self, libraries_lock);
     library = libraries->Get(path);
   }
-  if (library != NULL) {
+  if (library != nullptr) {
     if (library->GetClassLoader() != class_loader.get()) {
       // The library will be associated with class_loader. The JNI
       // spec says we can't load the same library into more than one
@@ -3276,12 +3262,12 @@
   // This can execute slowly for a large library on a busy system, so we
   // want to switch from kRunnable while it executes.  This allows the GC to ignore us.
   self->TransitionFromRunnableToSuspended(kWaitingForJniOnLoad);
-  void* handle = dlopen(path.empty() ? NULL : path.c_str(), RTLD_LAZY);
+  void* handle = dlopen(path.empty() ? nullptr : path.c_str(), RTLD_LAZY);
   self->TransitionFromSuspendedToRunnable();
 
   VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_LAZY) returned " << handle << "]";
 
-  if (handle == NULL) {
+  if (handle == nullptr) {
     *detail = dlerror();
     LOG(ERROR) << "dlopen(\"" << path << "\", RTLD_LAZY) failed: " << detail;
     return false;
@@ -3293,7 +3279,7 @@
   {
     MutexLock mu(self, libraries_lock);
     library = libraries->Get(path);
-    if (library == NULL) {  // We won race to get libraries_lock
+    if (library == nullptr) {  // We won race to get libraries_lock
       library = new SharedLibrary(path, handle, class_loader.get());
       libraries->Put(path, library);
       created_library = true;
@@ -3310,7 +3296,7 @@
 
   bool was_successful = false;
   void* sym = dlsym(handle, "JNI_OnLoad");
-  if (sym == NULL) {
+  if (sym == nullptr) {
     VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";
     was_successful = true;
   } else {
@@ -3320,14 +3306,14 @@
     // the comments in the JNI FindClass function.)
     typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
     JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
-    SirtRef<ClassLoader> old_class_loader(self, self->GetClassLoaderOverride());
+    SirtRef<mirror::ClassLoader> old_class_loader(self, self->GetClassLoaderOverride());
     self->SetClassLoaderOverride(class_loader.get());
 
     int version = 0;
     {
       ScopedThreadStateChange tsc(self, kNative);
       VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";
-      version = (*jni_on_load)(this, NULL);
+      version = (*jni_on_load)(this, nullptr);
     }
 
     self->SetClassLoaderOverride(old_class_loader.get());
@@ -3354,11 +3340,9 @@
   return was_successful;
 }
 
-void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) {
+void* JavaVMExt::FindCodeForNativeMethod(mirror::ArtMethod* m) {
   CHECK(m->IsNative());
-
-  Class* c = m->GetDeclaringClass();
-
+  mirror::Class* c = m->GetDeclaringClass();
   // If this is a static method, it could be called before the class
   // has been initialized.
   if (m->IsStatic()) {
@@ -3369,7 +3353,6 @@
   } else {
     CHECK(c->IsInitializing()) << c->GetStatus() << " " << PrettyMethod(m);
   }
-
   std::string detail;
   void* native_method;
   Thread* self = Thread::Current();
@@ -3378,7 +3361,7 @@
     native_method = libraries->FindNativeMethod(m, detail);
   }
   // Throwing can cause libraries_lock to be reacquired.
-  if (native_method == NULL) {
+  if (native_method == nullptr) {
     ThrowLocation throw_location = self->GetCurrentLocationForThrow();
     self->ThrowNewException(throw_location, "Ljava/lang/UnsatisfiedLinkError;", detail.c_str());
   }
@@ -3418,7 +3401,7 @@
 void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
                            jint method_count) {
   ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
-  if (c.get() == NULL) {
+  if (c.get() == nullptr) {
     LOG(FATAL) << "Couldn't find class: " << jni_class_name;
   }
   JNI::RegisterNativeMethods(env, c.get(), methods, method_count, false);
diff --git a/runtime/locks.cc b/runtime/locks.cc
index d08206a..246e339 100644
--- a/runtime/locks.cc
+++ b/runtime/locks.cc
@@ -33,6 +33,7 @@
 Mutex* Locks::trace_lock_ = NULL;
 Mutex* Locks::profiler_lock_ = NULL;
 Mutex* Locks::unexpected_signal_lock_ = NULL;
+Mutex* Locks::intern_table_lock_ = NULL;
 
 void Locks::Init() {
   if (logging_lock_ != NULL) {
@@ -49,6 +50,7 @@
     DCHECK(trace_lock_ != NULL);
     DCHECK(profiler_lock_ != NULL);
     DCHECK(unexpected_signal_lock_ != NULL);
+    DCHECK(intern_table_lock_ != NULL);
   } else {
     logging_lock_ = new Mutex("logging lock", kLoggingLock, true);
     abort_lock_ = new Mutex("abort lock", kAbortLock, true);
@@ -76,6 +78,8 @@
     profiler_lock_ = new Mutex("profiler lock", kProfilerLock);
     DCHECK(unexpected_signal_lock_ == NULL);
     unexpected_signal_lock_ = new Mutex("unexpected signal lock", kUnexpectedSignalLock, true);
+    DCHECK(intern_table_lock_ == NULL);
+    intern_table_lock_ = new Mutex("InternTable lock", kInternTableLock);
   }
 }
 
diff --git a/runtime/locks.h b/runtime/locks.h
index d4fbd91..2f9810d 100644
--- a/runtime/locks.h
+++ b/runtime/locks.h
@@ -44,6 +44,8 @@
   kDexFileMethodInlinerLock,
   kDexFileToMethodInlinerMapLock,
   kMarkSweepMarkStackLock,
+  kTransactionLogLock,
+  kInternTableLock,
   kDefaultMutexLevel,
   kMarkSweepLargeObjectLock,
   kPinTableLock,
@@ -163,6 +165,9 @@
   // doesn't try to hold a higher level Mutex.
   #define DEFAULT_MUTEX_ACQUIRED_AFTER ACQUIRED_AFTER(classlinker_classes_lock_)
 
+  // Guards intern table.
+  static Mutex* intern_table_lock_ ACQUIRED_AFTER(classlinker_classes_lock_);
+
   // Have an exclusive aborting thread.
   static Mutex* abort_lock_ ACQUIRED_AFTER(classlinker_classes_lock_);
 
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 35ea2b3..7c5de5e 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -113,7 +113,7 @@
 template<class T>
 inline void PrimitiveArray<T>::VisitRoots(RootCallback* callback, void* arg) {
   if (array_class_ != nullptr) {
-    array_class_ = down_cast<Class*>(callback(array_class_, arg, 0, kRootStickyClass));
+    callback(reinterpret_cast<mirror::Object**>(&array_class_), arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index c23234e..2180857 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -60,7 +60,8 @@
         CHECK(self->IsExceptionPending());
         return nullptr;
       }
-      new_array->AsObjectArray<Array>()->Set(i, sub_array);
+      // Use non-transactional mode without check.
+      new_array->AsObjectArray<Array>()->Set<false, false>(i, sub_array);
     }
   }
   return new_array.get();
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 2e123ef..7555975 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -20,6 +20,7 @@
 #include "object.h"
 #include "object_callbacks.h"
 #include "gc/heap.h"
+#include "runtime.h"
 #include "thread.h"
 
 namespace art {
@@ -60,7 +61,9 @@
 
   void SetLength(int32_t length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     CHECK_GE(length, 0);
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false, false);
+    // We use non transactional version since we can't undo this write. We also disable checking
+    // since it would fail during a transaction.
+    SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false, false);
   }
 
   static MemberOffset LengthOffset() {
@@ -144,14 +147,34 @@
   }
 
   void Set(int32_t i, T value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (Runtime::Current()->IsActiveTransaction()) {
+      Set<true>(i, value);
+    } else {
+      Set<false>(i, value);
+    }
+  }
+
+  // TODO fix thread safety analysis broken by the use of template. This should be
+  // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+  template<bool kTransactionActive, bool kCheckTransaction = true>
+  void Set(int32_t i, T value) NO_THREAD_SAFETY_ANALYSIS {
     if (LIKELY(CheckIsValidIndex(i))) {
-      SetWithoutChecks(i, value);
+      SetWithoutChecks<kTransactionActive, kCheckTransaction>(i, value);
     } else {
       DCHECK(Thread::Current()->IsExceptionPending());
     }
   }
 
-  void SetWithoutChecks(int32_t i, T value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  // TODO fix thread safety analysis broken by the use of template. This should be
+  // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+  template<bool kTransactionActive, bool kCheckTransaction = true>
+  void SetWithoutChecks(int32_t i, T value) NO_THREAD_SAFETY_ANALYSIS {
+    if (kCheckTransaction) {
+      DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+    }
+    if (kTransactionActive) {
+      Runtime::Current()->RecordWriteArray(this, i, GetWithoutChecks(i));
+    }
     DCHECK(CheckIsValidIndex(i));
     GetData()[i] = value;
   }
diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h
index 530226b..6253edd 100644
--- a/runtime/mirror/art_field-inl.h
+++ b/runtime/mirror/art_field-inl.h
@@ -37,7 +37,8 @@
 }
 
 inline void ArtField::SetDeclaringClass(Class *new_declaring_class) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_), new_declaring_class, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_),
+                        new_declaring_class, false);
 }
 
 inline uint32_t ArtField::GetAccessFlags() {
@@ -61,10 +62,11 @@
   return object->GetField32(GetOffset(), IsVolatile());
 }
 
+template<bool kTransactionActive>
 inline void ArtField::Set32(Object* object, uint32_t new_value) {
   DCHECK(object != NULL) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
-  object->SetField32(GetOffset(), new_value, IsVolatile());
+  object->SetField32<kTransactionActive>(GetOffset(), new_value, IsVolatile());
 }
 
 inline uint64_t ArtField::Get64(Object* object) {
@@ -73,10 +75,11 @@
   return object->GetField64(GetOffset(), IsVolatile());
 }
 
+template<bool kTransactionActive>
 inline void ArtField::Set64(Object* object, uint64_t new_value) {
   DCHECK(object != NULL) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
-  object->SetField64(GetOffset(), new_value, IsVolatile());
+  object->SetField64<kTransactionActive>(GetOffset(), new_value, IsVolatile());
 }
 
 inline Object* ArtField::GetObj(Object* object) {
@@ -85,10 +88,11 @@
   return object->GetFieldObject<Object>(GetOffset(), IsVolatile());
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetObj(Object* object, Object* new_value) {
   DCHECK(object != NULL) << PrettyField(this);
   DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
-  object->SetFieldObject(GetOffset(), new_value, IsVolatile());
+  object->SetFieldObject<kTransactionActive>(GetOffset(), new_value, IsVolatile());
 }
 
 inline bool ArtField::GetBoolean(Object* object) {
@@ -97,10 +101,11 @@
   return Get32(object);
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetBoolean(Object* object, bool z) {
   DCHECK_EQ(Primitive::kPrimBoolean, FieldHelper(this).GetTypeAsPrimitiveType())
       << PrettyField(this);
-  Set32(object, z);
+  Set32<kTransactionActive>(object, z);
 }
 
 inline int8_t ArtField::GetByte(Object* object) {
@@ -109,10 +114,11 @@
   return Get32(object);
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetByte(Object* object, int8_t b) {
   DCHECK_EQ(Primitive::kPrimByte, FieldHelper(this).GetTypeAsPrimitiveType())
       << PrettyField(this);
-  Set32(object, b);
+  Set32<kTransactionActive>(object, b);
 }
 
 inline uint16_t ArtField::GetChar(Object* object) {
@@ -121,10 +127,11 @@
   return Get32(object);
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetChar(Object* object, uint16_t c) {
   DCHECK_EQ(Primitive::kPrimChar, FieldHelper(this).GetTypeAsPrimitiveType())
        << PrettyField(this);
-  Set32(object, c);
+  Set32<kTransactionActive>(object, c);
 }
 
 inline int16_t ArtField::GetShort(Object* object) {
@@ -133,42 +140,45 @@
   return Get32(object);
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetShort(Object* object, int16_t s) {
   DCHECK_EQ(Primitive::kPrimShort, FieldHelper(this).GetTypeAsPrimitiveType())
        << PrettyField(this);
-  Set32(object, s);
+  Set32<kTransactionActive>(object, s);
 }
 
 inline int32_t ArtField::GetInt(Object* object) {
-#ifndef NDEBUG
-  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
-  CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
-#endif
+  if (kIsDebugBuild) {
+    Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+    CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
+  }
   return Get32(object);
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetInt(Object* object, int32_t i) {
-#ifndef NDEBUG
-  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
-  CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
-#endif
-  Set32(object, i);
+  if (kIsDebugBuild) {
+    Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+    CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
+  }
+  Set32<kTransactionActive>(object, i);
 }
 
 inline int64_t ArtField::GetLong(Object* object) {
-#ifndef NDEBUG
-  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
-  CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
-#endif
+  if (kIsDebugBuild) {
+    Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+    CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
+  }
   return Get64(object);
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetLong(Object* object, int64_t j) {
-#ifndef NDEBUG
-  Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
-  CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
-#endif
-  Set64(object, j);
+  if (kIsDebugBuild) {
+    Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+    CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
+  }
+  Set64<kTransactionActive>(object, j);
 }
 
 inline float ArtField::GetFloat(Object* object) {
@@ -179,12 +189,13 @@
   return bits.GetF();
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetFloat(Object* object, float f) {
   DCHECK_EQ(Primitive::kPrimFloat, FieldHelper(this).GetTypeAsPrimitiveType())
        << PrettyField(this);
   JValue bits;
   bits.SetF(f);
-  Set32(object, bits.GetI());
+  Set32<kTransactionActive>(object, bits.GetI());
 }
 
 inline double ArtField::GetDouble(Object* object) {
@@ -195,12 +206,13 @@
   return bits.GetD();
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetDouble(Object* object, double d) {
   DCHECK_EQ(Primitive::kPrimDouble, FieldHelper(this).GetTypeAsPrimitiveType())
        << PrettyField(this);
   JValue bits;
   bits.SetD(d);
-  Set64(object, bits.GetJ());
+  Set64<kTransactionActive>(object, bits.GetJ());
 }
 
 inline Object* ArtField::GetObject(Object* object) {
@@ -209,10 +221,11 @@
   return GetObj(object);
 }
 
+template<bool kTransactionActive>
 inline void ArtField::SetObject(Object* object, Object* l) {
   DCHECK_EQ(Primitive::kPrimNot, FieldHelper(this).GetTypeAsPrimitiveType())
        << PrettyField(this);
-  SetObj(object, l);
+  SetObj<kTransactionActive>(object, l);
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index 29aade9..7740213 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -42,20 +42,21 @@
 
 void ArtField::SetOffset(MemberOffset num_bytes) {
   DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-#if 0  // TODO enable later in boot and under !NDEBUG
-  FieldHelper fh(this);
-  Primitive::Type type = fh.GetTypeAsPrimitiveType();
-  if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) {
-    DCHECK_ALIGNED(num_bytes.Uint32Value(), 8);
+  if (kIsDebugBuild && Runtime::Current()->IsCompiler() &&
+      !Runtime::Current()->UseCompileTimeClassPath()) {
+    Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+    if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) {
+      DCHECK_ALIGNED(num_bytes.Uint32Value(), 8);
+    }
   }
-#endif
-  SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), num_bytes.Uint32Value(), false);
+  // Not called within a transaction.
+  SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), num_bytes.Uint32Value(), false);
 }
 
 void ArtField::VisitRoots(RootCallback* callback, void* arg) {
   if (java_lang_reflect_ArtField_ != nullptr) {
-    java_lang_reflect_ArtField_ = down_cast<mirror::Class*>(
-        callback(java_lang_reflect_ArtField_, arg, 0, kRootStickyClass));
+    callback(reinterpret_cast<mirror::Object**>(&java_lang_reflect_ArtField_), arg, 0,
+             kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 716b736..46287c3 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -38,7 +38,8 @@
   uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, access_flags_), new_access_flags, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, access_flags_), new_access_flags, false);
   }
 
   bool IsPublic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -58,7 +59,8 @@
   }
 
   void SetDexFieldIndex(uint32_t new_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, field_dex_idx_), new_idx, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, field_dex_idx_), new_idx, false);
   }
 
   // Offset to field within an Object.
@@ -74,30 +76,42 @@
 
   // field access, null object for static fields
   bool GetBoolean(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetBoolean(Object* object, bool z) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   int8_t GetByte(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetByte(Object* object, int8_t b) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   uint16_t GetChar(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetChar(Object* object, uint16_t c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   int16_t GetShort(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetShort(Object* object, int16_t s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   int32_t GetInt(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetInt(Object* object, int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   int64_t GetLong(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetLong(Object* object, int64_t j) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   float GetFloat(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetFloat(Object* object, float f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   double GetDouble(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetDouble(Object* object, double d) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   Object* GetObject(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetObject(Object* object, Object* l) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Raw field accesses.
   uint32_t Get32(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void Set32(Object* object, uint32_t new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   uint64_t Get64(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void Set64(Object* object, uint64_t new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   Object* GetObj(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive>
   void SetObj(Object* object, Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static Class* GetJavaLangReflectArtField() {
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 8ef3be8..d347724 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -36,7 +36,8 @@
 }
 
 inline void ArtMethod::SetDeclaringClass(Class *new_declaring_class) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_), new_declaring_class, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_),
+                        new_declaring_class, false);
 }
 
 inline uint32_t ArtMethod::GetAccessFlags() {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 67e6c7d..d5f7597 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -43,8 +43,8 @@
 
 void ArtMethod::VisitRoots(RootCallback* callback, void* arg) {
   if (java_lang_reflect_ArtMethod_ != nullptr) {
-    java_lang_reflect_ArtMethod_ = down_cast<mirror::Class*>(
-        callback(java_lang_reflect_ArtMethod_, arg, 0, kRootStickyClass));
+    callback(reinterpret_cast<mirror::Object**>(&java_lang_reflect_ArtMethod_), arg, 0,
+             kRootStickyClass);
   }
 }
 
@@ -73,18 +73,18 @@
 }
 
 void ArtMethod::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_),
-                 new_dex_cache_strings, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_),
+                        new_dex_cache_strings, false);
 }
 
 void ArtMethod::SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
-                 new_dex_cache_methods, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
+                        new_dex_cache_methods, false);
 }
 
 void ArtMethod::SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_classes) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_),
-                 new_dex_cache_classes, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_),
+                        new_dex_cache_classes, false);
 }
 
 size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) {
@@ -337,8 +337,8 @@
 #else
     SetNativeMethod(reinterpret_cast<void*>(art_work_around_app_jni_bugs));
 #endif
-    SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_),
-        reinterpret_cast<const uint8_t*>(native_method), false);
+    SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_),
+                       reinterpret_cast<const uint8_t*>(native_method), false);
   }
 }
 
@@ -349,8 +349,8 @@
 }
 
 void ArtMethod::SetNativeMethod(const void* native_method) {
-  SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_),
-      native_method, false);
+  SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_),
+                     native_method, false);
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index e678503..71cc7af 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -56,7 +56,8 @@
   uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, access_flags_), new_access_flags, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, access_flags_), new_access_flags, false);
   }
 
   // Approximate what kind of method call would be used for this method.
@@ -156,7 +157,8 @@
   }
 
   void SetMethodIndex(uint16_t new_method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_), new_method_index, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_), new_method_index, false);
   }
 
   static MemberOffset MethodIndexOffset() {
@@ -168,7 +170,8 @@
   }
 
   void SetCodeItemOffset(uint32_t new_code_off) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_code_item_offset_), new_code_off, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_code_item_offset_), new_code_off, false);
   }
 
   // Number of 32bit registers that would be required to hold all the arguments
@@ -177,7 +180,8 @@
   uint32_t GetDexMethodIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetDexMethodIndex(uint32_t new_idx) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), new_idx, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), new_idx, false);
   }
 
   ObjectArray<String>* GetDexCacheStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -216,9 +220,8 @@
   }
 
   void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter) {
-    SetFieldPtr<EntryPointFromInterpreter*>(
-        OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_),
-        entry_point_from_interpreter, false);
+    SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_),
+                       entry_point_from_interpreter, false);
   }
 
   static MemberOffset EntryPointFromPortableCompiledCodeOffset() {
@@ -230,8 +233,8 @@
   }
 
   void SetEntryPointFromPortableCompiledCode(const void* entry_point_from_portable_compiled_code) {
-    SetFieldPtr<const void*>(EntryPointFromPortableCompiledCodeOffset(),
-        entry_point_from_portable_compiled_code, false);
+    SetFieldPtr<false>(EntryPointFromPortableCompiledCodeOffset(),
+                       entry_point_from_portable_compiled_code, false);
   }
 
   static MemberOffset EntryPointFromQuickCompiledCodeOffset() {
@@ -243,8 +246,8 @@
   }
 
   void SetEntryPointFromQuickCompiledCode(const void* entry_point_from_quick_compiled_code) {
-    SetFieldPtr<const void*>(EntryPointFromQuickCompiledCodeOffset(),
-        entry_point_from_quick_compiled_code, false);
+    SetFieldPtr<false>(EntryPointFromQuickCompiledCodeOffset(),
+                       entry_point_from_quick_compiled_code, false);
   }
 
 
@@ -277,8 +280,8 @@
   }
 
   void SetMappingTable(const uint8_t* mapping_table) {
-    SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_),
-                                mapping_table, false);
+    SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_),
+                       mapping_table, false);
   }
 
   uint32_t GetOatMappingTableOffset();
@@ -292,8 +295,7 @@
   }
 
   void SetVmapTable(const uint8_t* vmap_table) {
-    SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_), vmap_table,
-        false);
+    SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_), vmap_table, false);
   }
 
   uint32_t GetOatVmapTableOffset();
@@ -304,7 +306,7 @@
     return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), false);
   }
   void SetNativeGcMap(const uint8_t* data) {
-    SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), data, false);
+    SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), data, false);
   }
 
   // When building the oat need a convenient place to stuff the offset of the native GC map.
@@ -319,8 +321,9 @@
   }
 
   void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_),
-               new_frame_size_in_bytes, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_),
+                      new_frame_size_in_bytes, false);
   }
 
   size_t GetReturnPcOffsetInBytes() {
@@ -358,8 +361,9 @@
   }
 
   void SetCoreSpillMask(uint32_t core_spill_mask) {
-    // Computed during compilation
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_), core_spill_mask, false);
+    // Computed during compilation.
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_), core_spill_mask, false);
   }
 
   uint32_t GetFpSpillMask() {
@@ -367,8 +371,9 @@
   }
 
   void SetFpSpillMask(uint32_t fp_spill_mask) {
-    // Computed during compilation
-    SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_), fp_spill_mask, false);
+    // Computed during compilation.
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_), fp_spill_mask, false);
   }
 
   // Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index a5f743b..4c2bdb0 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -64,8 +64,8 @@
   DCHECK(NULL == GetFieldObject<ObjectArray<ArtMethod> >(
       OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false));
   DCHECK_NE(0, new_direct_methods->GetLength());
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_),
-                 new_direct_methods, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_),
+                        new_direct_methods, false);
 }
 
 inline ArtMethod* Class::GetDirectMethod(int32_t i) {
@@ -77,7 +77,7 @@
   ObjectArray<ArtMethod>* direct_methods =
       GetFieldObject<ObjectArray<ArtMethod> >(
           OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
-  direct_methods->Set(i, f);
+  direct_methods->Set<false>(i, f);
 }
 
 // Returns the number of static, private, and constructor methods.
@@ -93,10 +93,10 @@
 
 inline void Class::SetVirtualMethods(ObjectArray<ArtMethod>* new_virtual_methods) {
   // TODO: we reassign virtual methods to grow the table for miranda
-  // methods.. they should really just be assigned once
+  // methods.. they should really just be assigned once.
   DCHECK_NE(0, new_virtual_methods->GetLength());
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_),
-                 new_virtual_methods, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_),
+                        new_virtual_methods, false);
 }
 
 inline uint32_t Class::NumVirtualMethods() {
@@ -118,7 +118,7 @@
   ObjectArray<ArtMethod>* virtual_methods =
       GetFieldObject<ObjectArray<ArtMethod> >(
           OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
-  virtual_methods->Set(i, f);
+  virtual_methods->Set<false>(i, f);
 }
 
 inline ObjectArray<ArtMethod>* Class::GetVTable() {
@@ -132,7 +132,7 @@
 }
 
 inline void Class::SetVTable(ObjectArray<ArtMethod>* new_vtable) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false);
 }
 
 inline ObjectArray<ArtMethod>* Class::GetImTable() {
@@ -140,7 +140,7 @@
 }
 
 inline void Class::SetImTable(ObjectArray<ArtMethod>* new_imtable) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false);
 }
 
 inline bool Class::Implements(Class* klass) {
@@ -347,7 +347,7 @@
 }
 
 inline void Class::SetIfTable(IfTable* new_iftable) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false);
 }
 
 inline ObjectArray<ArtField>* Class::GetIFields() {
@@ -359,7 +359,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(NULL == GetFieldObject<ObjectArray<ArtField> >(
       OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false));
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields, false);
 }
 
 inline ObjectArray<ArtField>* Class::GetSFields() {
@@ -371,7 +371,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(NULL == GetFieldObject<ObjectArray<ArtField> >(
       OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false));
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields, false);
 }
 
 inline uint32_t Class::NumStaticFields() {
@@ -387,7 +387,7 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ObjectArray<ArtField>* sfields= GetFieldObject<ObjectArray<ArtField> >(
       OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
-  sfields->Set(i, f);
+  sfields->Set<false>(i, f);
 }
 
 inline uint32_t Class::NumInstanceFields() {
@@ -403,12 +403,16 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ObjectArray<ArtField>* ifields= GetFieldObject<ObjectArray<ArtField> >(
       OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
-  ifields->Set(i, f);
+  ifields->Set<false>(i, f);
 }
 
 inline void Class::SetVerifyErrorClass(Class* klass) {
   CHECK(klass != NULL) << PrettyClass(this);
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
+  } else {
+    SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
+  }
 }
 
 inline uint32_t Class::GetAccessFlags() {
@@ -425,7 +429,11 @@
   return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Class, name_), false);
 }
 inline void Class::SetName(String* name) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false);
+  } else {
+    SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false);
+  }
 }
 
 inline void Class::CheckObjectAlloc() {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 99a35e3..3208de9 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -52,8 +52,7 @@
 
 void Class::VisitRoots(RootCallback* callback, void* arg) {
   if (java_lang_Class_ != nullptr) {
-    java_lang_Class_ = down_cast<Class*>(
-        callback(java_lang_Class_, arg, 0, kRootStickyClass));
+    callback(reinterpret_cast<mirror::Object**>(&java_lang_Class_), arg, 0, kRootStickyClass);
   }
 }
 
@@ -113,7 +112,11 @@
     self->SetException(gc_safe_throw_location, old_exception.get());
   }
   CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
-  SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+  } else {
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+  }
   // Classes that are being resolved or initialized need to notify waiters that the class status
   // changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass.
   if ((old_status >= kStatusResolved || new_status >= kStatusResolved) &&
@@ -123,7 +126,7 @@
 }
 
 void Class::SetDexCache(DexCache* new_dex_cache) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), new_dex_cache, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), new_dex_cache, false);
 }
 
 void Class::SetClassSize(uint32_t new_class_size) {
@@ -131,7 +134,8 @@
     DumpClass(LOG(ERROR), kDumpClassFullDetail);
     CHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this);
   }
-  SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false);
+  // Not called within a transaction.
+  SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false);
 }
 
 // Return the class' name. The exact format is bizarre, but it's the specified behavior for
@@ -254,8 +258,9 @@
     }
     CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets), count);
   }
-  SetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
-             new_reference_offsets, false);
+  // Not called within a transaction.
+  SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
+                    new_reference_offsets, false);
 }
 
 void Class::SetReferenceStaticOffsets(uint32_t new_reference_offsets) {
@@ -265,8 +270,9 @@
     CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets),
              NumReferenceStaticFieldsDuringLinking());
   }
-  SetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_),
-             new_reference_offsets, false);
+  // Not called within a transaction.
+  SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_),
+                    new_reference_offsets, false);
 }
 
 bool Class::IsInSamePackage(const StringPiece& descriptor1, const StringPiece& descriptor2) {
@@ -332,7 +338,11 @@
 }
 
 void Class::SetClassLoader(ClassLoader* new_class_loader) {
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
+  } else {
+    SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
+  }
 }
 
 ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 82c8264..cd8504b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -174,7 +174,8 @@
   uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags, false);
   }
 
   // Returns true if the class is an interface.
@@ -275,7 +276,7 @@
 
   void SetPrimitiveType(Primitive::Type new_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t));
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type, false);
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type, false);
   }
 
   // Returns true if the class is a primitive type.
@@ -357,7 +358,11 @@
   void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(GetComponentType() == NULL);
     DCHECK(new_component_type != NULL);
-    SetFieldObject(ComponentTypeOffset(), new_component_type, false);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      SetFieldObject<true>(ComponentTypeOffset(), new_component_type, false);
+    } else {
+      SetFieldObject<false>(ComponentTypeOffset(), new_component_type, false);
+    }
   }
 
   size_t GetComponentSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -406,7 +411,8 @@
 
   void SetObjectSize(uint32_t new_object_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(!IsVariableSize());
-    return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size, false);
+    // Not called within a transaction.
+    return SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size, false);
   }
 
   // Returns true if this class is in the same packages as that class.
@@ -499,7 +505,7 @@
                                                    false);
     DCHECK(old_super_class == nullptr || old_super_class == new_super_class);
     DCHECK(new_super_class != nullptr);
-    SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), new_super_class, false);
+    SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), new_super_class, false);
   }
 
   bool HasSuperClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -672,7 +678,9 @@
   }
 
   void SetNumReferenceInstanceFields(uint32_t new_num) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), new_num, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), new_num,
+                      false);
   }
 
   uint32_t GetReferenceInstanceOffsets() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -700,7 +708,8 @@
   }
 
   void SetNumReferenceStaticFields(uint32_t new_num) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num, false);
   }
 
   // Gets the static fields of the class.
@@ -763,7 +772,13 @@
   }
 
   void SetClinitThreadId(pid_t new_clinit_thread_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id, false);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id,
+                       false);
+    } else {
+      SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id,
+                        false);
+    }
   }
 
   Class* GetVerifyErrorClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -776,7 +791,8 @@
   }
 
   void SetDexClassDefIndex(uint16_t class_def_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false);
   }
 
   uint16_t GetDexTypeIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -784,7 +800,8 @@
   }
 
   void SetDexTypeIndex(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx, false);
+    // Not called within a transaction.
+    SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx, false);
   }
 
   static Class* GetJavaLangClass() {
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index fa0900c..0a77db3 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -44,12 +44,12 @@
   CHECK(resolved_methods != nullptr);
   CHECK(resolved_fields != nullptr);
 
-  SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location, false);
-  SetFieldObject(StringsOffset(), strings, false);
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), resolved_types, false);
-  SetFieldObject(ResolvedMethodsOffset(), resolved_methods, false);
-  SetFieldObject(ResolvedFieldsOffset(), resolved_fields, false);
+  SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location, false);
+  SetFieldObject<false>(StringsOffset(), strings, false);
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), resolved_types, false);
+  SetFieldObject<false>(ResolvedMethodsOffset(), resolved_methods, false);
+  SetFieldObject<false>(ResolvedFieldsOffset(), resolved_fields, false);
 
   Runtime* runtime = Runtime::Current();
   if (runtime->HasResolutionMethod()) {
@@ -57,7 +57,7 @@
     ArtMethod* trampoline = runtime->GetResolutionMethod();
     size_t length = resolved_methods->GetLength();
     for (size_t i = 0; i < length; i++) {
-      resolved_methods->SetWithoutChecks(i, trampoline);
+      resolved_methods->SetWithoutChecks<false>(i, trampoline);
     }
   }
 }
@@ -69,7 +69,7 @@
   size_t length = resolved_methods->GetLength();
   for (size_t i = 0; i < length; i++) {
     if (resolved_methods->GetWithoutChecks(i) == nullptr) {
-      resolved_methods->SetWithoutChecks(i, trampoline);
+      resolved_methods->SetWithoutChecks<false>(i, trampoline);
     }
   }
 }
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 99529f0..843f860 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -90,6 +90,7 @@
 
   void SetResolvedString(uint32_t string_idx, String* resolved)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // TODO default transaction support.
     GetStrings()->Set(string_idx, resolved);
   }
 
@@ -99,6 +100,7 @@
 
   void SetResolvedType(uint32_t type_idx, Class* resolved)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    // TODO default transaction support.
     GetResolvedTypes()->Set(type_idx, resolved);
   }
 
@@ -140,7 +142,7 @@
   }
 
   void SetDexFile(const DexFile* dex_file) {
-    return SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
+    return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
   }
 
  private:
diff --git a/runtime/mirror/iftable-inl.h b/runtime/mirror/iftable-inl.h
index 9d5fa74..ec3e514 100644
--- a/runtime/mirror/iftable-inl.h
+++ b/runtime/mirror/iftable-inl.h
@@ -26,7 +26,7 @@
   DCHECK(interface != NULL);
   DCHECK(interface->IsInterface());
   DCHECK(Get((i * kMax) + kInterface) == NULL);
-  Set((i * kMax) + kInterface, interface);
+  Set<false>((i * kMax) + kInterface, interface);
 }
 
 }  // namespace mirror
diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h
index be83d03..bb4cd41 100644
--- a/runtime/mirror/iftable.h
+++ b/runtime/mirror/iftable.h
@@ -52,7 +52,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK(new_ma != NULL);
     DCHECK(Get((i * kMax) + kMethodArray) == NULL);
-    Set((i * kMax) + kMethodArray, new_ma);
+    Set<false>((i * kMax) + kMethodArray, new_ma);
   }
 
   size_t Count() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index b994354..70291c1 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -40,7 +40,10 @@
   // new_klass may be NULL prior to class linker initialization.
   // We don't mark the card as this occurs as part of object allocation. Not all objects have
   // backing cards, such as large objects.
-  SetFieldObjectWithoutWriteBarrier(OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass, false, false);
+  // We use non transactional version since we can't undo this write. We also disable checking as
+  // we may run in transaction mode here.
+  SetFieldObjectWithoutWriteBarrier<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, klass_),
+                                                  new_klass, false, false);
 }
 
 inline LockWord Object::GetLockWord() {
@@ -48,20 +51,22 @@
 }
 
 inline void Object::SetLockWord(LockWord new_val) {
-  SetField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue(), true);
+  // Force use of non-transactional mode and do not check.
+  SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue(), true);
 }
 
 inline bool Object::CasLockWord(LockWord old_val, LockWord new_val) {
-  return CasField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(),
-                    new_val.GetValue());
+  // Force use of non-transactional mode and do not check.
+  return CasField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(),
+                                  new_val.GetValue());
 }
 
 inline uint32_t Object::GetLockOwnerThreadId() {
   return Monitor::GetLockOwnerThreadId(this);
 }
 
-inline void Object::MonitorEnter(Thread* self) {
-  Monitor::MonitorEnter(self, this);
+inline mirror::Object* Object::MonitorEnter(Thread* self) {
+  return Monitor::MonitorEnter(self, this);
 }
 
 inline bool Object::MonitorExit(Thread* self) {
@@ -199,6 +204,18 @@
   return down_cast<LongArray*>(this);
 }
 
+inline FloatArray* Object::AsFloatArray() {
+  DCHECK(GetClass()->IsArrayClass());
+  DCHECK(GetClass()->GetComponentType()->IsPrimitiveFloat());
+  return down_cast<FloatArray*>(this);
+}
+
+inline DoubleArray* Object::AsDoubleArray() {
+  DCHECK(GetClass()->IsArrayClass());
+  DCHECK(GetClass()->GetComponentType()->IsPrimitiveDouble());
+  return down_cast<DoubleArray*>(this);
+}
+
 inline String* Object::AsString() {
   DCHECK(GetClass()->IsStringClass());
   return down_cast<String*>(this);
@@ -253,8 +270,16 @@
   }
 }
 
+template<bool kTransactionActive, bool kCheckTransaction>
 inline void Object::SetField32(MemberOffset field_offset, int32_t new_value, bool is_volatile,
                                bool this_is_valid) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField32(this, field_offset, GetField32(field_offset, is_volatile),
+                                           is_volatile);
+  }
   if (this_is_valid) {
     VerifyObject(this);
   }
@@ -269,7 +294,14 @@
   }
 }
 
+template<bool kTransactionActive, bool kCheckTransaction>
 inline bool Object::CasField32(MemberOffset field_offset, int32_t old_value, int32_t new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
+  }
   VerifyObject(this);
   byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
   volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw_addr);
@@ -289,8 +321,16 @@
   }
 }
 
+template<bool kTransactionActive, bool kCheckTransaction>
 inline void Object::SetField64(MemberOffset field_offset, int64_t new_value, bool is_volatile,
                                bool this_is_valid) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField64(this, field_offset, GetField64(field_offset, is_volatile),
+                                           is_volatile);
+  }
   if (this_is_valid) {
     VerifyObject(this);
   }
@@ -309,7 +349,14 @@
   }
 }
 
+template<bool kTransactionActive, bool kCheckTransaction>
 inline bool Object::CasField64(MemberOffset field_offset, int64_t old_value, int64_t new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteField64(this, field_offset, old_value, true);
+  }
   VerifyObject(this);
   byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
   volatile int64_t* addr = reinterpret_cast<volatile int64_t*>(raw_addr);
@@ -331,8 +378,17 @@
   return result;
 }
 
+template<bool kTransactionActive, bool kCheckTransaction>
 inline void Object::SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value,
                                                       bool is_volatile, bool this_is_valid) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteFieldReference(this, field_offset,
+                                                  GetFieldObject<Object>(field_offset, is_volatile),
+                                                  true);
+  }
   if (this_is_valid) {
     VerifyObject(this);
   }
@@ -349,16 +405,26 @@
   }
 }
 
+template<bool kTransactionActive, bool kCheckTransaction>
 inline void Object::SetFieldObject(MemberOffset field_offset, Object* new_value, bool is_volatile,
                                    bool this_is_valid) {
-  SetFieldObjectWithoutWriteBarrier(field_offset, new_value, is_volatile, this_is_valid);
+  SetFieldObjectWithoutWriteBarrier<kTransactionActive, kCheckTransaction>(field_offset, new_value,
+                                                                           is_volatile,
+                                                                           this_is_valid);
   if (new_value != nullptr) {
     CheckFieldAssignment(field_offset, new_value);
     Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value);
   }
 }
 
+template<bool kTransactionActive, bool kCheckTransaction>
 inline bool Object::CasFieldObject(MemberOffset field_offset, Object* old_value, Object* new_value) {
+  if (kCheckTransaction) {
+    DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+  }
+  if (kTransactionActive) {
+    Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true);
+  }
   VerifyObject(this);
   byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
   volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw_addr);
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index c42750f..eb118c7 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -23,6 +23,7 @@
 #include "cutils/atomic-inline.h"
 #include "object_reference.h"
 #include "offsets.h"
+#include "runtime.h"
 
 namespace art {
 
@@ -92,7 +93,7 @@
   bool CasLockWord(LockWord old_val, LockWord new_val) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   uint32_t GetLockOwnerThreadId();
 
-  void MonitorEnter(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+  mirror::Object* MonitorEnter(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCK_FUNCTION(monitor_lock_);
 
   bool MonitorExit(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -130,6 +131,9 @@
   IntArray* AsIntArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   LongArray* AsLongArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  FloatArray* AsFloatArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  DoubleArray* AsDoubleArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   String* AsString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Throwable* AsThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -155,12 +159,15 @@
   // Accessor for Java type fields.
   template<class T> T* GetFieldObject(MemberOffset field_offset, bool is_volatile)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true>
   void SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value,
                                          bool is_volatile, bool this_is_valid = true)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true>
   void SetFieldObject(MemberOffset field_offset, Object* new_value, bool is_volatile,
                       bool this_is_valid = true)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  template<bool kTransactionActive, bool kCheckTransaction = true>
   bool CasFieldObject(MemberOffset field_offset, Object* old_value, Object* new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -172,27 +179,35 @@
 
   int32_t GetField32(MemberOffset field_offset, bool is_volatile);
 
+  template<bool kTransactionActive, bool kCheckTransaction = true>
   void SetField32(MemberOffset field_offset, int32_t new_value, bool is_volatile,
                   bool this_is_valid = true);
 
+  template<bool kTransactionActive, bool kCheckTransaction = true>
   bool CasField32(MemberOffset field_offset, int32_t old_value, int32_t new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   int64_t GetField64(MemberOffset field_offset, bool is_volatile);
 
+  template<bool kTransactionActive, bool kCheckTransaction = true>
   void SetField64(MemberOffset field_offset, int64_t new_value, bool is_volatile,
                   bool this_is_valid = true);
 
+  template<bool kTransactionActive, bool kCheckTransaction = true>
   bool CasField64(MemberOffset field_offset, int64_t old_value, int64_t new_value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<typename T>
+  template<bool kTransactionActive, bool kCheckTransaction = true, typename T>
   void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile,
                    bool this_is_valid = true) {
 #ifndef __LP64__
-    SetField32(field_offset, reinterpret_cast<int32_t>(new_value), is_volatile, this_is_valid);
+    SetField32<kTransactionActive, kCheckTransaction>(field_offset,
+                                                      reinterpret_cast<int32_t>(new_value),
+                                                      is_volatile, this_is_valid);
 #else
-    SetField64(field_offset, reinterpret_cast<int64_t>(new_value), is_volatile, this_is_valid);
+    SetField64<kTransactionActive, kCheckTransaction>(field_offset,
+                                                      reinterpret_cast<int64_t>(new_value),
+                                                      is_volatile, this_is_valid);
 #endif
   }
 
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index c342479..521b6ce 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -72,26 +72,39 @@
 
 template<class T>
 inline void ObjectArray<T>::Set(int32_t i, T* object) {
+  if (Runtime::Current()->IsActiveTransaction()) {
+    Set<true>(i, object);
+  } else {
+    Set<false>(i, object);
+  }
+}
+
+template<class T>
+template<bool kTransactionActive, bool kCheckTransaction>
+inline void ObjectArray<T>::Set(int32_t i, T* object) {
   if (LIKELY(CheckIsValidIndex(i) && CheckAssignable(object))) {
-    SetFieldObject(OffsetOfElement(i), object, false);
+    SetFieldObject<kTransactionActive, kCheckTransaction>(OffsetOfElement(i), object, false);
   } else {
     DCHECK(Thread::Current()->IsExceptionPending());
   }
 }
 
 template<class T>
+template<bool kTransactionActive, bool kCheckTransaction>
 inline void ObjectArray<T>::SetWithoutChecks(int32_t i, T* object) {
   DCHECK(CheckIsValidIndex(i));
   DCHECK(CheckAssignable(object));
-  SetFieldObject(OffsetOfElement(i), object, false);
+  SetFieldObject<kTransactionActive, kCheckTransaction>(OffsetOfElement(i), object, false);
 }
 
 template<class T>
+template<bool kTransactionActive, bool kCheckTransaction>
 inline void ObjectArray<T>::SetWithoutChecksAndWriteBarrier(int32_t i, T* object) {
   DCHECK(CheckIsValidIndex(i));
   // TODO:  enable this check. It fails when writing the image in ImageWriter::FixupObjectArray.
   // DCHECK(CheckAssignable(object));
-  SetFieldObjectWithoutWriteBarrier(OffsetOfElement(i), object, false);
+  SetFieldObjectWithoutWriteBarrier<kTransactionActive, kCheckTransaction>(OffsetOfElement(i),
+                                                                           object, false);
 }
 
 template<class T>
@@ -164,15 +177,15 @@
     o = src->GetWithoutChecks(src_pos + i);
     if (o == nullptr) {
       // Null is always assignable.
-      SetWithoutChecks(dst_pos + i, nullptr);
+      SetWithoutChecks<false>(dst_pos + i, nullptr);
     } else {
       // TODO: use the underlying class reference to avoid uncompression when not necessary.
       Class* o_class = o->GetClass();
       if (LIKELY(lastAssignableElementClass == o_class)) {
-        SetWithoutChecks(dst_pos + i, o);
+        SetWithoutChecks<false>(dst_pos + i, o);
       } else if (LIKELY(dst_class->IsAssignableFrom(o_class))) {
         lastAssignableElementClass = o_class;
-        SetWithoutChecks(dst_pos + i, o);
+        SetWithoutChecks<false>(dst_pos + i, o);
       } else {
         // Can't put this element into the array, break to perform write-barrier and throw
         // exception.
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index 347494e..668b276 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -40,12 +40,20 @@
   bool CheckAssignable(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void Set(int32_t i, T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // TODO fix thread safety analysis: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+  template<bool kTransactionActive, bool kCheckTransaction = true>
+  void Set(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
 
   // Set element without bound and element type checks, to be used in limited
-  // circumstances, such as during boot image writing
-  void SetWithoutChecks(int32_t i, T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SetWithoutChecksAndWriteBarrier(int32_t i, T* object)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  // circumstances, such as during boot image writing.
+  // TODO fix thread safety analysis broken by the use of template. This should be
+  // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+  template<bool kTransactionActive, bool kCheckTransaction = true>
+  void SetWithoutChecks(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
+  // TODO fix thread safety analysis broken by the use of template. This should be
+  // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+  template<bool kTransactionActive, bool kCheckTransaction = true>
+  void SetWithoutChecksAndWriteBarrier(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
 
   T* GetWithoutChecks(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index db9723b..40c3748 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -116,10 +116,10 @@
   EXPECT_EQ(2, oa->GetLength());
   EXPECT_TRUE(oa->Get(0) == NULL);
   EXPECT_TRUE(oa->Get(1) == NULL);
-  oa->Set(0, oa.get());
+  oa->Set<false>(0, oa.get());
   EXPECT_TRUE(oa->Get(0) == oa.get());
   EXPECT_TRUE(oa->Get(1) == NULL);
-  oa->Set(1, oa.get());
+  oa->Set<false>(1, oa.get());
   EXPECT_TRUE(oa->Get(0) == oa.get());
   EXPECT_TRUE(oa->Get(1) == oa.get());
 
@@ -235,12 +235,12 @@
 
   SirtRef<Class> c(soa.Self(), class_linker_->FindSystemClass("I"));
   SirtRef<IntArray> dims(soa.Self(), IntArray::Alloc(soa.Self(), 1));
-  dims->Set(0, 1);
+  dims->Set<false>(0, 1);
   Array* multi = Array::CreateMultiArray(soa.Self(), c, dims);
   EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass("[I"));
   EXPECT_EQ(1, multi->GetLength());
 
-  dims->Set(0, -1);
+  dims->Set<false>(0, -1);
   multi = Array::CreateMultiArray(soa.Self(), c, dims);
   EXPECT_TRUE(soa.Self()->IsExceptionPending());
   EXPECT_EQ(PrettyDescriptor(soa.Self()->GetException(NULL)->GetClass()),
@@ -250,8 +250,8 @@
   dims.reset(IntArray::Alloc(soa.Self(), 2));
   for (int i = 1; i < 20; ++i) {
     for (int j = 0; j < 20; ++j) {
-      dims->Set(0, i);
-      dims->Set(1, j);
+      dims->Set<false>(0, i);
+      dims->Set<false>(1, j);
       multi = Array::CreateMultiArray(soa.Self(), c, dims);
       EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass("[[I"));
       EXPECT_EQ(i, multi->GetLength());
@@ -301,10 +301,10 @@
   EXPECT_TRUE(s0 != NULL);
 
   SirtRef<CharArray> char_array(soa.Self(), CharArray::Alloc(soa.Self(), 0));
-  field->SetObj(field->GetDeclaringClass(), char_array.get());
+  field->SetObj<false>(field->GetDeclaringClass(), char_array.get());
   EXPECT_EQ(char_array.get(), field->GetObj(klass));
 
-  field->SetObj(field->GetDeclaringClass(), NULL);
+  field->SetObj<false>(field->GetDeclaringClass(), NULL);
   EXPECT_EQ(NULL, field->GetObj(klass));
 
   // TODO: more exhaustive tests of all 6 cases of ArtField::*FromCode
@@ -387,8 +387,8 @@
   EXPECT_EQ(string->GetLength(), 7);
   EXPECT_EQ(string->GetUtfLength(), 7);
 
-  string->SetOffset(2);
-  string->SetCount(5);
+  string->SetOffset<false>(2);
+  string->SetCount<false>(5);
   EXPECT_TRUE(string->Equals("droid"));
   EXPECT_EQ(string->GetLength(), 5);
   EXPECT_EQ(string->GetUtfLength(), 5);
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index 2e33198..02a396a 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -46,22 +46,32 @@
   StackTraceElement* trace =
       down_cast<StackTraceElement*>(GetStackTraceElement()->AllocObject(self));
   if (LIKELY(trace != NULL)) {
-    trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_),
-                          declaring_class.get(), false);
-    trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_),
-                          method_name.get(), false);
-    trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_),
-                          file_name.get(), false);
-    trace->SetField32(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_),
-                      line_number, false);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      trace->Init<true>(declaring_class, method_name, file_name, line_number);
+    } else {
+      trace->Init<false>(declaring_class, method_name, file_name, line_number);
+    }
   }
   return trace;
 }
 
+template<bool kTransactionActive>
+void StackTraceElement::Init(SirtRef<String>& declaring_class, SirtRef<String>& method_name,
+                             SirtRef<String>& file_name, int32_t line_number) {
+  SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_),
+                                     declaring_class.get(), false);
+  SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_),
+                                     method_name.get(), false);
+  SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_),
+                                     file_name.get(), false);
+  SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_),
+                                 line_number, false);
+}
+
 void StackTraceElement::VisitRoots(RootCallback* callback, void* arg) {
   if (java_lang_StackTraceElement_ != nullptr) {
-    java_lang_StackTraceElement_ = down_cast<Class*>(
-        callback(java_lang_StackTraceElement_, arg, 0, kRootStickyClass));
+    callback(reinterpret_cast<mirror::Object**>(&java_lang_StackTraceElement_), arg, 0,
+             kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 51817f6..779ec4b 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -67,6 +67,11 @@
   HeapReference<String> method_name_;
   int32_t line_number_;
 
+  template<bool kTransactionActive>
+  void Init(SirtRef<String>& declaring_class, SirtRef<String>& method_name,
+            SirtRef<String>& file_name, int32_t line_number)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   static Class* GetStackTraceElement() {
     DCHECK(java_lang_StackTraceElement_ != NULL);
     return java_lang_StackTraceElement_;
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index 6f4ead9..3f35210 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -33,7 +33,7 @@
   return GetFieldObject<CharArray>(ValueOffset(), false);
 }
 
-void String::ComputeHashCode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+void String::ComputeHashCode() {
   SetHashCode(ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength()));
 }
 
@@ -59,9 +59,10 @@
   return -1;
 }
 
-void String::SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+template<bool kTransactionActive>
+void String::SetArray(CharArray* new_array) {
   DCHECK(new_array != NULL);
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(String, array_), new_array, false);
+  SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(String, array_), new_array, false);
 }
 
 // TODO: get global references for these
@@ -169,8 +170,13 @@
   // Hold reference in case AllocObject causes GC.
   String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self));
   if (LIKELY(string != nullptr)) {
-    string->SetArray(array.get());
-    string->SetCount(array->GetLength());
+    if (Runtime::Current()->IsActiveTransaction()) {
+      string->SetArray<true>(array.get());
+      string->SetCount<true>(array->GetLength());
+    } else {
+      string->SetArray<false>(array.get());
+      string->SetCount<false>(array->GetLength());
+    }
   }
   return string;
 }
@@ -282,7 +288,7 @@
 
 void String::VisitRoots(RootCallback* callback, void* arg) {
   if (java_lang_String_ != nullptr) {
-    java_lang_String_ = down_cast<Class*>(callback(java_lang_String_, arg, 0, kRootStickyClass));
+    callback(reinterpret_cast<mirror::Object**>(&java_lang_String_), arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 57ec314..1340e7d 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -112,19 +112,23 @@
 
  private:
   void SetHashCode(int32_t new_hash_code) {
+    // Hash code is invariant so use non-transactional mode. Also disable check as we may run inside
+    // a transaction.
     DCHECK_EQ(0, GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), false));
-    SetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), new_hash_code, false);
+    SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), new_hash_code, false);
   }
 
+  template<bool kTransactionActive>
   void SetCount(int32_t new_count) {
     DCHECK_LE(0, new_count);
-    SetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false);
+    SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false);
   }
 
+  template<bool kTransactionActive>
   void SetOffset(int32_t new_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     DCHECK_LE(0, new_offset);
     DCHECK_GE(GetLength(), new_offset);
-    SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
+    SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
   }
 
   static String* Alloc(Thread* self, int32_t utf16_length)
@@ -133,6 +137,7 @@
   static String* Alloc(Thread* self, const SirtRef<CharArray>& array)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template<bool kTransactionActive>
   void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index a57bd43..4c53993 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -38,7 +38,11 @@
   Throwable* current_cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_),
                                                        false);
   CHECK(current_cause == NULL || current_cause == this);
-  SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false);
+  if (Runtime::Current()->IsActiveTransaction()) {
+    SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false);
+  } else {
+    SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false);
+  }
 }
 
 bool Throwable::IsCheckedException() {
@@ -95,8 +99,7 @@
 
 void Throwable::VisitRoots(RootCallback* callback, void* arg) {
   if (java_lang_Throwable_ != nullptr) {
-    java_lang_Throwable_ = down_cast<Class*>(callback(java_lang_Throwable_, arg, 0,
-                                                      kRootStickyClass));
+    callback(reinterpret_cast<mirror::Object**>(&java_lang_Throwable_), arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index de71957..c1438d7 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -31,7 +31,13 @@
 class MANAGED Throwable : public Object {
  public:
   void SetDetailMessage(String* new_detail_message) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message, false);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message,
+                           false);
+    } else {
+      SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message,
+                            false);
+    }
   }
   String* GetDetailMessage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), false);
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 85f3a09..64794fe 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -650,7 +650,7 @@
   }
 }
 
-void Monitor::MonitorEnter(Thread* self, mirror::Object* obj) {
+mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) {
   DCHECK(self != NULL);
   DCHECK(obj != NULL);
   uint32_t thread_id = self->GetThreadId();
@@ -663,7 +663,7 @@
         LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0));
         if (sirt_obj->CasLockWord(lock_word, thin_locked)) {
           QuasiAtomic::MembarLoadLoad();
-          return;  // Success!
+          return sirt_obj.get();  // Success!
         }
         continue;  // Go again.
       }
@@ -675,7 +675,7 @@
           if (LIKELY(new_count <= LockWord::kThinLockMaxCount)) {
             LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count));
             sirt_obj->SetLockWord(thin_locked);
-            return;  // Success!
+            return sirt_obj.get();  // Success!
           } else {
             // We'd overflow the recursion count, so inflate the monitor.
             InflateThinLocked(self, sirt_obj, lock_word, 0);
@@ -696,7 +696,7 @@
       case LockWord::kFatLocked: {
         Monitor* mon = lock_word.FatLockMonitor();
         mon->Lock(self);
-        return;  // Success!
+        return sirt_obj.get();  // Success!
       }
       case LockWord::kHashCode: {
         // Inflate with the existing hashcode.
@@ -705,10 +705,11 @@
       }
       default: {
         LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
-        return;
+        return sirt_obj.get();
       }
     }
   }
+  return sirt_obj.get();
 }
 
 bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) {
diff --git a/runtime/monitor.h b/runtime/monitor.h
index ca95e0b..d0a3a2e 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -57,7 +57,7 @@
   static uint32_t GetLockOwnerThreadId(mirror::Object* obj)
       NO_THREAD_SAFETY_ANALYSIS;  // TODO: Reading lock owner without holding lock is racy.
 
-  static void MonitorEnter(Thread* thread, mirror::Object* obj)
+  static mirror::Object* MonitorEnter(Thread* thread, mirror::Object* obj)
       EXCLUSIVE_LOCK_FUNCTION(monitor_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static bool MonitorExit(Thread* thread, mirror::Object* obj)
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 5267069..def3292 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -181,14 +181,12 @@
 
 typedef std::map<std::string, mirror::String*> StringTable;
 
-static mirror::Object* PreloadDexCachesStringsCallback(mirror::Object* root, void* arg,
-                                                       uint32_t /*thread_id*/,
-                                                       RootType /*root_type*/)
+static void PreloadDexCachesStringsCallback(mirror::Object** root, void* arg,
+                                            uint32_t /*thread_id*/, RootType /*root_type*/)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   StringTable& table = *reinterpret_cast<StringTable*>(arg);
-  mirror::String* string = const_cast<mirror::Object*>(root)->AsString();
+  mirror::String* string = const_cast<mirror::Object*>(*root)->AsString();
   table[string->ToModifiedUtf8()] = string;
-  return root;
 }
 
 // Based on ClassLinker::ResolveString.
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 269a4a3..40aebfa 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -183,32 +183,32 @@
   o = sirt_obj.get();
   switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
   case Primitive::kPrimBoolean:
-    f->SetBoolean(o, new_value.GetZ());
+    f->SetBoolean<false>(o, new_value.GetZ());
     break;
   case Primitive::kPrimByte:
-    f->SetByte(o, new_value.GetB());
+    f->SetByte<false>(o, new_value.GetB());
     break;
   case Primitive::kPrimChar:
-    f->SetChar(o, new_value.GetC());
+    f->SetChar<false>(o, new_value.GetC());
     break;
   case Primitive::kPrimDouble:
-    f->SetDouble(o, new_value.GetD());
+    f->SetDouble<false>(o, new_value.GetD());
     break;
   case Primitive::kPrimFloat:
-    f->SetFloat(o, new_value.GetF());
+    f->SetFloat<false>(o, new_value.GetF());
     break;
   case Primitive::kPrimInt:
-    f->SetInt(o, new_value.GetI());
+    f->SetInt<false>(o, new_value.GetI());
     break;
   case Primitive::kPrimLong:
-    f->SetLong(o, new_value.GetJ());
+    f->SetLong<false>(o, new_value.GetJ());
     break;
   case Primitive::kPrimShort:
-    f->SetShort(o, new_value.GetS());
+    f->SetShort<false>(o, new_value.GetS());
     break;
   case Primitive::kPrimNot:
     if (allow_references) {
-      f->SetObject(o, new_value.GetL());
+      f->SetObject<false>(o, new_value.GetL());
       break;
     }
     // Else fall through to report an error.
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 6727862..ad0f317 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -27,7 +27,8 @@
                                          jint expectedValue, jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  bool success = obj->CasField32(MemberOffset(offset), expectedValue, newValue);
+  // JNI must use non transactional mode.
+  bool success = obj->CasField32<false>(MemberOffset(offset), expectedValue, newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -35,7 +36,8 @@
                                           jlong expectedValue, jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  bool success = obj->CasField64(MemberOffset(offset), expectedValue, newValue);
+  // JNI must use non transactional mode.
+  bool success = obj->CasField64<false>(MemberOffset(offset), expectedValue, newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -45,7 +47,8 @@
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
   mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
-  bool success = obj->CasFieldObject(MemberOffset(offset), expectedValue, newValue);
+  // JNI must use non transactional mode.
+  bool success = obj->CasFieldObject<false>(MemberOffset(offset), expectedValue, newValue);
   return success ? JNI_TRUE : JNI_FALSE;
 }
 
@@ -64,14 +67,16 @@
 static void Unsafe_putInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  obj->SetField32(MemberOffset(offset), newValue, false);
+  // JNI must use non transactional mode.
+  obj->SetField32<false>(MemberOffset(offset), newValue, false);
 }
 
 static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                   jint newValue) {
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  obj->SetField32(MemberOffset(offset), newValue, true);
+  // JNI must use non transactional mode.
+  obj->SetField32<false>(MemberOffset(offset), newValue, true);
 }
 
 static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -79,7 +84,8 @@
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   QuasiAtomic::MembarStoreStore();
-  obj->SetField32(MemberOffset(offset), newValue, false);
+  // JNI must use non transactional mode.
+  obj->SetField32<false>(MemberOffset(offset), newValue, false);
 }
 
 static jlong Unsafe_getLong(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
@@ -97,14 +103,16 @@
 static void Unsafe_putLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  obj->SetField64(MemberOffset(offset), newValue, false);
+  // JNI must use non transactional mode.
+  obj->SetField64<false>(MemberOffset(offset), newValue, false);
 }
 
 static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
                                    jlong newValue) {
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
-  obj->SetField64(MemberOffset(offset), newValue, true);
+  // JNI must use non transactional mode.
+  obj->SetField64<false>(MemberOffset(offset), newValue, true);
 }
 
 static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -112,7 +120,8 @@
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   QuasiAtomic::MembarStoreStore();
-  obj->SetField64(MemberOffset(offset), newValue, false);
+  // JNI must use non transactional mode.
+  obj->SetField64<false>(MemberOffset(offset), newValue, false);
 }
 
 static jobject Unsafe_getObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
@@ -134,7 +143,8 @@
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
-  obj->SetFieldObject(MemberOffset(offset), newValue, false);
+  // JNI must use non transactional mode.
+  obj->SetFieldObject<false>(MemberOffset(offset), newValue, false);
 }
 
 static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -142,7 +152,8 @@
   ScopedFastNativeObjectAccess soa(env);
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
-  obj->SetFieldObject(MemberOffset(offset), newValue, true);
+  // JNI must use non transactional mode.
+  obj->SetFieldObject<false>(MemberOffset(offset), newValue, true);
 }
 
 static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -151,7 +162,8 @@
   mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
   mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
   QuasiAtomic::MembarStoreStore();
-  obj->SetFieldObject(MemberOffset(offset), newValue, false);
+  // JNI must use non transactional mode.
+  obj->SetFieldObject<false>(MemberOffset(offset), newValue, false);
 }
 
 static jint Unsafe_getArrayBaseOffsetForComponentType(JNIEnv* env, jclass, jobject component_class) {
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index 8e3c529..6af338b 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -46,8 +46,8 @@
 
 // Returns the new address of the object, returns root if it has not moved. tid and root_type are
 // only used by hprof.
-typedef mirror::Object* (RootCallback)(mirror::Object* root, void* arg, uint32_t thread_id,
-    RootType root_type) __attribute__((warn_unused_result));
+typedef void (RootCallback)(mirror::Object** root, void* arg, uint32_t thread_id,
+    RootType root_type);
 // A callback for visiting an object in the heap.
 typedef void (ObjectCallback)(mirror::Object* obj, void* arg);
 // A callback used for marking an object, returns the new address of the object if the object moved.
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index a9b17e0..f43a15b 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -234,7 +234,7 @@
 void ReferenceTable::VisitRoots(RootCallback* visitor, void* arg, uint32_t tid,
                                 RootType root_type) {
   for (auto& ref : entries_) {
-    ref = visitor(ref, arg, tid, root_type);
+    visitor(&ref, arg, tid, root_type);
   }
 }
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6ca45e8..e66e5af 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -60,6 +60,7 @@
 #include "thread.h"
 #include "thread_list.h"
 #include "trace.h"
+#include "transaction.h"
 #include "profiler.h"
 #include "UniquePtr.h"
 #include "verifier/method_verifier.h"
@@ -120,7 +121,8 @@
       main_thread_group_(nullptr),
       system_thread_group_(nullptr),
       system_class_loader_(nullptr),
-      dump_gc_performance_on_shutdown_(false) {
+      dump_gc_performance_on_shutdown_(false),
+      preinitialization_transaction(nullptr) {
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
     callee_save_methods_[i] = nullptr;
   }
@@ -826,7 +828,8 @@
       thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;");
   CHECK(contextClassLoader != NULL);
 
-  contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader.get());
+  // We can't run in a transaction yet.
+  contextClassLoader->SetObject<false>(soa.Self()->GetPeer(), class_loader.get());
 
   return env->NewGlobalRef(system_class_loader.get());
 }
@@ -1305,6 +1308,10 @@
                                    bool clean_dirty) {
   intern_table_->VisitRoots(callback, arg, only_dirty, clean_dirty);
   class_linker_->VisitRoots(callback, arg, only_dirty, clean_dirty);
+  // TODO: is it the right place ?
+  if (preinitialization_transaction != nullptr) {
+    preinitialization_transaction->VisitRoots(callback, arg);
+  }
 }
 
 void Runtime::VisitNonThreadRoots(RootCallback* callback, void* arg) {
@@ -1326,26 +1333,23 @@
   mirror::PrimitiveArray<int16_t>::VisitRoots(callback, arg);   // ShortArray
   java_vm_->VisitRoots(callback, arg);
   if (pre_allocated_OutOfMemoryError_ != nullptr) {
-    pre_allocated_OutOfMemoryError_ = down_cast<mirror::Throwable*>(
-        callback(pre_allocated_OutOfMemoryError_, arg, 0, kRootVMInternal));
+    callback(reinterpret_cast<mirror::Object**>(&pre_allocated_OutOfMemoryError_), arg, 0,
+             kRootVMInternal);
     DCHECK(pre_allocated_OutOfMemoryError_ != nullptr);
   }
-  resolution_method_ = down_cast<mirror::ArtMethod*>(callback(resolution_method_, arg, 0,
-                                                              kRootVMInternal));
+  callback(reinterpret_cast<mirror::Object**>(&resolution_method_), arg, 0, kRootVMInternal);
   DCHECK(resolution_method_ != nullptr);
   if (HasImtConflictMethod()) {
-    imt_conflict_method_ = down_cast<mirror::ArtMethod*>(callback(imt_conflict_method_, arg, 0,
-                                                                  kRootVMInternal));
+    callback(reinterpret_cast<mirror::Object**>(&imt_conflict_method_), arg, 0, kRootVMInternal);
   }
   if (HasDefaultImt()) {
-    default_imt_ = down_cast<mirror::ObjectArray<mirror::ArtMethod>*>(callback(default_imt_, arg,
-                                                                               0, kRootVMInternal));
+    callback(reinterpret_cast<mirror::Object**>(&default_imt_), arg, 0, kRootVMInternal);
   }
 
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
     if (callee_save_methods_[i] != nullptr) {
-      callee_save_methods_[i] = down_cast<mirror::ArtMethod*>(
-          callback(callee_save_methods_[i], arg, 0, kRootVMInternal));
+      callback(reinterpret_cast<mirror::Object**>(&callee_save_methods_[i]), arg, 0,
+               kRootVMInternal);
     }
   }
   {
@@ -1371,7 +1375,7 @@
   SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, cl->AllocArtMethodArray(self, 64));
   mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
   for (size_t i = 0; i < static_cast<size_t>(imtable->GetLength()); i++) {
-    imtable->Set(i, imt_conflict_method);
+    imtable->Set<false>(i, imt_conflict_method);
   }
   return imtable.get();
 }
@@ -1547,4 +1551,74 @@
   BackgroundMethodSamplingProfiler::Start(profile_period_s_, profile_duration_s_, appDir, profile_interval_us_,
       profile_backoff_coefficient_, startImmediately);
 }
+
+// Transaction support.
+// TODO move them to header file for inlining.
+bool Runtime::IsActiveTransaction() const {
+  return preinitialization_transaction != nullptr;
+}
+
+void Runtime::EnterTransactionMode(Transaction* transaction) {
+  DCHECK(IsCompiler());
+  DCHECK(transaction != nullptr);
+  DCHECK(!IsActiveTransaction());
+  preinitialization_transaction = transaction;
+}
+
+void Runtime::ExitTransactionMode() {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction = nullptr;
+}
+
+void Runtime::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset,
+                                 uint32_t value, bool is_volatile) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordWriteField32(obj, field_offset, value, is_volatile);
+}
+
+void Runtime::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset,
+                                 uint64_t value, bool is_volatile) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordWriteField64(obj, field_offset, value, is_volatile);
+}
+
+void Runtime::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+                                        mirror::Object* value, bool is_volatile) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordWriteFieldReference(obj, field_offset, value, is_volatile);
+}
+
+void Runtime::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordWriteArray(array, index, value);
+}
+
+void Runtime::RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordStrongStringInsertion(s, hash_code);
+}
+
+void Runtime::RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordWeakStringInsertion(s, hash_code);
+}
+
+void Runtime::RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordStrongStringRemoval(s, hash_code);
+}
+
+void Runtime::RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) const {
+  DCHECK(IsCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction->RecordWeakStringRemoval(s, hash_code);
+}
 }  // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 07f3d7d..159de2e 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -46,6 +46,7 @@
 namespace mirror {
   class ArtMethod;
   class ClassLoader;
+  class Array;
   template<class T> class ObjectArray;
   template<class T> class PrimitiveArray;
   typedef PrimitiveArray<int8_t> ByteArray;
@@ -65,6 +66,7 @@
 class SignalCatcher;
 class ThreadList;
 class Trace;
+class Transaction;
 
 class Runtime {
  public:
@@ -474,6 +476,27 @@
 
   void StartProfiler(const char *appDir, bool startImmediately = false);
 
+  // Transaction support.
+  bool IsActiveTransaction() const;
+  void EnterTransactionMode(Transaction* transaction);
+  void ExitTransactionMode();
+  void RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
+                          bool is_volatile) const;
+  void RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
+                          bool is_volatile) const;
+  void RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+                                 mirror::Object* value, bool is_volatile) const;
+  void RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  void RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  void RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+  void RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) const
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -612,6 +635,9 @@
   // If true, then we dump the GC cumulative timings on shutdown.
   bool dump_gc_performance_on_shutdown_;
 
+  // Transaction used for pre-initializing classes at compilation time.
+  Transaction* preinitialization_transaction;
+
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
 
diff --git a/runtime/stack.cc b/runtime/stack.cc
index fd7d981..864b86a 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -189,6 +189,11 @@
   }
 }
 
+uintptr_t* StackVisitor::GetGPRAddress(uint32_t reg) const {
+  DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
+  return context_->GetGPRAddress(reg);
+}
+
 uintptr_t StackVisitor::GetGPR(uint32_t reg) const {
   DCHECK(cur_quick_frame_ != NULL) << "This is a quick frame routine";
   return context_->GetGPR(reg);
diff --git a/runtime/stack.h b/runtime/stack.h
index 8466069..7e9889e 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -565,6 +565,7 @@
   void SetVReg(mirror::ArtMethod* m, uint16_t vreg, uint32_t new_value, VRegKind kind)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  uintptr_t* GetGPRAddress(uint32_t reg) const;
   uintptr_t GetGPR(uint32_t reg) const;
   void SetGPR(uint32_t reg, uintptr_t value);
 
@@ -654,10 +655,16 @@
     }  else if (reg < num_regs) {
       return locals_start + (reg * sizeof(uint32_t));
     } else {
-      return frame_size + ((reg - num_regs) * sizeof(uint32_t)) + sizeof(uint32_t);  // Dalvik in.
+      // Handle ins.
+      return frame_size + ((reg - num_regs) * sizeof(uint32_t)) + sizeof(StackReference<mirror::ArtMethod>);
     }
   }
 
+  static int GetOutVROffset(uint16_t out_num) {
+    // According to stack model, the first out is above the Method ptr.
+    return sizeof(StackReference<mirror::ArtMethod>) + (out_num * sizeof(uint32_t));
+  }
+
   uintptr_t GetCurrentQuickFramePc() const {
     return cur_quick_frame_pc_;
   }
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 3382811..16655fb 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -398,14 +398,11 @@
     // non-null value. However, because we can run without code
     // available (in the compiler, in tests), we manually assign the
     // fields the constructor should have set.
-    soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)->
-        SetBoolean(opeer_, thread_is_daemon);
-    soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->
-        SetObject(opeer_, soa.Decode<mirror::Object*>(thread_group));
-    soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
-        SetObject(opeer_, soa.Decode<mirror::Object*>(thread_name.get()));
-    soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
-        SetInt(opeer_, thread_priority);
+    if (runtime->IsActiveTransaction()) {
+      InitPeer<true>(soa, thread_is_daemon, thread_group, thread_name.get(), thread_priority);
+    } else {
+      InitPeer<false>(soa, thread_is_daemon, thread_group, thread_name.get(), thread_priority);
+    }
     peer_thread_name.reset(GetThreadName(soa));
   }
   // 'thread_name' may have been null, so don't trust 'peer_thread_name' to be non-null.
@@ -414,6 +411,19 @@
   }
 }
 
+template<bool kTransactionActive>
+void Thread::InitPeer(ScopedObjectAccess& soa, jboolean thread_is_daemon, jobject thread_group,
+                      jobject thread_name, jint thread_priority) {
+  soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)->
+      SetBoolean<kTransactionActive>(opeer_, thread_is_daemon);
+  soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->
+      SetObject<kTransactionActive>(opeer_, soa.Decode<mirror::Object*>(thread_group));
+  soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
+      SetObject<kTransactionActive>(opeer_, soa.Decode<mirror::Object*>(thread_name));
+  soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
+      SetInt<kTransactionActive>(opeer_, thread_priority);
+}
+
 void Thread::SetThreadName(const char* name) {
   name_->assign(name);
   ::art::SetThreadName(name);
@@ -994,19 +1004,18 @@
   }
 }
 
-static mirror::Object* MonitorExitVisitor(mirror::Object* object, void* arg, uint32_t /*thread_id*/,
-                                          RootType /*root_type*/)
+static void MonitorExitVisitor(mirror::Object** object, void* arg, uint32_t /*thread_id*/,
+                               RootType /*root_type*/)
     NO_THREAD_SAFETY_ANALYSIS {
   Thread* self = reinterpret_cast<Thread*>(arg);
-  mirror::Object* entered_monitor = object;
+  mirror::Object* entered_monitor = *object;
   if (self->HoldsLock(entered_monitor)) {
     LOG(WARNING) << "Calling MonitorExit on object "
-                 << object << " (" << PrettyTypeOf(object) << ")"
+                 << object << " (" << PrettyTypeOf(entered_monitor) << ")"
                  << " left locked by native thread "
                  << *Thread::Current() << " which is detaching";
     entered_monitor->MonitorExit(self);
   }
-  return object;
 }
 
 void Thread::Destroy() {
@@ -1020,7 +1029,11 @@
     RemoveFromThreadGroup(soa);
 
     // this.nativePeer = 0;
-    soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetLong(opeer_, 0);
+    if (Runtime::Current()->IsActiveTransaction()) {
+      soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetLong<true>(opeer_, 0);
+    } else {
+      soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetLong<false>(opeer_, 0);
+    }
     Dbg::PostThreadDeath(self);
 
     // Thread.join() is implemented as an Object.wait() on the Thread.lock object. Signal anyone
@@ -1153,10 +1166,10 @@
     for (size_t j = 0; j < num_refs; ++j) {
       mirror::Object* object = cur->GetReference(j);
       if (object != nullptr) {
-        mirror::Object* new_obj = visitor(object, arg, thread_id, kRootNativeStack);
-        DCHECK(new_obj != nullptr);
-        if (new_obj != object) {
-          cur->SetReference(j, new_obj);
+        mirror::Object* old_obj = object;
+        visitor(&object, arg, thread_id, kRootNativeStack);
+        if (old_obj != object) {
+          cur->SetReference(j, object);
         }
       }
     }
@@ -1309,7 +1322,8 @@
     }
     // Save PC trace in last element of method trace, also places it into the
     // object graph.
-    method_trace->Set(depth, dex_pc_trace);
+    // We are called from native: use non-transactional mode.
+    method_trace->Set<false>(depth, dex_pc_trace);
     // Set the Object*s and assert that no thread suspension is now possible.
     const char* last_no_suspend_cause =
         self_->StartAssertNoThreadSuspension("Building internal stack trace");
@@ -1337,8 +1351,14 @@
     if (m->IsRuntimeMethod()) {
       return true;  // Ignore runtime frames (in particular callee save).
     }
-    method_trace_->Set(count_, m);
-    dex_pc_trace_->Set(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
+    // TODO dedup this code.
+    if (Runtime::Current()->IsActiveTransaction()) {
+      method_trace_->Set<true>(count_, m);
+      dex_pc_trace_->Set<true>(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
+    } else {
+      method_trace_->Set<false>(count_, m);
+      dex_pc_trace_->Set<false>(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
+    }
     ++count_;
     return true;
   }
@@ -1461,7 +1481,8 @@
     if (obj == nullptr) {
       return nullptr;
     }
-    soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->Set(i, obj);
+    // We are called from native: use non-transactional mode.
+    soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->Set<false>(i, obj);
   }
   return result;
 }
@@ -1866,7 +1887,8 @@
         for (size_t reg = 0; reg < num_regs; ++reg) {
           mirror::Object* ref = shadow_frame->GetVRegReference(reg);
           if (ref != nullptr) {
-            mirror::Object* new_ref = visitor_(ref, reg, this);
+            mirror::Object* new_ref = ref;
+            visitor_(&new_ref, reg, this);
             if (new_ref != ref) {
              shadow_frame->SetVRegReference(reg, new_ref);
             }
@@ -1886,7 +1908,8 @@
           if (TestBitmap(reg, reg_bitmap)) {
             mirror::Object* ref = shadow_frame->GetVRegReference(reg);
             if (ref != nullptr) {
-              mirror::Object* new_ref = visitor_(ref, reg, this);
+              mirror::Object* new_ref = ref;
+              visitor_(&new_ref, reg, this);
               if (new_ref != ref) {
                shadow_frame->SetVRegReference(reg, new_ref);
               }
@@ -1922,21 +1945,22 @@
               uint32_t vmap_offset;
               if (vmap_table.IsInContext(reg, kReferenceVReg, &vmap_offset)) {
                 int vmap_reg = vmap_table.ComputeRegister(core_spills, vmap_offset, kReferenceVReg);
-                mirror::Object* ref = reinterpret_cast<mirror::Object*>(GetGPR(vmap_reg));
-                if (ref != nullptr) {
-                  mirror::Object* new_ref = visitor_(ref, reg, this);
-                  if (ref != new_ref) {
-                    SetGPR(vmap_reg, reinterpret_cast<uintptr_t>(new_ref));
-                  }
+                // This is sound as spilled GPRs will be word sized (ie 32 or 64bit).
+                mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(vmap_reg));
+                if (*ref_addr != nullptr) {
+                  visitor_(ref_addr, reg, this);
                 }
               } else {
-                uintptr_t* reg_addr = reinterpret_cast<uintptr_t*>(
-                    GetVRegAddr(cur_quick_frame, code_item, core_spills, fp_spills, frame_size, reg));
-                mirror::Object* ref = reinterpret_cast<mirror::Object*>(*reg_addr);
+                StackReference<mirror::Object>* ref_addr =
+                    reinterpret_cast<StackReference<mirror::Object>*>(
+                        GetVRegAddr(cur_quick_frame, code_item, core_spills, fp_spills, frame_size,
+                                    reg));
+                mirror::Object* ref = ref_addr->AsMirrorPtr();
                 if (ref != nullptr) {
-                  mirror::Object* new_ref = visitor_(ref, reg, this);
+                  mirror::Object* new_ref = ref;
+                  visitor_(&new_ref, reg, this);
                   if (ref != new_ref) {
-                    *reg_addr = reinterpret_cast<uintptr_t>(new_ref);
+                    ref_addr->Assign(new_ref);
                   }
                 }
               }
@@ -1949,8 +1973,8 @@
   }
 
  private:
-  static bool TestBitmap(int reg, const uint8_t* reg_vector) {
-    return ((reg_vector[reg / 8] >> (reg % 8)) & 0x01) != 0;
+  static bool TestBitmap(size_t reg, const uint8_t* reg_vector) {
+    return ((reg_vector[reg / kBitsPerByte] >> (reg % kBitsPerByte)) & 0x01) != 0;
   }
 
   // Visitor for when we visit a root.
@@ -1965,8 +1989,8 @@
   RootCallbackVisitor(RootCallback* callback, void* arg, uint32_t tid)
      : callback_(callback), arg_(arg), tid_(tid) {}
 
-  mirror::Object* operator()(mirror::Object* obj, size_t, const StackVisitor*) const {
-    return callback_(obj, arg_, tid_, kRootJavaFrame);
+  void operator()(mirror::Object** obj, size_t, const StackVisitor*) const {
+    callback_(obj, arg_, tid_, kRootJavaFrame);
   }
 
  private:
@@ -1985,17 +2009,15 @@
 void Thread::VisitRoots(RootCallback* visitor, void* arg) {
   uint32_t thread_id = GetThreadId();
   if (opeer_ != nullptr) {
-    opeer_ = visitor(opeer_, arg, thread_id, kRootThreadObject);
+    visitor(&opeer_, arg, thread_id, kRootThreadObject);
   }
   if (exception_ != nullptr) {
-    exception_ = down_cast<mirror::Throwable*>(visitor(exception_, arg, thread_id,
-                                                       kRootNativeStack));
+    visitor(reinterpret_cast<mirror::Object**>(&exception_), arg, thread_id, kRootNativeStack);
   }
   throw_location_.VisitRoots(visitor, arg);
   if (class_loader_override_ != nullptr) {
-    class_loader_override_ =
-        down_cast<mirror::ClassLoader*>(visitor(class_loader_override_, arg, thread_id,
-                                                kRootNativeStack));
+    visitor(reinterpret_cast<mirror::Object**>(&class_loader_override_), arg, thread_id,
+            kRootNativeStack);
   }
   jni_env_->locals.VisitRoots(visitor, arg, thread_id, kRootJNILocal);
   jni_env_->monitors.VisitRoots(visitor, arg, thread_id, kRootJNIMonitor);
@@ -2008,20 +2030,18 @@
   ReleaseLongJumpContext(context);
   for (instrumentation::InstrumentationStackFrame& frame : *GetInstrumentationStack()) {
     if (frame.this_object_ != nullptr) {
-      frame.this_object_ = visitor(frame.this_object_, arg, thread_id, kRootJavaFrame);
+      visitor(&frame.this_object_, arg, thread_id, kRootJavaFrame);
     }
     DCHECK(frame.method_ != nullptr);
-    frame.method_ = down_cast<mirror::ArtMethod*>(visitor(frame.method_, arg, thread_id,
-                                                          kRootJavaFrame));
+    visitor(reinterpret_cast<mirror::Object**>(&frame.method_), arg, thread_id, kRootJavaFrame);
   }
 }
 
-static mirror::Object* VerifyRoot(mirror::Object* root, void* arg, uint32_t /*thread_id*/,
-                                  RootType /*root_type*/) {
+static void VerifyRoot(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
+                       RootType /*root_type*/) {
   DCHECK(root != nullptr);
   DCHECK(arg != nullptr);
-  reinterpret_cast<gc::Heap*>(arg)->VerifyObject(root);
-  return root;
+  reinterpret_cast<gc::Heap*>(arg)->VerifyObject(*root);
 }
 
 void Thread::VerifyStackImpl() {
diff --git a/runtime/thread.h b/runtime/thread.h
index 6c072ba..48912d1 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -591,6 +591,11 @@
 
   void CreatePeer(const char* name, bool as_daemon, jobject thread_group);
 
+  template<bool kTransactionActive>
+  void InitPeer(ScopedObjectAccess& soa, jboolean thread_is_daemon, jobject thread_group,
+                jobject thread_name, jint thread_priority)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Avoid use, callers should use SetState. Used only by SignalCatcher::HandleSigQuit, ~Thread and
   // Dbg::Disconnected.
   ThreadState SetStateUnsafe(ThreadState new_state) {
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 25f692d..74e6f1c 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -577,6 +577,18 @@
 
   VLOG(threads) << *self << " self-suspending (debugger)";
 
+  // Tell JDWP we've completed invocation and are ready to suspend.
+  DebugInvokeReq* pReq = self->GetInvokeReq();
+  DCHECK(pReq != NULL);
+  if (pReq->invoke_needed) {
+    // Clear this before signaling.
+    pReq->invoke_needed = false;
+
+    VLOG(jdwp) << "invoke complete, signaling";
+    MutexLock mu(self, pReq->lock);
+    pReq->cond.Signal(self);
+  }
+
   // Tell JDWP that we've completed suspension. The JDWP thread can't
   // tell us to resume before we're fully asleep because we hold the
   // suspend count lock.
@@ -771,11 +783,10 @@
   void* const arg_;
 };
 
-static mirror::Object* VerifyRootWrapperCallback(mirror::Object* root, void* arg,
-                                                 uint32_t /*thread_id*/, RootType /*root_type*/) {
+static void VerifyRootWrapperCallback(mirror::Object** root, void* arg, uint32_t /*thread_id*/,
+                                      RootType /*root_type*/) {
   VerifyRootWrapperArg* wrapperArg = reinterpret_cast<VerifyRootWrapperArg*>(arg);
-  wrapperArg->callback_(root, wrapperArg->arg_, 0, NULL);
-  return root;
+  wrapperArg->callback_(*root, wrapperArg->arg_, 0, NULL);
 }
 
 void ThreadList::VerifyRoots(VerifyRootCallback* callback, void* arg) const {
diff --git a/runtime/throw_location.cc b/runtime/throw_location.cc
index 2a1faff..06b6e8d 100644
--- a/runtime/throw_location.cc
+++ b/runtime/throw_location.cc
@@ -35,11 +35,11 @@
 
 void ThrowLocation::VisitRoots(RootCallback* visitor, void* arg) {
   if (this_object_ != nullptr) {
-    this_object_ = visitor(this_object_, arg, 0, kRootVMInternal);
+    visitor(&this_object_, arg, 0, kRootVMInternal);
     DCHECK(this_object_ != nullptr);
   }
   if (method_ != nullptr) {
-    method_ = down_cast<mirror::ArtMethod*>(visitor(method_, arg, 0, kRootVMInternal));
+    visitor(reinterpret_cast<mirror::Object**>(&method_), arg, 0, kRootVMInternal);
     DCHECK(method_ != nullptr);
   }
 }
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
new file mode 100644
index 0000000..019a322
--- /dev/null
+++ b/runtime/transaction.cc
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "transaction.h"
+
+#include "base/stl_util.h"
+#include "base/logging.h"
+#include "gc/accounting/card_table-inl.h"
+#include "intern_table.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+
+#include <list>
+
+namespace art {
+
+// TODO: remove (only used for debugging purpose).
+static constexpr bool kEnableTransactionStats = false;
+
+Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) {
+  CHECK(Runtime::Current()->IsCompiler());
+}
+
+Transaction::~Transaction() {
+  if (kEnableTransactionStats) {
+    MutexLock mu(Thread::Current(), log_lock_);
+    size_t objects_count = object_logs_.size();
+    size_t field_values_count = 0;
+    for (auto it : object_logs_) {
+      field_values_count += it.second.Size();
+    }
+    size_t array_count = array_logs_.size();
+    size_t array_values_count = 0;
+    for (auto it : array_logs_) {
+      array_values_count += it.second.Size();
+    }
+    size_t string_count = intern_string_logs_.size();
+    LOG(INFO) << "Transaction::~Transaction"
+              << ": objects_count=" << objects_count
+              << ", field_values_count=" << field_values_count
+              << ", array_count=" << array_count
+              << ", array_values_count=" << array_values_count
+              << ", string_count=" << string_count;
+  }
+}
+
+void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
+                                     bool is_volatile) {
+  DCHECK(obj != nullptr);
+  MutexLock mu(Thread::Current(), log_lock_);
+  ObjectLog& object_log = object_logs_[obj];
+  object_log.Log32BitsValue(field_offset, value, is_volatile);
+}
+
+void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
+                                     bool is_volatile) {
+  DCHECK(obj != nullptr);
+  MutexLock mu(Thread::Current(), log_lock_);
+  ObjectLog& object_log = object_logs_[obj];
+  object_log.Log64BitsValue(field_offset, value, is_volatile);
+}
+
+void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+                                            mirror::Object* value, bool is_volatile) {
+  DCHECK(obj != nullptr);
+  MutexLock mu(Thread::Current(), log_lock_);
+  ObjectLog& object_log = object_logs_[obj];
+  object_log.LogReferenceValue(field_offset, value, is_volatile);
+}
+
+void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
+  DCHECK(array != nullptr);
+  DCHECK(array->IsArrayInstance());
+  MutexLock mu(Thread::Current(), log_lock_);
+  ArrayLog& array_log = array_logs_[array];
+  array_log.LogValue(index, value);
+}
+
+void Transaction::RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) {
+  DCHECK(s != nullptr);
+  InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kInsert);
+  LogInternedString(log);
+}
+
+void Transaction::RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) {
+  DCHECK(s != nullptr);
+  InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kInsert);
+  LogInternedString(log);
+}
+
+void Transaction::RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) {
+  InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kRemove);
+  LogInternedString(log);
+}
+
+void Transaction::RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) {
+  InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kRemove);
+  LogInternedString(log);
+}
+
+void Transaction::LogInternedString(InternStringLog& log) {
+  Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
+  MutexLock mu(Thread::Current(), log_lock_);
+  intern_string_logs_.push_front(log);
+}
+
+void Transaction::Abort() {
+  CHECK(!Runtime::Current()->IsActiveTransaction());
+  Thread* self = Thread::Current();
+  self->AssertNoPendingException();
+  MutexLock mu1(self, *Locks::intern_table_lock_);
+  MutexLock mu2(self, log_lock_);
+  UndoObjectModifications();
+  UndoArrayModifications();
+  UndoInternStringTableModifications();
+}
+
+void Transaction::UndoObjectModifications() {
+  // TODO we may not need to restore objects allocated during this transaction. Or we could directly
+  // remove them from the heap.
+  for (auto it : object_logs_) {
+    it.second.Undo(it.first);
+  }
+  object_logs_.clear();
+}
+
+void Transaction::UndoArrayModifications() {
+  // TODO we may not need to restore array allocated during this transaction. Or we could directly
+  // remove them from the heap.
+  for (auto it : array_logs_) {
+    it.second.Undo(it.first);
+  }
+  array_logs_.clear();
+}
+
+void Transaction::UndoInternStringTableModifications() {
+  InternTable* const intern_table = Runtime::Current()->GetInternTable();
+  // We want to undo each operation from the most recent to the oldest. List has been filled so the
+  // most recent operation is at list begin so just have to iterate over it.
+  for (InternStringLog& string_log : intern_string_logs_) {
+    string_log.Undo(intern_table);
+  }
+  intern_string_logs_.clear();
+}
+
+void Transaction::VisitRoots(RootCallback* callback, void* arg) {
+  LOG(INFO) << "Transaction::VisitRoots";
+  MutexLock mu(Thread::Current(), log_lock_);
+  VisitObjectLogs(callback, arg);
+  VisitArrayLogs(callback, arg);
+  VisitStringLogs(callback, arg);
+}
+
+void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
+  // List of moving roots.
+  typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
+  std::list<ObjectPair> moving_roots;
+
+  // Visit roots.
+  for (auto it : object_logs_) {
+    it.second.VisitRoots(callback, arg);
+    mirror::Object* old_root = it.first;
+    mirror::Object* new_root = old_root;
+    callback(&new_root, arg, 0, kRootUnknown);
+    if (new_root != old_root) {
+      moving_roots.push_back(std::make_pair(old_root, new_root));
+    }
+  }
+
+  // Update object logs with moving roots.
+  for (const ObjectPair& pair : moving_roots) {
+    mirror::Object* old_root = pair.first;
+    mirror::Object* new_root = pair.second;
+    auto old_root_it = object_logs_.find(old_root);
+    CHECK(old_root_it != object_logs_.end());
+    CHECK(object_logs_.find(new_root) == object_logs_.end());
+    object_logs_.insert(std::make_pair(new_root, old_root_it->second));
+    object_logs_.erase(old_root_it);
+  }
+}
+
+void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
+  // List of moving roots.
+  typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
+  std::list<ArrayPair> moving_roots;
+
+  for (auto it : array_logs_) {
+    mirror::Array* old_root = it.first;
+    if (old_root->IsObjectArray()) {
+      it.second.VisitRoots(callback, arg);
+    }
+    mirror::Array* new_root = old_root;
+    callback(reinterpret_cast<mirror::Object**>(&new_root), arg, 0, kRootUnknown);
+    if (new_root != old_root) {
+      moving_roots.push_back(std::make_pair(old_root, new_root));
+    }
+  }
+
+  // Update array logs with moving roots.
+  for (const ArrayPair& pair : moving_roots) {
+    mirror::Array* old_root = pair.first;
+    mirror::Array* new_root = pair.second;
+    auto old_root_it = array_logs_.find(old_root);
+    CHECK(old_root_it != array_logs_.end());
+    CHECK(array_logs_.find(new_root) == array_logs_.end());
+    array_logs_.insert(std::make_pair(new_root, old_root_it->second));
+    array_logs_.erase(old_root_it);
+  }
+}
+
+void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
+  for (InternStringLog& log : intern_string_logs_) {
+    log.VisitRoots(callback, arg);
+  }
+}
+
+void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
+  auto it = field_values_.find(offset.Uint32Value());
+  if (it == field_values_.end()) {
+    ObjectLog::FieldValue field_value;
+    field_value.value = value;
+    field_value.is_volatile = is_volatile;
+    field_value.kind = ObjectLog::k32Bits;
+    field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
+  }
+}
+
+void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
+  auto it = field_values_.find(offset.Uint32Value());
+  if (it == field_values_.end()) {
+    ObjectLog::FieldValue field_value;
+    field_value.value = value;
+    field_value.is_volatile = is_volatile;
+    field_value.kind = ObjectLog::k64Bits;
+    field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
+  }
+}
+
+void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
+  auto it = field_values_.find(offset.Uint32Value());
+  if (it == field_values_.end()) {
+    ObjectLog::FieldValue field_value;
+    field_value.value = reinterpret_cast<uintptr_t>(obj);
+    field_value.is_volatile = is_volatile;
+    field_value.kind = ObjectLog::kReference;
+    field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
+  }
+}
+
+void Transaction::ObjectLog::Undo(mirror::Object* obj) {
+  for (auto& it : field_values_) {
+    // Garbage collector needs to access object's class and array's length. So we don't rollback
+    // these values.
+    MemberOffset field_offset(it.first);
+    if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
+      // Skip Object::class field.
+      continue;
+    }
+    if (obj->IsArrayInstance() &&
+        field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
+      // Skip Array::length field.
+      continue;
+    }
+    FieldValue& field_value = it.second;
+    UndoFieldWrite(obj, field_offset, field_value);
+  }
+}
+
+void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
+                                            const FieldValue& field_value) {
+  // TODO We may want to abort a transaction while still being in transaction mode. In this case,
+  // we'd need to disable the check.
+  constexpr bool kCheckTransaction = true;
+  switch (field_value.kind) {
+    case k32Bits:
+      obj->SetField32<false, kCheckTransaction>(field_offset, static_cast<uint32_t>(field_value.value),
+                                                field_value.is_volatile);
+      break;
+    case k64Bits:
+      obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value,
+                                                field_value.is_volatile);
+      break;
+    case kReference:
+      obj->SetFieldObject<false, kCheckTransaction>(field_offset,
+                                                    reinterpret_cast<mirror::Object*>(field_value.value),
+                                                    field_value.is_volatile);
+      break;
+    default:
+      LOG(FATAL) << "Unknown value kind " << field_value.kind;
+      break;
+  }
+}
+
+void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
+  for (auto it : field_values_) {
+    FieldValue& field_value = it.second;
+    if (field_value.kind == ObjectLog::kReference) {
+      mirror::Object* obj =
+          reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
+      callback(&obj, arg, 0, kRootUnknown);
+      field_value.value = reinterpret_cast<uintptr_t>(obj);
+    }
+  }
+}
+
+void Transaction::InternStringLog::Undo(InternTable* intern_table) {
+  DCHECK(intern_table != nullptr);
+  switch (string_op_) {
+      case InternStringLog::kInsert: {
+        switch (string_kind_) {
+          case InternStringLog::kStrongString:
+            intern_table->RemoveStrongFromTransaction(str_, hash_code_);
+            break;
+          case InternStringLog::kWeakString:
+            intern_table->RemoveWeakFromTransaction(str_, hash_code_);
+            break;
+          default:
+            LOG(FATAL) << "Unknown interned string kind";
+            break;
+        }
+        break;
+      }
+      case InternStringLog::kRemove: {
+        switch (string_kind_) {
+          case InternStringLog::kStrongString:
+            intern_table->InsertStrongFromTransaction(str_, hash_code_);
+            break;
+          case InternStringLog::kWeakString:
+            intern_table->InsertWeakFromTransaction(str_, hash_code_);
+            break;
+          default:
+            LOG(FATAL) << "Unknown interned string kind";
+            break;
+        }
+        break;
+      }
+      default:
+        LOG(FATAL) << "Unknown interned string op";
+        break;
+    }
+}
+
+void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
+  callback(reinterpret_cast<mirror::Object**>(&str_), arg, 0, kRootInternedString);
+}
+
+void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
+  auto it = array_values_.find(index);
+  if (it == array_values_.end()) {
+    array_values_.insert(std::make_pair(index, value));
+  }
+}
+
+void Transaction::ArrayLog::Undo(mirror::Array* array) {
+  DCHECK(array != nullptr);
+  DCHECK(array->IsArrayInstance());
+  Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
+  for (auto it : array_values_) {
+    UndoArrayWrite(array, type, it.first, it.second);
+  }
+}
+
+void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
+                                           size_t index, uint64_t value) {
+  // TODO We may want to abort a transaction while still being in transaction mode. In this case,
+  // we'd need to disable the check.
+  switch (array_type) {
+    case Primitive::kPrimBoolean:
+      array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
+      break;
+    case Primitive::kPrimByte:
+      array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
+      break;
+    case Primitive::kPrimChar:
+      array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
+      break;
+    case Primitive::kPrimShort:
+      array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
+      break;
+    case Primitive::kPrimInt:
+      array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
+      break;
+    case Primitive::kPrimFloat:
+      array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
+      break;
+    case Primitive::kPrimLong:
+      array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
+      break;
+    case Primitive::kPrimDouble:
+      array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
+      break;
+    case Primitive::kPrimNot: {
+      mirror::ObjectArray<mirror::Object>* obj_array = array->AsObjectArray<mirror::Object>();
+      obj_array->SetWithoutChecks<false>(index, reinterpret_cast<mirror::Object*>(
+          static_cast<uintptr_t>(value)));
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unsupported type " << array_type;
+  }
+}
+
+void Transaction::ArrayLog::VisitRoots(RootCallback* callback, void* arg) {
+  for (auto& it : array_values_) {
+    mirror::Object* obj = reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(it.second));
+    callback(&obj, arg, 0, kRootUnknown);
+    it.second = reinterpret_cast<uintptr_t>(obj);
+  }
+}
+
+}  // namespace art
diff --git a/runtime/transaction.h b/runtime/transaction.h
new file mode 100644
index 0000000..68f9540
--- /dev/null
+++ b/runtime/transaction.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_TRANSACTION_H_
+#define ART_RUNTIME_TRANSACTION_H_
+
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "locks.h"
+#include "offsets.h"
+#include "primitive.h"
+#include "object_callbacks.h"
+#include "safe_map.h"
+
+#include <list>
+#include <map>
+
+namespace art {
+namespace mirror {
+class Array;
+class Object;
+class String;
+}
+class InternTable;
+
+class Transaction {
+ public:
+  Transaction();
+  ~Transaction();
+
+  // Record object field changes.
+  void RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
+                          bool is_volatile)
+      LOCKS_EXCLUDED(log_lock_);
+  void RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
+                          bool is_volatile)
+      LOCKS_EXCLUDED(log_lock_);
+  void RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+                                 mirror::Object* value, bool is_volatile)
+      LOCKS_EXCLUDED(log_lock_);
+
+  // Record array change.
+  void RecordWriteArray(mirror::Array* array, size_t index, uint64_t value)
+      LOCKS_EXCLUDED(log_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  // Record intern string table changes.
+  void RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+      LOCKS_EXCLUDED(log_lock_);
+  void RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+      LOCKS_EXCLUDED(log_lock_);
+  void RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+      LOCKS_EXCLUDED(log_lock_);
+  void RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+      LOCKS_EXCLUDED(log_lock_);
+
+  // Abort transaction by undoing all recorded changes.
+  void Abort()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(log_lock_);
+
+  void VisitRoots(RootCallback* callback, void* arg)
+      LOCKS_EXCLUDED(log_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  class ObjectLog {
+   public:
+    void Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile);
+    void Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile);
+    void LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile);
+
+    void Undo(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    void VisitRoots(RootCallback* callback, void* arg);
+
+    size_t Size() const {
+      return field_values_.size();
+    }
+
+   private:
+    enum FieldValueKind {
+      k32Bits,
+      k64Bits,
+      kReference
+    };
+    struct FieldValue {
+      // TODO use JValue instead ?
+      uint64_t value;
+      FieldValueKind kind;
+      bool is_volatile;
+    };
+
+    void UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
+                        const FieldValue& field_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+    // Maps field's offset to its value.
+    std::map<uint32_t, FieldValue> field_values_;
+  };
+
+  class ArrayLog {
+   public:
+    void LogValue(size_t index, uint64_t value);
+
+    void Undo(mirror::Array* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+    void VisitRoots(RootCallback* callback, void* arg);
+
+    size_t Size() const {
+      return array_values_.size();
+    }
+
+   private:
+    void UndoArrayWrite(mirror::Array* array, Primitive::Type array_type, size_t index,
+                        uint64_t value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+    // Maps index to value.
+    // TODO use JValue instead ?
+    std::map<size_t, uint64_t> array_values_;
+  };
+
+  class InternStringLog {
+   public:
+    enum StringKind {
+      kStrongString,
+      kWeakString
+    };
+    enum StringOp {
+      kInsert,
+      kRemove
+    };
+    InternStringLog(mirror::String* s, uint32_t hash_code, StringKind kind, StringOp op)
+      : str_(s), hash_code_(hash_code), string_kind_(kind), string_op_(op) {
+    }
+
+    void Undo(InternTable* intern_table) EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+    void VisitRoots(RootCallback* callback, void* arg);
+
+   private:
+    mirror::String* str_;
+    uint32_t hash_code_;
+    StringKind string_kind_;
+    StringOp string_op_;
+  };
+
+  void LogInternedString(InternStringLog& log)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+      LOCKS_EXCLUDED(log_lock_);
+
+  void UndoObjectModifications()
+      EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void UndoArrayModifications()
+      EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void UndoInternStringTableModifications()
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(log_lock_);
+
+  void VisitObjectLogs(RootCallback* callback, void* arg)
+      EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void VisitArrayLogs(RootCallback* callback, void* arg)
+      EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void VisitStringLogs(RootCallback* callback, void* arg)
+      EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  Mutex log_lock_ ACQUIRED_AFTER(Locks::intern_table_lock_);
+  std::map<mirror::Object*, ObjectLog> object_logs_ GUARDED_BY(log_lock_);
+  std::map<mirror::Array*, ArrayLog> array_logs_  GUARDED_BY(log_lock_);
+  std::list<InternStringLog> intern_string_logs_ GUARDED_BY(log_lock_);
+
+  DISALLOW_COPY_AND_ASSIGN(Transaction);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_TRANSACTION_H_
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
new file mode 100644
index 0000000..dcfa24b
--- /dev/null
+++ b/runtime/transaction_test.cc
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_test.h"
+#include "invoke_arg_array_builder.h"
+#include "mirror/array-inl.h"
+#include "mirror/art_field-inl.h"
+#include "mirror/art_method-inl.h"
+#include "transaction.h"
+
+namespace art {
+
+class TransactionTest : public CommonTest {
+};
+
+TEST_F(TransactionTest, Object_class) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindSystemClass("Ljava/lang/Object;"));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+  ASSERT_TRUE(sirt_obj.get() != nullptr);
+  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  Runtime::Current()->ExitTransactionMode();
+
+  // Aborting transaction must not clear the Object::class field.
+  transaction.Abort();
+  EXPECT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+}
+
+TEST_F(TransactionTest, Object_monitor) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindSystemClass("Ljava/lang/Object;"));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+  ASSERT_TRUE(sirt_obj.get() != nullptr);
+  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+  // Lock object's monitor outside the transaction.
+  sirt_obj->MonitorEnter(soa.Self());
+  uint32_t old_lock_word = sirt_obj->GetLockWord().GetValue();
+
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  // Unlock object's monitor inside the transaction.
+  sirt_obj->MonitorExit(soa.Self());
+  uint32_t new_lock_word = sirt_obj->GetLockWord().GetValue();
+  Runtime::Current()->ExitTransactionMode();
+
+  // Aborting transaction must not clear the Object::class field.
+  transaction.Abort();
+  uint32_t aborted_lock_word = sirt_obj->GetLockWord().GetValue();
+  EXPECT_NE(old_lock_word, new_lock_word);
+  EXPECT_EQ(aborted_lock_word, new_lock_word);
+}
+
+TEST_F(TransactionTest, Array_length) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindSystemClass("[Ljava/lang/Object;"));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+
+  constexpr int32_t kArraySize = 2;
+
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+
+  // Allocate an array during transaction.
+  SirtRef<mirror::Array> sirt_obj(soa.Self(),
+                                  mirror::Array::Alloc<false>(soa.Self(), sirt_klass.get(), kArraySize));
+  ASSERT_TRUE(sirt_obj.get() != nullptr);
+  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+  Runtime::Current()->ExitTransactionMode();
+
+  // Aborting transaction must not clear the Object::class field.
+  transaction.Abort();
+  EXPECT_EQ(sirt_obj->GetLength(), kArraySize);
+}
+
+TEST_F(TransactionTest, StaticFieldsTest) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::ClassLoader> class_loader(
+      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+  ASSERT_TRUE(class_loader.get() != nullptr);
+
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindClass("LStaticFieldsTest;", class_loader));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  ASSERT_TRUE(sirt_klass->IsInitialized());
+
+  // Lookup fields.
+  mirror::ArtField* booleanField = sirt_klass->FindDeclaredStaticField("booleanField", "Z");
+  ASSERT_TRUE(booleanField != nullptr);
+  ASSERT_EQ(FieldHelper(booleanField).GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
+  ASSERT_EQ(booleanField->GetBoolean(sirt_klass.get()), false);
+
+  mirror::ArtField* byteField = sirt_klass->FindDeclaredStaticField("byteField", "B");
+  ASSERT_TRUE(byteField != nullptr);
+  ASSERT_EQ(FieldHelper(byteField).GetTypeAsPrimitiveType(), Primitive::kPrimByte);
+  ASSERT_EQ(byteField->GetByte(sirt_klass.get()), 0);
+
+  mirror::ArtField* charField = sirt_klass->FindDeclaredStaticField("charField", "C");
+  ASSERT_TRUE(charField != nullptr);
+  ASSERT_EQ(FieldHelper(charField).GetTypeAsPrimitiveType(), Primitive::kPrimChar);
+  ASSERT_EQ(charField->GetChar(sirt_klass.get()), 0u);
+
+  mirror::ArtField* shortField = sirt_klass->FindDeclaredStaticField("shortField", "S");
+  ASSERT_TRUE(shortField != nullptr);
+  ASSERT_EQ(FieldHelper(shortField).GetTypeAsPrimitiveType(), Primitive::kPrimShort);
+  ASSERT_EQ(shortField->GetShort(sirt_klass.get()), 0);
+
+  mirror::ArtField* intField = sirt_klass->FindDeclaredStaticField("intField", "I");
+  ASSERT_TRUE(intField != nullptr);
+  ASSERT_EQ(FieldHelper(intField).GetTypeAsPrimitiveType(), Primitive::kPrimInt);
+  ASSERT_EQ(intField->GetInt(sirt_klass.get()), 0);
+
+  mirror::ArtField* longField = sirt_klass->FindDeclaredStaticField("longField", "J");
+  ASSERT_TRUE(longField != nullptr);
+  ASSERT_EQ(FieldHelper(longField).GetTypeAsPrimitiveType(), Primitive::kPrimLong);
+  ASSERT_EQ(longField->GetLong(sirt_klass.get()), static_cast<int64_t>(0));
+
+  mirror::ArtField* floatField = sirt_klass->FindDeclaredStaticField("floatField", "F");
+  ASSERT_TRUE(floatField != nullptr);
+  ASSERT_EQ(FieldHelper(floatField).GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
+  ASSERT_EQ(floatField->GetFloat(sirt_klass.get()), static_cast<float>(0.0f));
+
+  mirror::ArtField* doubleField = sirt_klass->FindDeclaredStaticField("doubleField", "D");
+  ASSERT_TRUE(doubleField != nullptr);
+  ASSERT_EQ(FieldHelper(doubleField).GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
+  ASSERT_EQ(doubleField->GetDouble(sirt_klass.get()), static_cast<double>(0.0));
+
+  mirror::ArtField* objectField = sirt_klass->FindDeclaredStaticField("objectField", "Ljava/lang/Object;");
+  ASSERT_TRUE(objectField != nullptr);
+  ASSERT_EQ(FieldHelper(objectField).GetTypeAsPrimitiveType(), Primitive::kPrimNot);
+  ASSERT_EQ(objectField->GetObject(sirt_klass.get()), nullptr);
+
+  // Create a java.lang.Object instance to set objectField.
+  SirtRef<mirror::Class> object_klass(soa.Self(), class_linker_->FindSystemClass("Ljava/lang/Object;"));
+  ASSERT_TRUE(object_klass.get() != nullptr);
+  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+  ASSERT_TRUE(sirt_obj.get() != nullptr);
+  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+  // Modify fields inside transaction and abort it.
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  booleanField->SetBoolean<true>(sirt_klass.get(), true);
+  byteField->SetByte<true>(sirt_klass.get(), 1);
+  charField->SetChar<true>(sirt_klass.get(), 1u);
+  shortField->SetShort<true>(sirt_klass.get(), 1);
+  intField->SetInt<true>(sirt_klass.get(), 1);
+  longField->SetLong<true>(sirt_klass.get(), 1);
+  floatField->SetFloat<true>(sirt_klass.get(), 1.0);
+  doubleField->SetDouble<true>(sirt_klass.get(), 1.0);
+  objectField->SetObject<true>(sirt_klass.get(), sirt_obj.get());
+  Runtime::Current()->ExitTransactionMode();
+  transaction.Abort();
+
+  // Check values have properly been restored to their original (default) value.
+  EXPECT_EQ(booleanField->GetBoolean(sirt_klass.get()), false);
+  EXPECT_EQ(byteField->GetByte(sirt_klass.get()), 0);
+  EXPECT_EQ(charField->GetChar(sirt_klass.get()), 0u);
+  EXPECT_EQ(shortField->GetShort(sirt_klass.get()), 0);
+  EXPECT_EQ(intField->GetInt(sirt_klass.get()), 0);
+  EXPECT_EQ(longField->GetLong(sirt_klass.get()), static_cast<int64_t>(0));
+  EXPECT_EQ(floatField->GetFloat(sirt_klass.get()), static_cast<float>(0.0f));
+  EXPECT_EQ(doubleField->GetDouble(sirt_klass.get()), static_cast<double>(0.0));
+  EXPECT_EQ(objectField->GetObject(sirt_klass.get()), nullptr);
+}
+
+TEST_F(TransactionTest, InstanceFieldsTest) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::ClassLoader> class_loader(
+      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+  ASSERT_TRUE(class_loader.get() != nullptr);
+
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindClass("LInstanceFieldsTest;", class_loader));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  ASSERT_TRUE(sirt_klass->IsInitialized());
+
+  // Allocate an InstanceFieldTest object.
+  SirtRef<mirror::Object> sirt_instance(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+  ASSERT_TRUE(sirt_instance.get() != nullptr);
+
+  // Lookup fields.
+  mirror::ArtField* booleanField = sirt_klass->FindDeclaredInstanceField("booleanField", "Z");
+  ASSERT_TRUE(booleanField != nullptr);
+  ASSERT_EQ(FieldHelper(booleanField).GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
+  ASSERT_EQ(booleanField->GetBoolean(sirt_instance.get()), false);
+
+  mirror::ArtField* byteField = sirt_klass->FindDeclaredInstanceField("byteField", "B");
+  ASSERT_TRUE(byteField != nullptr);
+  ASSERT_EQ(FieldHelper(byteField).GetTypeAsPrimitiveType(), Primitive::kPrimByte);
+  ASSERT_EQ(byteField->GetByte(sirt_instance.get()), 0);
+
+  mirror::ArtField* charField = sirt_klass->FindDeclaredInstanceField("charField", "C");
+  ASSERT_TRUE(charField != nullptr);
+  ASSERT_EQ(FieldHelper(charField).GetTypeAsPrimitiveType(), Primitive::kPrimChar);
+  ASSERT_EQ(charField->GetChar(sirt_instance.get()), 0u);
+
+  mirror::ArtField* shortField = sirt_klass->FindDeclaredInstanceField("shortField", "S");
+  ASSERT_TRUE(shortField != nullptr);
+  ASSERT_EQ(FieldHelper(shortField).GetTypeAsPrimitiveType(), Primitive::kPrimShort);
+  ASSERT_EQ(shortField->GetShort(sirt_instance.get()), 0);
+
+  mirror::ArtField* intField = sirt_klass->FindDeclaredInstanceField("intField", "I");
+  ASSERT_TRUE(intField != nullptr);
+  ASSERT_EQ(FieldHelper(intField).GetTypeAsPrimitiveType(), Primitive::kPrimInt);
+  ASSERT_EQ(intField->GetInt(sirt_instance.get()), 0);
+
+  mirror::ArtField* longField = sirt_klass->FindDeclaredInstanceField("longField", "J");
+  ASSERT_TRUE(longField != nullptr);
+  ASSERT_EQ(FieldHelper(longField).GetTypeAsPrimitiveType(), Primitive::kPrimLong);
+  ASSERT_EQ(longField->GetLong(sirt_instance.get()), static_cast<int64_t>(0));
+
+  mirror::ArtField* floatField = sirt_klass->FindDeclaredInstanceField("floatField", "F");
+  ASSERT_TRUE(floatField != nullptr);
+  ASSERT_EQ(FieldHelper(floatField).GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
+  ASSERT_EQ(floatField->GetFloat(sirt_instance.get()), static_cast<float>(0.0f));
+
+  mirror::ArtField* doubleField = sirt_klass->FindDeclaredInstanceField("doubleField", "D");
+  ASSERT_TRUE(doubleField != nullptr);
+  ASSERT_EQ(FieldHelper(doubleField).GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
+  ASSERT_EQ(doubleField->GetDouble(sirt_instance.get()), static_cast<double>(0.0));
+
+  mirror::ArtField* objectField = sirt_klass->FindDeclaredInstanceField("objectField", "Ljava/lang/Object;");
+  ASSERT_TRUE(objectField != nullptr);
+  ASSERT_EQ(FieldHelper(objectField).GetTypeAsPrimitiveType(), Primitive::kPrimNot);
+  ASSERT_EQ(objectField->GetObject(sirt_instance.get()), nullptr);
+
+  // Create a java.lang.Object instance to set objectField.
+  SirtRef<mirror::Class> object_klass(soa.Self(), class_linker_->FindSystemClass("Ljava/lang/Object;"));
+  ASSERT_TRUE(object_klass.get() != nullptr);
+  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+  ASSERT_TRUE(sirt_obj.get() != nullptr);
+  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+  // Modify fields inside transaction and abort it.
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  booleanField->SetBoolean<true>(sirt_instance.get(), true);
+  byteField->SetByte<true>(sirt_instance.get(), 1);
+  charField->SetChar<true>(sirt_instance.get(), 1u);
+  shortField->SetShort<true>(sirt_instance.get(), 1);
+  intField->SetInt<true>(sirt_instance.get(), 1);
+  longField->SetLong<true>(sirt_instance.get(), 1);
+  floatField->SetFloat<true>(sirt_instance.get(), 1.0);
+  doubleField->SetDouble<true>(sirt_instance.get(), 1.0);
+  objectField->SetObject<true>(sirt_instance.get(), sirt_obj.get());
+  Runtime::Current()->ExitTransactionMode();
+  transaction.Abort();
+
+  // Check values have properly been restored to their original (default) value.
+  EXPECT_EQ(booleanField->GetBoolean(sirt_instance.get()), false);
+  EXPECT_EQ(byteField->GetByte(sirt_instance.get()), 0);
+  EXPECT_EQ(charField->GetChar(sirt_instance.get()), 0u);
+  EXPECT_EQ(shortField->GetShort(sirt_instance.get()), 0);
+  EXPECT_EQ(intField->GetInt(sirt_instance.get()), 0);
+  EXPECT_EQ(longField->GetLong(sirt_instance.get()), static_cast<int64_t>(0));
+  EXPECT_EQ(floatField->GetFloat(sirt_instance.get()), static_cast<float>(0.0f));
+  EXPECT_EQ(doubleField->GetDouble(sirt_instance.get()), static_cast<double>(0.0));
+  EXPECT_EQ(objectField->GetObject(sirt_instance.get()), nullptr);
+}
+
+
+TEST_F(TransactionTest, StaticArrayFieldsTest) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::ClassLoader> class_loader(
+      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+  ASSERT_TRUE(class_loader.get() != nullptr);
+
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindClass("LStaticArrayFieldsTest;", class_loader));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  ASSERT_TRUE(sirt_klass->IsInitialized());
+
+  // Lookup fields.
+  mirror::ArtField* booleanArrayField = sirt_klass->FindDeclaredStaticField("booleanArrayField", "[Z");
+  ASSERT_TRUE(booleanArrayField != nullptr);
+  mirror::BooleanArray* booleanArray = booleanArrayField->GetObject(sirt_klass.get())->AsBooleanArray();
+  ASSERT_TRUE(booleanArray != nullptr);
+  ASSERT_EQ(booleanArray->GetLength(), 1);
+  ASSERT_EQ(booleanArray->GetWithoutChecks(0), false);
+
+  mirror::ArtField* byteArrayField = sirt_klass->FindDeclaredStaticField("byteArrayField", "[B");
+  ASSERT_TRUE(byteArrayField != nullptr);
+  mirror::ByteArray* byteArray = byteArrayField->GetObject(sirt_klass.get())->AsByteArray();
+  ASSERT_TRUE(byteArray != nullptr);
+  ASSERT_EQ(byteArray->GetLength(), 1);
+  ASSERT_EQ(byteArray->GetWithoutChecks(0), 0);
+
+  mirror::ArtField* charArrayField = sirt_klass->FindDeclaredStaticField("charArrayField", "[C");
+  ASSERT_TRUE(charArrayField != nullptr);
+  mirror::CharArray* charArray = charArrayField->GetObject(sirt_klass.get())->AsCharArray();
+  ASSERT_TRUE(charArray != nullptr);
+  ASSERT_EQ(charArray->GetLength(), 1);
+  ASSERT_EQ(charArray->GetWithoutChecks(0), 0u);
+
+  mirror::ArtField* shortArrayField = sirt_klass->FindDeclaredStaticField("shortArrayField", "[S");
+  ASSERT_TRUE(shortArrayField != nullptr);
+  mirror::ShortArray* shortArray = shortArrayField->GetObject(sirt_klass.get())->AsShortArray();
+  ASSERT_TRUE(shortArray != nullptr);
+  ASSERT_EQ(shortArray->GetLength(), 1);
+  ASSERT_EQ(shortArray->GetWithoutChecks(0), 0);
+
+  mirror::ArtField* intArrayField = sirt_klass->FindDeclaredStaticField("intArrayField", "[I");
+  ASSERT_TRUE(intArrayField != nullptr);
+  mirror::IntArray* intArray = intArrayField->GetObject(sirt_klass.get())->AsIntArray();
+  ASSERT_TRUE(intArray != nullptr);
+  ASSERT_EQ(intArray->GetLength(), 1);
+  ASSERT_EQ(intArray->GetWithoutChecks(0), 0);
+
+  mirror::ArtField* longArrayField = sirt_klass->FindDeclaredStaticField("longArrayField", "[J");
+  ASSERT_TRUE(longArrayField != nullptr);
+  mirror::LongArray* longArray = longArrayField->GetObject(sirt_klass.get())->AsLongArray();
+  ASSERT_TRUE(longArray != nullptr);
+  ASSERT_EQ(longArray->GetLength(), 1);
+  ASSERT_EQ(longArray->GetWithoutChecks(0), static_cast<int64_t>(0));
+
+  mirror::ArtField* floatArrayField = sirt_klass->FindDeclaredStaticField("floatArrayField", "[F");
+  ASSERT_TRUE(floatArrayField != nullptr);
+  mirror::FloatArray* floatArray = floatArrayField->GetObject(sirt_klass.get())->AsFloatArray();
+  ASSERT_TRUE(floatArray != nullptr);
+  ASSERT_EQ(floatArray->GetLength(), 1);
+  ASSERT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+
+  mirror::ArtField* doubleArrayField = sirt_klass->FindDeclaredStaticField("doubleArrayField", "[D");
+  ASSERT_TRUE(doubleArrayField != nullptr);
+  mirror::DoubleArray* doubleArray = doubleArrayField->GetObject(sirt_klass.get())->AsDoubleArray();
+  ASSERT_TRUE(doubleArray != nullptr);
+  ASSERT_EQ(doubleArray->GetLength(), 1);
+  ASSERT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+
+  mirror::ArtField* objectArrayField = sirt_klass->FindDeclaredStaticField("objectArrayField", "[Ljava/lang/Object;");
+  ASSERT_TRUE(objectArrayField != nullptr);
+  mirror::ObjectArray<mirror::Object>* objectArray = objectArrayField->GetObject(sirt_klass.get())->AsObjectArray<mirror::Object>();
+  ASSERT_TRUE(objectArray != nullptr);
+  ASSERT_EQ(objectArray->GetLength(), 1);
+  ASSERT_EQ(objectArray->GetWithoutChecks(0), nullptr);
+
+  // Create a java.lang.Object instance to set objectField.
+  SirtRef<mirror::Class> object_klass(soa.Self(), class_linker_->FindSystemClass("Ljava/lang/Object;"));
+  ASSERT_TRUE(object_klass.get() != nullptr);
+  SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+  ASSERT_TRUE(sirt_obj.get() != nullptr);
+  ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+  // Modify fields inside transaction and abort it.
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  booleanArray->SetWithoutChecks<true>(0, true);
+  byteArray->SetWithoutChecks<true>(0, 1);
+  charArray->SetWithoutChecks<true>(0, 1u);
+  shortArray->SetWithoutChecks<true>(0, 1);
+  intArray->SetWithoutChecks<true>(0, 1);
+  longArray->SetWithoutChecks<true>(0, 1);
+  floatArray->SetWithoutChecks<true>(0, 1.0);
+  doubleArray->SetWithoutChecks<true>(0, 1.0);
+  objectArray->SetWithoutChecks<true>(0, sirt_obj.get());
+  Runtime::Current()->ExitTransactionMode();
+  transaction.Abort();
+
+  // Check values have properly been restored to their original (default) value.
+  EXPECT_EQ(booleanArray->GetWithoutChecks(0), false);
+  EXPECT_EQ(byteArray->GetWithoutChecks(0), 0);
+  EXPECT_EQ(charArray->GetWithoutChecks(0), 0u);
+  EXPECT_EQ(shortArray->GetWithoutChecks(0), 0);
+  EXPECT_EQ(intArray->GetWithoutChecks(0), 0);
+  EXPECT_EQ(longArray->GetWithoutChecks(0), static_cast<int64_t>(0));
+  EXPECT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+  EXPECT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+  EXPECT_EQ(objectArray->GetWithoutChecks(0), nullptr);
+}
+
+TEST_F(TransactionTest, EmptyClass) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::ClassLoader> class_loader(
+      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+  ASSERT_TRUE(class_loader.get() != nullptr);
+
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindClass("LTransaction$EmptyStatic;", class_loader));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->VerifyClass(sirt_klass);
+  ASSERT_TRUE(sirt_klass->IsVerified());
+
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  Runtime::Current()->ExitTransactionMode();
+  ASSERT_FALSE(soa.Self()->IsExceptionPending());
+}
+
+TEST_F(TransactionTest, StaticFieldClass) {
+  ScopedObjectAccess soa(Thread::Current());
+  SirtRef<mirror::ClassLoader> class_loader(
+      soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+  ASSERT_TRUE(class_loader.get() != nullptr);
+
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindClass("LTransaction$StaticFieldClass;", class_loader));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->VerifyClass(sirt_klass);
+  ASSERT_TRUE(sirt_klass->IsVerified());
+
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  Runtime::Current()->ExitTransactionMode();
+  ASSERT_FALSE(soa.Self()->IsExceptionPending());
+}
+
+TEST_F(TransactionTest, BlacklistedClass) {
+  ScopedObjectAccess soa(Thread::Current());
+  jobject jclass_loader = LoadDex("Transaction");
+  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+                                            soa.Decode<mirror::ClassLoader*>(jclass_loader));
+  ASSERT_TRUE(class_loader.get() != nullptr);
+
+  // Load and verify java.lang.ExceptionInInitializerError and java.lang.InternalError which will
+  // be thrown by class initialization due to native call.
+  SirtRef<mirror::Class> sirt_klass(soa.Self(),
+                                    class_linker_->FindSystemClass("Ljava/lang/ExceptionInInitializerError;"));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->VerifyClass(sirt_klass);
+  ASSERT_TRUE(sirt_klass->IsVerified());
+  sirt_klass.reset(class_linker_->FindSystemClass("Ljava/lang/InternalError;"));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->VerifyClass(sirt_klass);
+  ASSERT_TRUE(sirt_klass->IsVerified());
+
+  // Load and verify Transaction$NativeSupport used in class initialization.
+  sirt_klass.reset(class_linker_->FindClass("LTransaction$NativeSupport;", class_loader));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->VerifyClass(sirt_klass);
+  ASSERT_TRUE(sirt_klass->IsVerified());
+
+  sirt_klass.reset(class_linker_->FindClass("LTransaction$BlacklistedClass;", class_loader));
+  ASSERT_TRUE(sirt_klass.get() != nullptr);
+  class_linker_->VerifyClass(sirt_klass);
+  ASSERT_TRUE(sirt_klass->IsVerified());
+
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  class_linker_->EnsureInitialized(sirt_klass, true, true);
+  Runtime::Current()->ExitTransactionMode();
+  ASSERT_TRUE(soa.Self()->IsExceptionPending());
+}
+
+
+}  // namespace art
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index e56e670..630ef8a 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -971,7 +971,7 @@
 
 void RegType::VisitRoots(RootCallback* callback, void* arg) {
   if (klass_ != nullptr) {
-    klass_ = down_cast<mirror::Class*>(callback(klass_, arg, 0, kRootUnknown));
+    callback(reinterpret_cast<mirror::Object**>(&klass_), arg, 0, kRootUnknown);
   }
 }
 
diff --git a/test/Android.mk b/test/Android.mk
index 4d47651..e68ad7f 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -36,6 +36,7 @@
 	StaticLeafMethods \
 	Statics \
 	StaticsFromCode \
+	Transaction \
 	XandY
 
 # subdirectories of which are used with test-art-target-oat
@@ -109,7 +110,7 @@
 test-art-target-oat-$(1): $(ART_TEST_OUT)/oat-test-dex-$(1).jar test-art-target-sync
 	adb shell touch $(ART_TEST_DIR)/test-art-target-oat-$(1)
 	adb shell rm $(ART_TEST_DIR)/test-art-target-oat-$(1)
-	adb shell sh -c "dalvikvm -XXlib:libartd.so -Ximage:$(ART_TEST_DIR)/core.art -classpath $(ART_TEST_DIR)/oat-test-dex-$(1).jar -Djava.library.path=$(ART_TEST_DIR) $(1) $(2) && touch $(ART_TEST_DIR)/test-art-target-oat-$(1)"
+	adb shell sh -c "/system/bin/dalvikvm -XXlib:libartd.so -Ximage:$(ART_TEST_DIR)/core.art -classpath $(ART_TEST_DIR)/oat-test-dex-$(1).jar -Djava.library.path=$(ART_TEST_DIR) $(1) $(2) && touch $(ART_TEST_DIR)/test-art-target-oat-$(1)"
 	$(hide) (adb pull $(ART_TEST_DIR)/test-art-target-oat-$(1) /tmp/ && echo test-art-target-oat-$(1) PASSED) || (echo test-art-target-oat-$(1) FAILED && exit 1)
 	$(hide) rm /tmp/test-art-target-oat-$(1)
 
@@ -122,7 +123,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-default-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
-	  dalvikvm -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
           && echo test-art-host-oat-default-$(1) PASSED || (echo test-art-host-oat-default-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-default-$(1)
 
@@ -132,7 +133,7 @@
 	ANDROID_DATA=/tmp/android-data/test-art-host-oat-interpreter-$(1) \
 	  ANDROID_ROOT=$(HOST_OUT) \
 	  LD_LIBRARY_PATH=$(HOST_OUT_SHARED_LIBRARIES) \
-	  dalvikvm -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
+	  $(HOST_OUT_EXECUTABLES)/dalvikvm -XXlib:libartd.so -Ximage:$(shell pwd)/$(HOST_CORE_IMG_OUT) -Xint -classpath $(HOST_OUT_JAVA_LIBRARIES)/oat-test-dex-$(1).jar -Djava.library.path=$(HOST_OUT_SHARED_LIBRARIES) $(1) $(2) \
           && echo test-art-host-oat-interpreter-$(1) PASSED || (echo test-art-host-oat-interpreter-$(1) FAILED && exit 1)
 	$(hide) rm -r /tmp/android-data/test-art-host-oat-interpreter-$(1)
 
diff --git a/test/Transaction/InstanceFieldsTest.java b/test/Transaction/InstanceFieldsTest.java
new file mode 100644
index 0000000..38a44d2
--- /dev/null
+++ b/test/Transaction/InstanceFieldsTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class InstanceFieldsTest {
+    public boolean booleanField;
+    public byte    byteField;
+    public char    charField;
+    public short   shortField;
+    public int     intField;
+    public long    longField;
+    public float   floatField;
+    public double  doubleField;
+    public Object  objectField;
+}
diff --git a/test/Transaction/StaticArrayFieldsTest.java b/test/Transaction/StaticArrayFieldsTest.java
new file mode 100644
index 0000000..6436839
--- /dev/null
+++ b/test/Transaction/StaticArrayFieldsTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class StaticArrayFieldsTest {
+    public static boolean[] booleanArrayField = new boolean[1];
+    public static byte[]    byteArrayField = new byte[1];
+    public static char []   charArrayField = new char[1];
+    public static short[]   shortArrayField = new short[1];
+    public static int[]     intArrayField = new int[1];
+    public static long[]    longArrayField = new long[1];
+    public static float[]   floatArrayField = new float[1];
+    public static double[]  doubleArrayField = new double[1];
+    public static Object[]  objectArrayField = new Object[1];
+}
diff --git a/test/Transaction/StaticFieldsTest.java b/test/Transaction/StaticFieldsTest.java
new file mode 100644
index 0000000..2316f3b
--- /dev/null
+++ b/test/Transaction/StaticFieldsTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class StaticFieldsTest {
+    public static boolean booleanField;
+    public static byte    byteField;
+    public static char    charField;
+    public static short   shortField;
+    public static int     intField;
+    public static long    longField;
+    public static float   floatField;
+    public static double  doubleField;
+    public static Object  objectField;
+}
diff --git a/test/Transaction/Transaction.java b/test/Transaction/Transaction.java
new file mode 100644
index 0000000..9ca7fbf
--- /dev/null
+++ b/test/Transaction/Transaction.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Transaction {
+    static class EmptyStatic {
+    }
+
+    static class StaticFieldClass {
+      public static int intField;
+      static {
+        intField = 5;
+      }
+    }
+
+    static class BlacklistedClass {
+      static {
+        NativeSupport.native_call();
+      }
+    }
+
+    static class NativeSupport {
+      public static native void native_call();
+    }
+}
diff --git a/test/etc/push-and-run-test-jar b/test/etc/push-and-run-test-jar
index ff75d32..a218a42 100755
--- a/test/etc/push-and-run-test-jar
+++ b/test/etc/push-and-run-test-jar
@@ -141,7 +141,7 @@
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
 
 cmdline="cd $DEX_LOCATION && mkdir dalvik-cache && export ANDROID_DATA=$DEX_LOCATION && export DEX_LOCATION=$DEX_LOCATION && \
-    $INVOKE_WITH $gdb dalvikvm $gdbargs -XXlib:$LIB $ZYGOTE $JNI_OPTS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main"
+    $INVOKE_WITH $gdb /system/bin/dalvikvm $gdbargs -XXlib:$LIB $ZYGOTE $JNI_OPTS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar Main"
 if [ "$DEV_MODE" = "y" ]; then
   echo $cmdline "$@"
 fi
diff --git a/test/run-test b/test/run-test
index c3943e7..ea60f51 100755
--- a/test/run-test
+++ b/test/run-test
@@ -170,6 +170,13 @@
     fi
 elif [ "$runtime" = "art" ]; then
     if [ "$target_mode" = "no" ]; then
+	# ANDROID_BUILD_TOP and ANDROID_HOST_OUT are not set in a build environment.
+        if [ -z "$ANDROID_BUILD_TOP" ]; then
+	    export ANDROID_BUILD_TOP=$oldwd
+        fi
+        if [ -z "$ANDROID_HOST_OUT" ]; then
+	    export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
+        fi
         run_args="${run_args} --boot -Ximage:${ANDROID_HOST_OUT}/framework/core.art"
     else
         run_args="${run_args} --boot -Ximage:/data/art-test/core.art"