Merge "Documentation nit."
diff --git a/Android.mk b/Android.mk
index 6ad5606..06bbc67 100644
--- a/Android.mk
+++ b/Android.mk
@@ -62,6 +62,10 @@
 	rm -f $(TARGET_OUT_APPS)/*.odex
 	rm -f $(TARGET_OUT_INTERMEDIATES)/JAVA_LIBRARIES/*_intermediates/javalib.odex
 	rm -f $(TARGET_OUT_INTERMEDIATES)/APPS/*_intermediates/*.odex
+ifdef TARGET_2ND_ARCH
+	rm -f $(2ND_TARGET_OUT_INTERMEDIATES)/JAVA_LIBRARIES/*_intermediates/javalib.odex
+	rm -f $(2ND_TARGET_OUT_INTERMEDIATES)/APPS/*_intermediates/*.odex
+endif
 	rm -rf /tmp/test-*/dalvik-cache/*@classes.dex
 	rm -rf /tmp/android-data/dalvik-cache/*@classes.dex
 
@@ -143,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)
@@ -168,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)
@@ -209,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
@@ -226,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.common.mk b/build/Android.common.mk
index 415d810..1299beb 100644
--- a/build/Android.common.mk
+++ b/build/Android.common.mk
@@ -17,6 +17,12 @@
 ifndef ANDROID_COMMON_MK
 ANDROID_COMMON_MK = true
 
+ART_SUPPORTED_ARCH := arm mips x86 x86_64
+
+ifeq (,$(filter $(TARGET_ARCH),$(ART_SUPPORTED_ARCH)))
+$(warning unsupported TARGET_ARCH=$(TARGET_ARCH))
+endif
+
 # These can be overridden via the environment or by editing to
 # enable/disable certain build configuration.
 #
@@ -162,10 +168,6 @@
 endif
 ART_TARGET_CFLAGS += -DART_DEFAULT_INSTRUCTION_SET_FEATURES=$(DEX2OAT_TARGET_INSTRUCTION_SET_FEATURES)
 
-ifeq ($(TARGET_ARCH),x86)
-ART_TARGET_CFLAGS += -msse2
-endif
-
 # Enable thread-safety for GCC 4.6 on the target but not for GCC 4.7 where this feature was removed.
 ifneq ($(filter 4.6 4.6.%, $(TARGET_GCC_VERSION)),)
   ART_TARGET_CFLAGS += -Wthread-safety
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index 5cf15be..e8d48e4 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -70,6 +70,7 @@
   ifeq ($$(art_target_or_host),target)
     LOCAL_CLANG := $(ART_TARGET_CLANG)
     LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
+    LOCAL_CFLAGS_x86 += $(ART_TARGET_CFLAGS_x86)
     ifeq ($$(art_ndebug_or_debug),debug)
       LOCAL_CFLAGS += $(ART_TARGET_DEBUG_CFLAGS)
     else
@@ -95,6 +96,10 @@
   LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.executable.mk
 
   ifeq ($$(art_target_or_host),target)
+    LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
+  endif
+
+  ifeq ($$(art_target_or_host),target)
     include $(BUILD_EXECUTABLE)
     ART_TARGET_EXECUTABLES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_EXECUTABLES)/$$(LOCAL_MODULE)
   else # host
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 66a16b6..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 \
@@ -134,6 +135,7 @@
   ifeq ($$(art_target_or_host),target)
     LOCAL_CLANG := $(ART_TARGET_CLANG)
     LOCAL_CFLAGS += $(ART_TARGET_CFLAGS) $(ART_TARGET_DEBUG_CFLAGS)
+    LOCAL_CFLAGS_x86 := $(ART_TARGET_CFLAGS_x86)
     LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils
     LOCAL_STATIC_LIBRARIES += libgtest
     LOCAL_MODULE_PATH := $(ART_NATIVETEST_OUT)
diff --git a/build/Android.libarttest.mk b/build/Android.libarttest.mk
index 65b78c9..d807a9c 100644
--- a/build/Android.libarttest.mk
+++ b/build/Android.libarttest.mk
@@ -48,9 +48,11 @@
   ifeq ($$(art_target_or_host),target)
     LOCAL_CLANG := $(ART_TARGET_CLANG)
     LOCAL_CFLAGS := $(ART_TARGET_CFLAGS) $(ART_TARGET_DEBUG_CFLAGS)
+    LOCAL_CFLAGS_x86 := $(ART_TARGET_CFLAGS_x86)
     LOCAL_SHARED_LIBRARIES += libdl libcutils
     LOCAL_STATIC_LIBRARIES := libgtest
     LOCAL_MODULE_PATH := $(ART_TEST_OUT)
+    LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
     include $(BUILD_SHARED_LIBRARY)
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
diff --git a/compiler/Android.mk b/compiler/Android.mk
index 27bc3a3..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 \
@@ -156,7 +158,7 @@
 
   LOCAL_SRC_FILES := $$(LIBART_COMPILER_SRC_FILES)
 
-  GENERATED_SRC_DIR := $$(call intermediates-dir-for,$$(LOCAL_MODULE_CLASS),$$(LOCAL_MODULE),$$(LOCAL_IS_HOST_MODULE),)
+  GENERATED_SRC_DIR := $$(call local-generated-sources-dir)
   ENUM_OPERATOR_OUT_CC_FILES := $$(patsubst %.h,%_operator_out.cc,$$(LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES))
   ENUM_OPERATOR_OUT_GEN := $$(addprefix $$(GENERATED_SRC_DIR)/,$$(ENUM_OPERATOR_OUT_CC_FILES))
 
@@ -199,27 +201,13 @@
   ifeq ($(ART_USE_PORTABLE_COMPILER),true)
     LOCAL_CFLAGS += -DART_USE_PORTABLE_COMPILER=1
     ifeq ($$(art_target_or_host),target)
-      ifeq ($(TARGET_ARCH),arm)
-        LOCAL_STATIC_LIBRARIES += libmcldARMInfo libmcldARMTarget
-      else # TARGET_ARCH != arm
-      ifeq ($(TARGET_ARCH),x86)
-        LOCAL_STATIC_LIBRARIES += libmcldX86Info libmcldX86Target
-      else # TARGET_ARCH != x86
-      ifeq ($(TARGET_ARCH),x86_64)
-        LOCAL_STATIC_LIBRARIES += libmcldX86Info libmcldX86Target
-      else # TARGET_ARCH != x86_64
-      ifeq ($(TARGET_ARCH),mips)
-        LOCAL_STATIC_LIBRARIES += libmcldMipsInfo libmcldMipsTarget
-      else # TARGET_ARCH != mips
-      ifeq ($(TARGET_ARCH),aarch64)
-         $$(info TODOAArch64: $$(LOCAL_PATH)/Android.mk Add AArch64 specific MCLinker libraries)
-      else # TARGET_ARCH != aarch64
-        $$(error unsupported TARGET_ARCH=$(TARGET_ARCH))
-      endif # TARGET_ARCH != aarch64
-      endif # TARGET_ARCH != mips
-      endif # TARGET_ARCH != x86_64
-      endif # TARGET_ARCH != x86
-      endif # TARGET_ARCH != arm
+      LOCAL_STATIC_LIBRARIES_arm += libmcldARMInfo libmcldARMTarget
+      LOCAL_STATIC_LIBRARIES_x86 += libmcldX86Info libmcldX86Target
+      LOCAL_STATIC_LIBRARIES_x86_64 += libmcldX86Info libmcldX86Target
+      LOCAL_STATIC_LIBRARIES_mips += libmcldMipsInfo libmcldMipsTarget
+      ifeq ($(TARGET_ARCH),arm64)
+         $$(info TODOAArch64: $$(LOCAL_PATH)/Android.mk Add Arm64 specific MCLinker libraries)
+      endif # TARGET_ARCH != arm64
     else # host
       LOCAL_STATIC_LIBRARIES += libmcldARMInfo libmcldARMTarget
       LOCAL_STATIC_LIBRARIES += libmcldX86Info libmcldX86Target
@@ -285,6 +273,9 @@
 ifeq ($(ART_BUILD_TARGET),true)
 # TODO: Move to external/compiler_rt
 $(eval $(call copy-one-file, $(call intermediates-dir-for,STATIC_LIBRARIES,libcompiler_rt,,)/libcompiler_rt.a, $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler_rt.a))
+ifdef TARGET_2ND_ARCH
+$(eval $(call copy-one-file, $(call intermediates-dir-for,STATIC_LIBRARIES,libcompiler_rt,,,t)/libcompiler_rt.a, $(2ND_TARGET_OUT_SHARED_LIBRARIES)/libcompiler_rt.a))
+endif
 
 $(DEX2OAT): $(TARGET_OUT_SHARED_LIBRARIES)/libcompiler_rt.a
 
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 ea8eb1c..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 {
 
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index e866612..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 {
 
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index 729aaee..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 {
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index a9e029d..da4b69d 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -28,7 +28,6 @@
 #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"
@@ -36,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 {
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/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/disassembler/Android.mk b/disassembler/Android.mk
index f8001a4..1ce7b13 100644
--- a/disassembler/Android.mk
+++ b/disassembler/Android.mk
@@ -59,8 +59,6 @@
 
   LOCAL_SRC_FILES := $$(LIBART_DISASSEMBLER_SRC_FILES)
 
-  GENERATED_SRC_DIR := $$(call intermediates-dir-for,$$(LOCAL_MODULE_CLASS),$$(LOCAL_MODULE),$$(LOCAL_IS_HOST_MODULE),)
-
   ifeq ($$(art_target_or_host),target)
     LOCAL_CLANG := $(ART_TARGET_CLANG)
     LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
diff --git a/runtime/Android.mk b/runtime/Android.mk
index b6b4ff9..1e5a681 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -185,6 +185,8 @@
 	entrypoints/quick/quick_throw_entrypoints.cc \
 	entrypoints/quick/quick_trampoline_entrypoints.cc
 
+LIBART_LDFLAGS := -Wl,--no-fatal-warnings
+
 LIBART_TARGET_SRC_FILES := \
 	$(LIBART_COMMON_SRC_FILES) \
 	base/logging_android.cc \
@@ -193,9 +195,7 @@
 	runtime_android.cc \
 	thread_android.cc
 
-LIBART_LDFLAGS :=
-ifeq ($(TARGET_ARCH),arm)
-LIBART_TARGET_SRC_FILES += \
+LIBART_TARGET_SRC_FILES_arm := \
 	arch/arm/context_arm.cc.arm \
 	arch/arm/entrypoints_init_arm.cc \
 	arch/arm/jni_entrypoints_arm.S \
@@ -203,19 +203,16 @@
 	arch/arm/quick_entrypoints_arm.S \
 	arch/arm/arm_sdiv.S \
 	arch/arm/thread_arm.cc
-else # TARGET_ARCH != arm
-ifeq ($(TARGET_ARCH),x86)
-LIBART_TARGET_SRC_FILES += \
+
+LIBART_TARGET_SRC_FILES_x86 := \
 	arch/x86/context_x86.cc \
 	arch/x86/entrypoints_init_x86.cc \
 	arch/x86/jni_entrypoints_x86.S \
 	arch/x86/portable_entrypoints_x86.S \
 	arch/x86/quick_entrypoints_x86.S \
 	arch/x86/thread_x86.cc
-LIBART_LDFLAGS += -Wl,--no-fatal-warnings
-else # TARGET_ARCH != x86
-ifeq ($(TARGET_ARCH),x86_64)
-LIBART_TARGET_SRC_FILES += \
+
+LIBART_TARGET_SRC_FILES_x86_64 := \
 	arch/x86_64/context_x86_64.cc \
 	arch/x86_64/entrypoints_init_x86_64.cc \
 	arch/x86_64/jni_entrypoints_x86_64.S \
@@ -223,31 +220,27 @@
 	arch/x86_64/quick_entrypoints_x86_64.S \
 	arch/x86_64/thread_x86_64.cc \
 	monitor_pool.cc
-LIBART_LDFLAGS += -Wl,--no-fatal-warnings
-else # TARGET_ARCH != x86_64
-ifeq ($(TARGET_ARCH),mips)
-LIBART_TARGET_SRC_FILES += \
+
+
+LIBART_TARGET_SRC_FILES_mips := \
 	arch/mips/context_mips.cc \
 	arch/mips/entrypoints_init_mips.cc \
 	arch/mips/jni_entrypoints_mips.S \
 	arch/mips/portable_entrypoints_mips.S \
 	arch/mips/quick_entrypoints_mips.S \
 	arch/mips/thread_mips.cc
-else # TARGET_ARCH != mips
+
 ifeq ($(TARGET_ARCH),arm64)
 $(info TODOArm64: $(LOCAL_PATH)/Android.mk Add Arm64 specific runtime files)
 else
 ifeq ($(TARGET_ARCH),mips64)
 $(info TODOMips64: $(LOCAL_PATH)/Android.mk Add mips64 specific runtime files)
-else
-$(error unsupported TARGET_ARCH=$(TARGET_ARCH))
 endif # TARGET_ARCH != mips64
 endif # TARGET_ARCH != arm64
-endif # TARGET_ARCH != mips
-endif # TARGET_ARCH != x86_64
-endif # TARGET_ARCH != x86
-endif # TARGET_ARCH != arm
 
+ifeq (,$(filter $(TARGET_ARCH),$(ART_SUPPORTED_ARCH)))
+$(warning unsupported TARGET_ARCH=$(TARGET_ARCH))
+endif
 
 LIBART_HOST_SRC_FILES := \
 	$(LIBART_COMMON_SRC_FILES) \
@@ -338,12 +331,14 @@
 
   ifeq ($$(art_target_or_host),target)
     LOCAL_SRC_FILES := $(LIBART_TARGET_SRC_FILES)
+    $(foreach arch,$(ART_SUPPORTED_ARCH),
+      LOCAL_SRC_FILES_$(arch) := $$(LIBART_TARGET_SRC_FILES_$(arch))))
   else # host
     LOCAL_SRC_FILES := $(LIBART_HOST_SRC_FILES)
     LOCAL_IS_HOST_MODULE := true
   endif
 
-  GENERATED_SRC_DIR := $$(call intermediates-dir-for,$$(LOCAL_MODULE_CLASS),$$(LOCAL_MODULE),$$(LOCAL_IS_HOST_MODULE),)
+  GENERATED_SRC_DIR := $$(call local-generated-sources-dir)
   ENUM_OPERATOR_OUT_CC_FILES := $$(patsubst %.h,%_operator_out.cc,$$(LIBART_ENUM_OPERATOR_OUT_HEADER_FILES))
   ENUM_OPERATOR_OUT_GEN := $$(addprefix $$(GENERATED_SRC_DIR)/,$$(ENUM_OPERATOR_OUT_CC_FILES))
 
@@ -356,6 +351,9 @@
 
   LOCAL_CFLAGS := $(LIBART_CFLAGS)
   LOCAL_LDFLAGS := $(LIBART_LDFLAGS)
+  $(foreach arch,$(ART_SUPPORTED_ARCH),
+    LOCAL_LDFLAGS_$(arch) := $$(LIBART_TARGET_LDFLAGS_$(arch))))
+
   ifeq ($$(art_target_or_host),target)
     LOCAL_CLANG := $(ART_TARGET_CLANG)
     LOCAL_CFLAGS += $(ART_TARGET_CFLAGS)
@@ -394,6 +392,11 @@
   include $(LLVM_GEN_INTRINSICS_MK)
   LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common.mk
   LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+
+  ifeq ($$(art_target_or_host),target)
+    LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
+  endif
+
   ifeq ($$(art_target_or_host),target)
     include $(LLVM_DEVICE_BUILD_MK)
     include $(BUILD_SHARED_LIBRARY)
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 3863ee5..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);
 }
 
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 28ed6c4..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);
   }
 };
 
diff --git a/runtime/common_test.h b/runtime/common_test.h
index a94cbfc..7f9b6b1 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -381,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__)
@@ -391,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
@@ -417,7 +431,7 @@
 
  protected:
   static bool IsHost() {
-    return (getenv("ANDROID_BUILD_TOP") != NULL);
+    return !kIsTargetBuild;
   }
 
   virtual void SetUp() {
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index 6258070..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,7 +80,7 @@
                   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.
@@ -94,13 +94,13 @@
   }
 
  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
@@ -112,7 +112,7 @@
   }
 
  private:
-  RootCallback* const callback_;
+  MarkObjectCallback* const callback_;
   void* const arg_;
 };
 
@@ -265,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();
 
@@ -300,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);
@@ -322,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 6d9496e..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.
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 7613a31..9e5e3ab 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:
@@ -1878,10 +1876,14 @@
 
 // Must do this with mutators suspended since we are directly accessing the allocation stacks.
 bool Heap::VerifyHeapReferences() {
-  Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
+  Thread* self = Thread::Current();
+  Locks::mutator_lock_->AssertExclusiveHeld(self);
   // Lets sort our allocation stacks so that we can efficiently binary search them.
   allocation_stack_->Sort();
   live_stack_->Sort();
+  // Since we sorted the allocation stack content, need to revoke all
+  // thread-local allocation stacks.
+  RevokeAllThreadLocalAllocationStacks(self);
   VerifyObjectVisitor visitor(this);
   // Verify objects in the allocation stack since these will be objects which were:
   // 1. Allocated prior to the GC (pre GC verification).
@@ -1997,10 +1999,14 @@
 };
 
 bool Heap::VerifyMissingCardMarks() {
-  Locks::mutator_lock_->AssertExclusiveHeld(Thread::Current());
+  Thread* self = Thread::Current();
+  Locks::mutator_lock_->AssertExclusiveHeld(self);
 
   // We need to sort the live stack since we binary search it.
   live_stack_->Sort();
+  // Since we sorted the allocation stack content, need to revoke all
+  // thread-local allocation stacks.
+  RevokeAllThreadLocalAllocationStacks(self);
   VerifyLiveStackReferences visitor(this);
   GetLiveBitmap()->Visit(visitor);
 
@@ -2072,7 +2078,7 @@
   }
 }
 
-static mirror::Object* IdentityRootCallback(mirror::Object* obj, void*, uint32_t, RootType) {
+static mirror::Object* IdentityMarkObjectCallback(mirror::Object* obj, void*) {
   return obj;
 }
 
@@ -2111,7 +2117,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();
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 cc49d67..660efe4 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -48,9 +48,8 @@
   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) {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index a674571..cb9e2e8 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -69,27 +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);
-    // Check offset is 32bits to fit in MemberOffset.
-    CHECK_GE(offset, static_cast<jlong>(std::numeric_limits<int32_t>::min()));
-    CHECK_LE(offset, static_cast<jlong>(std::numeric_limits<int32_t>::max()));
-    Runtime::Current()->RecordWriteField32(obj, MemberOffset(offset), *address, true);
-    // 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<true>(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();
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 876de05..362df8c 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -505,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);
     }
   }
 
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/art_field.cc b/runtime/mirror/art_field.cc
index dd628ea..7740213 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -55,8 +55,8 @@
 
 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_method.cc b/runtime/mirror/art_method.cc
index b5c87ad..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);
   }
 }
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 6446d02..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);
   }
 }
 
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index 6bc695d..02a396a 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -70,8 +70,8 @@
 
 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/string.cc b/runtime/mirror/string.cc
index cd63c39..3f35210 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -288,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/throwable.cc b/runtime/mirror/throwable.cc
index fef7d36..4c53993 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -99,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/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/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 e1b0ed4..e66e5af 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1333,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);
     }
   }
   {
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 2d56a74..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);
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 5728391..16655fb 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1004,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() {
@@ -1167,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);
         }
       }
     }
@@ -1888,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);
             }
@@ -1908,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);
               }
@@ -1944,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);
                   }
                 }
               }
@@ -1971,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.
@@ -1987,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:
@@ -2007,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);
@@ -2030,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_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
index 6adcfec..019a322 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -173,7 +173,8 @@
   for (auto it : object_logs_) {
     it.second.VisitRoots(callback, arg);
     mirror::Object* old_root = it.first;
-    mirror::Object* new_root = callback(old_root, arg, 0, kRootUnknown);
+    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));
     }
@@ -201,7 +202,8 @@
     if (old_root->IsObjectArray()) {
       it.second.VisitRoots(callback, arg);
     }
-    mirror::Array* new_root = down_cast<mirror::Array*>(callback(old_root, arg, 0, kRootUnknown));
+    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));
     }
@@ -306,8 +308,10 @@
   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));
-      field_value.value = reinterpret_cast<uintptr_t>(callback(obj, arg, 0, kRootUnknown));
+      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);
     }
   }
 }
@@ -350,7 +354,7 @@
 }
 
 void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
-  str_ = down_cast<mirror::String*>(callback(str_, arg, 0, kRootInternedString));
+  callback(reinterpret_cast<mirror::Object**>(&str_), arg, 0, kRootInternedString);
 }
 
 void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
@@ -412,7 +416,8 @@
 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));
-    it.second = reinterpret_cast<uintptr_t>(callback(obj, arg, 0, kRootUnknown));
+    callback(&obj, arg, 0, kRootUnknown);
+    it.second = reinterpret_cast<uintptr_t>(obj);
   }
 }
 
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 dcf75d0..e68ad7f 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -110,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)
 
@@ -123,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)
 
@@ -133,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/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"