Merge "x86: GenSelect utility update"
diff --git a/Android.mk b/Android.mk
index 5a819f6..c5e90f2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -127,7 +127,6 @@
 
 include $(art_path)/build/Android.common_test.mk
 include $(art_path)/build/Android.gtest.mk
-include $(art_path)/test/Android.oat.mk
 include $(art_path)/test/Android.run-test.mk
 
 # Sync test files to the target, depends upon all things that must be pushed to the target.
@@ -169,65 +168,59 @@
 
 # "mm test-art-host" to build and run all host tests.
 .PHONY: test-art-host
-test-art-host: test-art-host-gtest test-art-host-oat test-art-host-run-test test-art-host-vixl
+test-art-host: test-art-host-gtest test-art-host-run-test test-art-host-vixl
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # All host tests that run solely with the default compiler.
 .PHONY: test-art-host-default
-test-art-host-default: test-art-host-oat-default test-art-host-run-test-default
+test-art-host-default: test-art-host-run-test-default
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # All host tests that run solely with the optimizing compiler.
 .PHONY: test-art-host-optimizing
-test-art-host-optimizing: test-art-host-oat-optimizing test-art-host-run-test-optimizing
+test-art-host-optimizing: test-art-host-run-test-optimizing
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # All host tests that run solely on the interpreter.
 .PHONY: test-art-host-interpreter
-test-art-host-interpreter: test-art-host-oat-interpreter test-art-host-run-test-interpreter
+test-art-host-interpreter: test-art-host-run-test-interpreter
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # Primary host architecture variants:
 .PHONY: test-art-host$(ART_PHONY_TEST_HOST_SUFFIX)
 test-art-host$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-gtest$(ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-oat$(ART_PHONY_TEST_HOST_SUFFIX) test-art-host-run-test$(ART_PHONY_TEST_HOST_SUFFIX)
+    test-art-host-run-test$(ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-host-default$(ART_PHONY_TEST_HOST_SUFFIX)
-test-art-host-default$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-default$(ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-run-test-default$(ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-default$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-run-test-default$(ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-host-optimizing$(ART_PHONY_TEST_HOST_SUFFIX)
-test-art-host-optimizing$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-optimizing$(ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-run-test-optimizing$(ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-optimizing$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-run-test-optimizing$(ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-host-interpreter$(ART_PHONY_TEST_HOST_SUFFIX)
-test-art-host-interpreter$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-interpreter$(ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-run-test-interpreter$(ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-interpreter$(ART_PHONY_TEST_HOST_SUFFIX): test-art-host-run-test-interpreter$(ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # Secondary host architecture variants:
 ifneq ($(HOST_PREFER_32_BIT),true)
 .PHONY: test-art-host$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
 test-art-host$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-gtest$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-oat$(2ND_ART_PHONY_TEST_HOST_SUFFIX) test-art-host-run-test$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+    test-art-host-run-test$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-host-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
-test-art-host-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-run-test-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-run-test-default$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-host-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
-test-art-host-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-run-test-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-run-test-optimizing$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-host-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
-test-art-host-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-oat-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX) \
-    test-art-host-run-test-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
+test-art-host-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX): test-art-host-run-test-interpreter$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 endif
 
@@ -236,65 +229,59 @@
 
 # "mm test-art-target" to build and run all target tests.
 .PHONY: test-art-target
-test-art-target: test-art-target-gtest test-art-target-oat test-art-target-run-test
+test-art-target: test-art-target-gtest test-art-target-run-test
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # All target tests that run solely with the default compiler.
 .PHONY: test-art-target-default
-test-art-target-default: test-art-target-oat-default test-art-target-run-test-default
+test-art-target-default: test-art-target-run-test-default
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # All target tests that run solely with the optimizing compiler.
 .PHONY: test-art-target-optimizing
-test-art-target-optimizing: test-art-target-oat-optimizing test-art-target-run-test-optimizing
+test-art-target-optimizing: test-art-target-run-test-optimizing
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # All target tests that run solely on the interpreter.
 .PHONY: test-art-target-interpreter
-test-art-target-interpreter: test-art-target-oat-interpreter test-art-target-run-test-interpreter
+test-art-target-interpreter: test-art-target-run-test-interpreter
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # Primary target architecture variants:
 .PHONY: test-art-target$(ART_PHONY_TEST_TARGET_SUFFIX)
 test-art-target$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-gtest$(ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-oat$(ART_PHONY_TEST_TARGET_SUFFIX) test-art-target-run-test$(ART_PHONY_TEST_TARGET_SUFFIX)
+    test-art-target-run-test$(ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-target-default$(ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-default$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-default$(ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-run-test-default$(ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-default$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-run-test-default$(ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-target-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-run-test-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-run-test-optimizing$(ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-target-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-run-test-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-run-test-interpreter$(ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 # Secondary target architecture variants:
 ifdef TARGET_2ND_ARCH
 .PHONY: test-art-target$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
 test-art-target$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-gtest$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-oat$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) test-art-target-run-test$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+    test-art-target-run-test$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-target-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-run-test-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-run-test-default$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-target-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-run-test-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-run-test-optimizing$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 
 .PHONY: test-art-target-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-test-art-target-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-oat-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX) \
-    test-art-target-run-test-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
+test-art-target-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX): test-art-target-run-test-interpreter$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 endif
 
@@ -322,7 +309,7 @@
 .PHONY: oat-target-$(1)
 oat-target-$(1): $$(OUT_OAT_FILE)
 
-$$(OUT_OAT_FILE): $(PRODUCT_OUT)/$(1) $(DEFAULT_DEX_PREOPT_BUILT_IMAGE) $(DEX2OATD_DEPENDENCY)
+$$(OUT_OAT_FILE): $(PRODUCT_OUT)/$(1) $(DEFAULT_DEX_PREOPT_BUILT_IMAGE) $(DEX2OATD)
 	@mkdir -p $$(dir $$@)
 	$(DEX2OATD) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \
 		--boot-image=$(DEFAULT_DEX_PREOPT_BUILT_IMAGE) --dex-file=$(PRODUCT_OUT)/$(1) \
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 8c0d9f2..bd1e8aa 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -31,7 +31,11 @@
 ART_TARGET_TEST_OUT := $(TARGET_OUT_DATA)/art-test
 
 # Directory used for temporary test files on the host.
+ifneq ($(TMPDIR),)
+ART_HOST_TEST_DIR := $(TMPDIR)/test-art-$(shell echo $$PPID)
+else
 ART_HOST_TEST_DIR := /tmp/test-art-$(shell echo $$PPID)
+endif
 
 # Core.oat location on the device.
 TARGET_CORE_OAT := $(ART_TARGET_TEST_DIR)/$(DEX2OAT_TARGET_ARCH)/core.oat
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index f26bca0..c50b4ae 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -21,7 +21,27 @@
 
 # List of known broken tests that we won't attempt to execute. The test name must be the full
 # rule name such as test-art-host-oat-optimizing-HelloWorld64.
-ART_TEST_KNOWN_BROKEN :=
+ART_TEST_KNOWN_BROKEN := \
+  test-art-host-run-test-gcstress-optimizing-no-prebuild-004-SignalTest32 \
+  test-art-host-run-test-gcstress-optimizing-prebuild-004-SignalTest32 \
+  test-art-host-run-test-gcstress-optimizing-norelocate-004-SignalTest32 \
+  test-art-host-run-test-gcstress-optimizing-relocate-004-SignalTest32 \
+  test-art-host-run-test-gcverify-optimizing-no-prebuild-004-SignalTest32 \
+  test-art-host-run-test-gcverify-optimizing-prebuild-004-SignalTest32 \
+  test-art-host-run-test-gcverify-optimizing-norelocate-004-SignalTest32 \
+  test-art-host-run-test-gcverify-optimizing-relocate-004-SignalTest32 \
+  test-art-host-run-test-optimizing-no-prebuild-004-SignalTest32 \
+  test-art-host-run-test-optimizing-prebuild-004-SignalTest32 \
+  test-art-host-run-test-optimizing-norelocate-004-SignalTest32 \
+  test-art-host-run-test-optimizing-relocate-004-SignalTest32 \
+  test-art-target-run-test-gcstress-optimizing-prebuild-004-SignalTest32 \
+  test-art-target-run-test-gcstress-optimizing-norelocate-004-SignalTest32 \
+  test-art-target-run-test-gcstress-default-prebuild-004-SignalTest32 \
+  test-art-target-run-test-gcstress-default-norelocate-004-SignalTest32 \
+  test-art-target-run-test-gcstress-optimizing-relocate-004-SignalTest32 \
+  test-art-target-run-test-gcstress-default-relocate-004-SignalTest32 \
+  test-art-target-run-test-gcstress-optimizing-no-prebuild-004-SignalTest32 \
+  test-art-target-run-test-gcstress-default-no-prebuild-004-SignalTest32
 
 # List of known failing tests that when executed won't cause test execution to not finish.
 # The test name must be the full rule name such as test-art-host-oat-optimizing-HelloWorld64.
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index d75644d..2cba0ec 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -127,6 +127,7 @@
   runtime/reflection_test.cc \
   compiler/dex/global_value_numbering_test.cc \
   compiler/dex/local_value_numbering_test.cc \
+  compiler/dex/mir_graph_test.cc \
   compiler/dex/mir_optimization_test.cc \
   compiler/driver/compiler_driver_test.cc \
   compiler/elf_writer_test.cc \
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 10936a4..cd6b13a 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -26,7 +26,7 @@
 # Use dex2oat debug version for better error reporting
 # $(1): 2ND_ or undefined, 2ND_ for 32-bit host builds.
 define create-core-oat-host-rules
-$$($(1)HOST_CORE_IMG_OUT): $$(HOST_CORE_DEX_FILES) $$(DEX2OATD_DEPENDENCY)
+$$($(1)HOST_CORE_IMG_OUT): $$(HOST_CORE_DEX_FILES) $$(DEX2OATD)
 	@echo "host dex2oat: $$@ ($$?)"
 	@mkdir -p $$(dir $$@)
 	$$(hide) $$(DEX2OATD) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
@@ -49,7 +49,7 @@
 endif
 
 define create-core-oat-target-rules
-$$($(1)TARGET_CORE_IMG_OUT): $$($(1)TARGET_CORE_DEX_FILES) $$(DEX2OATD_DEPENDENCY)
+$$($(1)TARGET_CORE_IMG_OUT): $$($(1)TARGET_CORE_DEX_FILES) $$(DEX2OATD)
 	@echo "target dex2oat: $$@ ($$?)"
 	@mkdir -p $$(dir $$@)
 	$$(hide) $$(DEX2OATD) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) \
diff --git a/compiler/dex/bb_optimizations.h b/compiler/dex/bb_optimizations.h
index d1d5ad9..7395324 100644
--- a/compiler/dex/bb_optimizations.h
+++ b/compiler/dex/bb_optimizations.h
@@ -172,7 +172,7 @@
 class ClassInitCheckElimination : public PassME {
  public:
   ClassInitCheckElimination()
-    : PassME("ClInitCheckElimination", kRepeatingTopologicalSortTraversal) {
+    : PassME("ClInitCheckElimination", kLoopRepeatingTopologicalSortTraversal) {
   }
 
   bool Gate(const PassDataHolder* data) const {
@@ -207,17 +207,17 @@
 class GlobalValueNumberingPass : public PassME {
  public:
   GlobalValueNumberingPass()
-    : PassME("GVN", kRepeatingTopologicalSortTraversal, "4_post_gvn_cfg") {
+    : PassME("GVN", kLoopRepeatingTopologicalSortTraversal, "4_post_gvn_cfg") {
   }
 
-  bool Gate(const PassDataHolder* data) const {
+  bool Gate(const PassDataHolder* data) const OVERRIDE {
     DCHECK(data != nullptr);
     CompilationUnit* cUnit = down_cast<const PassMEDataHolder*>(data)->c_unit;
     DCHECK(cUnit != nullptr);
     return cUnit->mir_graph->ApplyGlobalValueNumberingGate();
   }
 
-  bool Worker(const PassDataHolder* data) const {
+  bool Worker(const PassDataHolder* data) const OVERRIDE {
     DCHECK(data != nullptr);
     const PassMEDataHolder* pass_me_data_holder = down_cast<const PassMEDataHolder*>(data);
     CompilationUnit* cUnit = pass_me_data_holder->c_unit;
@@ -227,7 +227,7 @@
     return cUnit->mir_graph->ApplyGlobalValueNumbering(bb);
   }
 
-  void End(PassDataHolder* data) const {
+  void End(PassDataHolder* data) const OVERRIDE {
     DCHECK(data != nullptr);
     CompilationUnit* cUnit = down_cast<PassMEDataHolder*>(data)->c_unit;
     DCHECK(cUnit != nullptr);
diff --git a/compiler/dex/dataflow_iterator-inl.h b/compiler/dex/dataflow_iterator-inl.h
index f8b9c1a..d1abf7f 100644
--- a/compiler/dex/dataflow_iterator-inl.h
+++ b/compiler/dex/dataflow_iterator-inl.h
@@ -121,6 +121,56 @@
   return res;
 }
 
+inline BasicBlock* LoopRepeatingTopologicalSortIterator::Next(bool had_change) {
+  if (idx_ != 0) {
+    // Mark last processed block visited.
+    BasicBlock* bb = mir_graph_->GetBasicBlock(block_id_list_->Get(idx_ - 1));
+    bb->visited = true;
+    if (had_change) {
+      // If we had a change we need to revisit the children.
+      ChildBlockIterator iter(bb, mir_graph_);
+      for (BasicBlock* child_bb = iter.Next(); child_bb != nullptr; child_bb = iter.Next()) {
+        child_bb->visited = false;
+      }
+    }
+  }
+
+  while (true) {
+    // Pop loops we have left and check if we need to recalculate one of them.
+    // NOTE: We need to do this even if idx_ == end_idx_.
+    while (loop_head_stack_->Size() != 0u &&
+        loop_ends_->Get(loop_head_stack_->Peek().first) == idx_) {
+      auto top = loop_head_stack_->Peek();
+      uint16_t loop_head_idx = top.first;
+      bool recalculated = top.second;
+      loop_head_stack_->Pop();
+      BasicBlock* loop_head = mir_graph_->GetBasicBlock(block_id_list_->Get(loop_head_idx));
+      DCHECK(loop_head != nullptr);
+      if (!recalculated || !loop_head->visited) {
+        loop_head_stack_->Insert(std::make_pair(loop_head_idx, true));  // Recalculating this loop.
+        idx_ = loop_head_idx + 1;
+        return loop_head;
+      }
+    }
+
+    if (idx_ == end_idx_) {
+      return nullptr;
+    }
+
+    // Get next block and return it if unvisited.
+    BasicBlockId idx = idx_;
+    idx_ += 1;
+    BasicBlock* bb = mir_graph_->GetBasicBlock(block_id_list_->Get(idx));
+    DCHECK(bb != nullptr);
+    if (!bb->visited) {
+      if (loop_ends_->Get(idx) != 0u) {
+        loop_head_stack_->Insert(std::make_pair(idx, false));  // Not recalculating.
+      }
+      return bb;
+    }
+  }
+}
+
 }  // namespace art
 
 #endif  // ART_COMPILER_DEX_DATAFLOW_ITERATOR_INL_H_
diff --git a/compiler/dex/dataflow_iterator.h b/compiler/dex/dataflow_iterator.h
index 66c524f..06d6832 100644
--- a/compiler/dex/dataflow_iterator.h
+++ b/compiler/dex/dataflow_iterator.h
@@ -388,6 +388,52 @@
      }
   };
 
+  /**
+   * @class LoopRepeatingTopologicalSortIterator
+   * @brief Used to perform a Topological Sort Iteration of a MIRGraph, repeating loops as needed.
+   * @details The iterator uses the visited flags to keep track of the blocks that need
+   * recalculation and keeps a stack of loop heads in the MIRGraph. At the end of the loop
+   * it returns back to the loop head if it needs to be recalculated. Due to the use of
+   * the visited flags and the loop head stack in the MIRGraph, it's not possible to use
+   * two iterators at the same time or modify this data during iteration (though inspection
+   * of this data is allowed and sometimes even expected).
+   *
+   * NOTE: This iterator is not suitable for passes that need to propagate changes to
+   * predecessors, such as type inferrence.
+   */
+  class LoopRepeatingTopologicalSortIterator : public DataflowIterator {
+    public:
+     /**
+      * @brief The constructor, using all of the reachable blocks of the MIRGraph.
+      * @param mir_graph The MIRGraph considered.
+      */
+     explicit LoopRepeatingTopologicalSortIterator(MIRGraph* mir_graph)
+         : DataflowIterator(mir_graph, 0, mir_graph->GetTopologicalSortOrder()->Size()),
+           loop_ends_(mir_graph->GetTopologicalSortOrderLoopEnds()),
+           loop_head_stack_(mir_graph_->GetTopologicalSortOrderLoopHeadStack()) {
+       // Extra setup for RepeatingTopologicalSortIterator.
+       idx_ = start_idx_;
+       block_id_list_ = mir_graph->GetTopologicalSortOrder();
+       // Clear visited flags and check that the loop head stack is empty.
+       mir_graph->ClearAllVisitedFlags();
+       DCHECK_EQ(loop_head_stack_->Size(), 0u);
+     }
+
+     ~LoopRepeatingTopologicalSortIterator() {
+       DCHECK_EQ(loop_head_stack_->Size(), 0u);
+     }
+
+     /**
+      * @brief Get the next BasicBlock depending on iteration order.
+      * @param had_change did the user of the iteration change the previous BasicBlock.
+      * @return the next BasicBlock following the iteration order, 0 if finished.
+      */
+     virtual BasicBlock* Next(bool had_change = false) OVERRIDE;
+
+    private:
+     const GrowableArray<BasicBlockId>* const loop_ends_;
+     GrowableArray<std::pair<uint16_t, bool>>* const loop_head_stack_;
+  };
 
 }  // namespace art
 
diff --git a/compiler/dex/global_value_numbering.cc b/compiler/dex/global_value_numbering.cc
index 614e826..d86be4e 100644
--- a/compiler/dex/global_value_numbering.cc
+++ b/compiler/dex/global_value_numbering.cc
@@ -22,8 +22,10 @@
 
 GlobalValueNumbering::GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator)
     : cu_(cu),
+      mir_graph_(cu->mir_graph.get()),
       allocator_(allocator),
-      repeat_count_(0u),
+      bbs_processed_(0u),
+      max_bbs_to_process_(kMaxBbsToProcessMultiplyFactor * mir_graph_->GetNumReachableBlocks()),
       last_value_(0u),
       modifications_allowed_(false),
       global_value_map_(std::less<uint64_t>(), allocator->Adapter()),
@@ -32,10 +34,9 @@
       array_location_map_(ArrayLocationComparator(), allocator->Adapter()),
       array_location_reverse_map_(allocator->Adapter()),
       ref_set_map_(std::less<ValueNameSet>(), allocator->Adapter()),
-      lvns_(cu_->mir_graph->GetNumBlocks(), nullptr, allocator->Adapter()),
+      lvns_(mir_graph_->GetNumBlocks(), nullptr, allocator->Adapter()),
       work_lvn_(nullptr),
       merge_lvns_(allocator->Adapter()) {
-  cu_->mir_graph->ClearAllVisitedFlags();
 }
 
 GlobalValueNumbering::~GlobalValueNumbering() {
@@ -46,21 +47,15 @@
   if (UNLIKELY(!Good())) {
     return nullptr;
   }
-  if (bb->data_flow_info == nullptr) {
+  if (UNLIKELY(bb->data_flow_info == nullptr)) {
     return nullptr;
   }
-  if (bb->block_type == kEntryBlock) {
-    repeat_count_ += 1u;
-    if (repeat_count_ > kMaxRepeatCount) {
-      last_value_ = kNoValue;  // Make bad.
-      return nullptr;
-    }
-  }
-  if (bb->block_type == kExitBlock) {
+  if (UNLIKELY(bb->block_type == kExitBlock)) {
     DCHECK(bb->first_mir_insn == nullptr);
     return nullptr;
   }
-  if (bb->visited) {
+  if (UNLIKELY(bbs_processed_ == max_bbs_to_process_)) {
+    last_value_ = kNoValue;  // Make bad.
     return nullptr;
   }
   DCHECK(work_lvn_.get() == nullptr);
@@ -72,13 +67,34 @@
       work_lvn_->SetSRegNullChecked(this_reg);
     }
   } else {
-    // Merge all incoming arcs.
     // To avoid repeated allocation on the ArenaStack, reuse a single vector kept as a member.
     DCHECK(merge_lvns_.empty());
+    // If we're running the full GVN, the RepeatingTopologicalSortIterator keeps the loop
+    // head stack in the MIRGraph up to date and for a loop head we need to check whether
+    // we're making the initial computation and need to merge only preceding blocks in the
+    // topological order, or we're recalculating a loop head and need to merge all incoming
+    // LVNs. When we're not at a loop head (including having an empty loop head stack) all
+    // predecessors should be preceding blocks and we shall merge all of them anyway.
+    //
+    // If we're running the modification phase of the full GVN, the loop head stack will be
+    // empty and we need to merge all incoming LVNs. If we're running just a simple LVN,
+    // the loop head stack will also be empty and there will be nothing to merge anyway.
+    bool use_all_predecessors = true;
+    uint16_t loop_head_idx = 0u;  // Used only if !use_all_predecessors.
+    if (mir_graph_->GetTopologicalSortOrderLoopHeadStack()->Size() != 0) {
+      // Full GVN inside a loop, see if we're at the loop head for the first time.
+      auto top = mir_graph_->GetTopologicalSortOrderLoopHeadStack()->Peek();
+      loop_head_idx = top.first;
+      bool recalculating = top.second;
+      use_all_predecessors = recalculating ||
+          loop_head_idx != mir_graph_->GetTopologicalSortOrderIndexes()->Get(bb->id);
+    }
     GrowableArray<BasicBlockId>::Iterator iter(bb->predecessors);
-    for (BasicBlock* pred_bb = cu_->mir_graph->GetBasicBlock(iter.Next());
-         pred_bb != nullptr; pred_bb = cu_->mir_graph->GetBasicBlock(iter.Next())) {
-      if (lvns_[pred_bb->id] != nullptr) {
+    for (BasicBlock* pred_bb = mir_graph_->GetBasicBlock(iter.Next());
+         pred_bb != nullptr; pred_bb = mir_graph_->GetBasicBlock(iter.Next())) {
+      if (lvns_[pred_bb->id] != nullptr &&
+          (use_all_predecessors ||
+              mir_graph_->GetTopologicalSortOrderIndexes()->Get(pred_bb->id) < loop_head_idx)) {
         merge_lvns_.push_back(lvns_[pred_bb->id]);
       }
     }
@@ -87,19 +103,22 @@
     if (bb->catch_entry) {
       merge_type = LocalValueNumbering::kCatchMerge;
     } else if (bb->last_mir_insn != nullptr &&
-        (bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN ||
+        (bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_VOID ||
+         bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN ||
          bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_OBJECT ||
          bb->last_mir_insn->dalvikInsn.opcode == Instruction::RETURN_WIDE) &&
         (bb->first_mir_insn == bb->last_mir_insn ||
-         (bb->first_mir_insn->next == bb->last_mir_insn &&
-          static_cast<int>(bb->first_mir_insn->dalvikInsn.opcode) == kMirOpPhi))) {
+         (static_cast<int>(bb->first_mir_insn->dalvikInsn.opcode) == kMirOpPhi &&
+          (bb->first_mir_insn->next == bb->last_mir_insn ||
+           (static_cast<int>(bb->first_mir_insn->next->dalvikInsn.opcode) == kMirOpPhi &&
+            bb->first_mir_insn->next->next == bb->last_mir_insn))))) {
       merge_type = LocalValueNumbering::kReturnMerge;
     }
     // At least one predecessor must have been processed before this bb.
     CHECK(!merge_lvns_.empty());
     if (merge_lvns_.size() == 1u) {
       work_lvn_->MergeOne(*merge_lvns_[0], merge_type);
-      BasicBlock* pred_bb = cu_->mir_graph->GetBasicBlock(merge_lvns_[0]->Id());
+      BasicBlock* pred_bb = mir_graph_->GetBasicBlock(merge_lvns_[0]->Id());
       if (HasNullCheckLastInsn(pred_bb, bb->id)) {
         work_lvn_->SetSRegNullChecked(pred_bb->last_mir_insn->ssa_rep->uses[0]);
       }
@@ -112,32 +131,13 @@
 
 bool GlobalValueNumbering::FinishBasicBlock(BasicBlock* bb) {
   DCHECK(work_lvn_ != nullptr);
-  DCHECK(bb->id == work_lvn_->Id());
+  DCHECK_EQ(bb->id, work_lvn_->Id());
+  ++bbs_processed_;
   merge_lvns_.clear();
 
-  bool change = false;
-  // Look for a branch to self or an already processed child.
-  // (No need to repeat the LVN if all children are processed later.)
-  ChildBlockIterator iter(bb, cu_->mir_graph.get());
-  for (BasicBlock* child = iter.Next(); child != nullptr; child = iter.Next()) {
-    if (child == bb || lvns_[child->id] != nullptr) {
-      // If we found an already processed child, check if the LVN actually differs.
-      change = (lvns_[bb->id] == nullptr || !lvns_[bb->id]->Equals(*work_lvn_));
-      break;
-    }
-  }
-
   std::unique_ptr<const LocalValueNumbering> old_lvn(lvns_[bb->id]);
   lvns_[bb->id] = work_lvn_.release();
-
-  bb->visited = true;
-  if (change) {
-    ChildBlockIterator iter(bb, cu_->mir_graph.get());
-    for (BasicBlock* child = iter.Next(); child != nullptr; child = iter.Next()) {
-      child->visited = false;
-    }
-  }
-  return change;
+  return (old_lvn == nullptr) || !old_lvn->Equals(*lvns_[bb->id]);
 }
 
 uint16_t GlobalValueNumbering::GetFieldId(const MirFieldInfo& field_info, uint16_t type) {
@@ -188,7 +188,7 @@
     uint16_t value_name = merge_names[i];
     if (!pred_lvn->IsValueNullChecked(value_name)) {
       // Check if the predecessor has an IF_EQZ/IF_NEZ as the last insn.
-      const BasicBlock* pred_bb = cu_->mir_graph->GetBasicBlock(pred_lvn->Id());
+      const BasicBlock* pred_bb = mir_graph_->GetBasicBlock(pred_lvn->Id());
       if (!HasNullCheckLastInsn(pred_bb, work_lvn_->Id())) {
         return false;
       }
diff --git a/compiler/dex/global_value_numbering.h b/compiler/dex/global_value_numbering.h
index 7ab77b7..a12a779 100644
--- a/compiler/dex/global_value_numbering.h
+++ b/compiler/dex/global_value_numbering.h
@@ -31,7 +31,10 @@
   GlobalValueNumbering(CompilationUnit* cu, ScopedArenaAllocator* allocator);
   ~GlobalValueNumbering();
 
+  // Prepare LVN for the basic block.
   LocalValueNumbering* PrepareBasicBlock(BasicBlock* bb);
+
+  // Finish processing the basic block.
   bool FinishBasicBlock(BasicBlock* bb);
 
   // Checks that the value names didn't overflow.
@@ -42,7 +45,6 @@
   // Allow modifications.
   void AllowModifications() {
     DCHECK(Good());
-    cu_->mir_graph->ClearAllVisitedFlags();
     modifications_allowed_ = true;
   }
 
@@ -182,7 +184,7 @@
   }
 
   const BasicBlock* GetBasicBlock(uint16_t bb_id) const {
-    return cu_->mir_graph->GetBasicBlock(bb_id);
+    return mir_graph_->GetBasicBlock(bb_id);
   }
 
   static bool HasNullCheckLastInsn(const BasicBlock* pred_bb, BasicBlockId succ_id);
@@ -194,7 +196,7 @@
   }
 
   MIRGraph* GetMirGraph() const {
-    return cu_->mir_graph.get();
+    return mir_graph_;
   }
 
   ScopedArenaAllocator* Allocator() const {
@@ -202,12 +204,16 @@
   }
 
   CompilationUnit* const cu_;
+  MIRGraph* mir_graph_;
   ScopedArenaAllocator* const allocator_;
 
-  static constexpr uint32_t kMaxRepeatCount = 10u;
+  // The number of BBs that we need to process grows exponentially with the number
+  // of nested loops. Don't allow excessive processing for too many nested loops or
+  // otherwise expensive methods.
+  static constexpr uint32_t kMaxBbsToProcessMultiplyFactor = 20u;
 
-  // Track the repeat count to make sure the GVN converges quickly and abort the GVN otherwise.
-  uint32_t repeat_count_;
+  uint32_t bbs_processed_;
+  uint32_t max_bbs_to_process_;
 
   // We have 32-bit last_value_ so that we can detect when we run out of value names, see Good().
   // We usually don't check Good() until the end of LVN unless we're about to modify code.
diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc
index 18adbab..c82d231 100644
--- a/compiler/dex/global_value_numbering_test.cc
+++ b/compiler/dex/global_value_numbering_test.cc
@@ -273,23 +273,20 @@
   }
 
   void PerformGVN() {
-    cu_.mir_graph->SSATransformationStart();
-    cu_.mir_graph->ComputeDFSOrders();
-    cu_.mir_graph->ComputeDominators();
-    cu_.mir_graph->ComputeTopologicalSortOrder();
-    cu_.mir_graph->SSATransformationEnd();
-    DoPerformGVN<RepeatingPreOrderDfsIterator>();
+    DoPerformGVN<LoopRepeatingTopologicalSortIterator>();
   }
 
   void PerformPreOrderDfsGVN() {
-    cu_.mir_graph->SSATransformationStart();
-    cu_.mir_graph->ComputeDFSOrders();
-    cu_.mir_graph->SSATransformationEnd();
     DoPerformGVN<RepeatingPreOrderDfsIterator>();
   }
 
   template <typename IteratorType>
   void DoPerformGVN() {
+    cu_.mir_graph->SSATransformationStart();
+    cu_.mir_graph->ComputeDFSOrders();
+    cu_.mir_graph->ComputeDominators();
+    cu_.mir_graph->ComputeTopologicalSortOrder();
+    cu_.mir_graph->SSATransformationEnd();
     ASSERT_TRUE(gvn_ == nullptr);
     gvn_.reset(new (allocator_.get()) GlobalValueNumbering(&cu_, allocator_.get()));
     ASSERT_FALSE(gvn_->CanModify());
@@ -313,7 +310,7 @@
     ASSERT_TRUE(gvn_->Good());
     ASSERT_FALSE(gvn_->CanModify());
     gvn_->AllowModifications();
-    PreOrderDfsIterator iterator(cu_.mir_graph.get());
+    TopologicalSortIterator iterator(cu_.mir_graph.get());
     for (BasicBlock* bb = iterator.Next(); bb != nullptr; bb = iterator.Next()) {
       LocalValueNumbering* lvn = gvn_->PrepareBasicBlock(bb);
       if (lvn != nullptr) {
@@ -340,7 +337,6 @@
     cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
     cu_.access_flags = kAccStatic;  // Don't let "this" interfere with this test.
     allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack));
-    // gvn_->AllowModifications();
   }
 
   ArenaPool pool_;
@@ -1917,7 +1913,7 @@
   PerformPreOrderDfsGVN();
 }
 
-TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, DISABLED_IFieldAndPhi) {
+TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, IFieldAndPhi) {
   static const IFieldDef ifields[] = {
       { 0u, 1u, 0u, false },  // Int.
   };
@@ -1954,7 +1950,7 @@
   EXPECT_EQ(value_names_[5], value_names_[12]);
 }
 
-TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, DISABLED_NullCheck) {
+TEST_F(GlobalValueNumberingTestTwoConsecutiveLoops, NullCheck) {
   static const IFieldDef ifields[] = {
       { 0u, 1u, 0u, false },  // Int.
   };
@@ -2024,14 +2020,10 @@
   EXPECT_NE(value_names_[2], value_names_[6]);
   EXPECT_NE(value_names_[3], value_names_[7]);
   EXPECT_NE(value_names_[4], value_names_[8]);
-  EXPECT_NE(value_names_[0], value_names_[12]);
-  EXPECT_NE(value_names_[1], value_names_[13]);
-  EXPECT_NE(value_names_[2], value_names_[14]);
-  EXPECT_NE(value_names_[3], value_names_[15]);
   EXPECT_EQ(value_names_[4], value_names_[12]);
-  EXPECT_NE(value_names_[5], value_names_[13]);
-  EXPECT_NE(value_names_[6], value_names_[14]);
-  EXPECT_NE(value_names_[7], value_names_[15]);
+  EXPECT_EQ(value_names_[5], value_names_[13]);
+  EXPECT_EQ(value_names_[6], value_names_[14]);
+  EXPECT_EQ(value_names_[7], value_names_[15]);
   EXPECT_EQ(value_names_[12], value_names_[20]);
   EXPECT_EQ(value_names_[13], value_names_[21]);
   EXPECT_EQ(value_names_[14], value_names_[22]);
@@ -2049,7 +2041,7 @@
   }
 }
 
-TEST_F(GlobalValueNumberingTestTwoNestedLoops, DISABLED_IFieldAndPhi) {
+TEST_F(GlobalValueNumberingTestTwoNestedLoops, IFieldAndPhi) {
   static const IFieldDef ifields[] = {
       { 0u, 1u, 0u, false },  // Int.
   };
@@ -2097,7 +2089,7 @@
   static const BBDef bbs[] = {
       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
-      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(4)),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
       DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
       DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(3)),
       DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(3, 4)),
@@ -2108,6 +2100,15 @@
   PrepareBasicBlocks(bbs);
   BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(5u);
   catch_handler->catch_entry = true;
+  // Add successor block info to the check block.
+  BasicBlock* check_bb = cu_.mir_graph->GetBasicBlock(3u);
+  check_bb->successor_block_list_type = kCatch;
+  check_bb->successor_blocks = new (&cu_.arena) GrowableArray<SuccessorBlockInfo*>(
+      &cu_.arena, 2, kGrowableArraySuccessorBlocks);
+  SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
+      (cu_.arena.Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
+  successor_block_info->block = catch_handler->id;
+  check_bb->successor_blocks->Insert(successor_block_info);
   BasicBlock* merge_block = cu_.mir_graph->GetBasicBlock(4u);
   std::swap(merge_block->taken, merge_block->fall_through);
   PrepareMIRs(mirs);
diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc
index ef893fe..0e072ec 100644
--- a/compiler/dex/local_value_numbering.cc
+++ b/compiler/dex/local_value_numbering.cc
@@ -534,6 +534,10 @@
          (!cmp(entry, *work_it) && !(work_it->second == entry.second)))) {
       work_it = work_map->erase(work_it);
     }
+    if (work_it == work_end) {
+      return;
+    }
+    ++work_it;
   }
 }
 
@@ -855,13 +859,18 @@
   MergeMemoryVersions(merge_type == kCatchMerge);
 
   // Merge non-aliasing maps/sets.
-  MergeSets<IFieldLocToValueMap, &LocalValueNumbering::non_aliasing_ifield_value_map_,
-            &LocalValueNumbering::MergeNonAliasingIFieldValues>();
-  MergeSets<NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
-            &LocalValueNumbering::MergeAliasingValues<
-                NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
-                NonAliasingArrayVersions>>();
   IntersectSets<ValueNameSet, &LocalValueNumbering::non_aliasing_refs_>();
+  if (!non_aliasing_refs_.empty() && merge_type == kCatchMerge) {
+    PruneNonAliasingRefsForCatch();
+  }
+  if (!non_aliasing_refs_.empty()) {
+    MergeSets<IFieldLocToValueMap, &LocalValueNumbering::non_aliasing_ifield_value_map_,
+              &LocalValueNumbering::MergeNonAliasingIFieldValues>();
+    MergeSets<NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
+              &LocalValueNumbering::MergeAliasingValues<
+                  NonAliasingArrayValuesMap, &LocalValueNumbering::non_aliasing_array_value_map_,
+                  NonAliasingArrayVersions>>();
+  }
 
   // We won't do anything complicated for range checks, just calculate the intersection.
   IntersectSets<RangeCheckSet, &LocalValueNumbering::range_checked_>();
@@ -872,7 +881,6 @@
 
   if (merge_type == kCatchMerge) {
     // Memory is clobbered. New memory version already created, don't merge aliasing locations.
-    PruneNonAliasingRefsForCatch();
     return;
   }
 
@@ -1361,8 +1369,8 @@
     case Instruction::MONITOR_EXIT:
       HandleNullCheck(mir, GetOperandValue(mir->ssa_rep->uses[0]));
       // If we're running GVN and CanModify(), uneliminated null check indicates bytecode error.
-      if ((gvn_->cu_->disable_opt & (1 << kGlobalValueNumbering)) == 0 && gvn_->CanModify() &&
-          (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0) {
+      if ((gvn_->GetCompilationUnit()->disable_opt & (1u << kGlobalValueNumbering)) == 0u &&
+          gvn_->CanModify() && (mir->optimization_flags & MIR_IGNORE_NULL_CHECK) == 0) {
         LOG(WARNING) << "Bytecode error: MONITOR_EXIT is still null checked at 0x" << std::hex
             << mir->offset << " in " << PrettyMethod(gvn_->cu_->method_idx, *gvn_->cu_->dex_file);
       }
diff --git a/compiler/dex/mir_graph.cc b/compiler/dex/mir_graph.cc
index 1c8a9b5..331af21 100644
--- a/compiler/dex/mir_graph.cc
+++ b/compiler/dex/mir_graph.cc
@@ -84,6 +84,9 @@
       dfs_post_order_(NULL),
       dom_post_order_traversal_(NULL),
       topological_order_(nullptr),
+      topological_order_loop_ends_(nullptr),
+      topological_order_indexes_(nullptr),
+      topological_order_loop_head_stack_(nullptr),
       i_dom_list_(NULL),
       def_block_matrix_(NULL),
       temp_scoped_alloc_(),
@@ -1526,117 +1529,248 @@
   temp_scoped_alloc_.reset();
 }
 
-void MIRGraph::ComputeTopologicalSortOrder() {
-  // Clear the nodes.
-  ClearAllVisitedFlags();
-
-  // Create the topological order if need be.
-  if (topological_order_ == nullptr) {
-    topological_order_ = new (arena_) GrowableArray<BasicBlockId>(arena_, GetNumBlocks());
-  }
-  topological_order_->Reset();
-
-  ScopedArenaAllocator allocator(&cu_->arena_stack);
-  ScopedArenaQueue<BasicBlock*> q(allocator.Adapter());
-  ScopedArenaVector<size_t> visited_cnt_values(GetNumBlocks(), 0u, allocator.Adapter());
-
-  // Set up visitedCntValues map for all BB. The default value for this counters in the map is zero.
-  // also fill initial queue.
-  GrowableArray<BasicBlock*>::Iterator iterator(&block_list_);
-
-  size_t num_blocks = 0u;
-  while (true) {
-    BasicBlock* bb = iterator.Next();
-
-    if (bb == nullptr) {
-      break;
+static BasicBlock* SelectTopologicalSortOrderFallBack(
+    MIRGraph* mir_graph, const ArenaBitVector* current_loop,
+    const ScopedArenaVector<size_t>* visited_cnt_values, ScopedArenaAllocator* allocator,
+    ScopedArenaVector<BasicBlockId>* tmp_stack) {
+  // No true loop head has been found but there may be true loop heads after the mess we need
+  // to resolve. To avoid taking one of those, pick the candidate with the highest number of
+  // reachable unvisited nodes. That candidate will surely be a part of a loop.
+  BasicBlock* fall_back = nullptr;
+  size_t fall_back_num_reachable = 0u;
+  // Reuse the same bit vector for each candidate to mark reachable unvisited blocks.
+  ArenaBitVector candidate_reachable(allocator, mir_graph->GetNumBlocks(), false, kBitMapMisc);
+  AllNodesIterator iter(mir_graph);
+  for (BasicBlock* candidate = iter.Next(); candidate != nullptr; candidate = iter.Next()) {
+    if (candidate->hidden ||                            // Hidden, or
+        candidate->visited ||                           // already processed, or
+        (*visited_cnt_values)[candidate->id] == 0u ||   // no processed predecessors, or
+        (current_loop != nullptr &&                     // outside current loop.
+         !current_loop->IsBitSet(candidate->id))) {
+      continue;
     }
+    DCHECK(tmp_stack->empty());
+    tmp_stack->push_back(candidate->id);
+    candidate_reachable.ClearAllBits();
+    size_t num_reachable = 0u;
+    while (!tmp_stack->empty()) {
+      BasicBlockId current_id = tmp_stack->back();
+      tmp_stack->pop_back();
+      BasicBlock* current_bb = mir_graph->GetBasicBlock(current_id);
+      DCHECK(current_bb != nullptr);
+      ChildBlockIterator child_iter(current_bb, mir_graph);
+      BasicBlock* child_bb = child_iter.Next();
+      for ( ; child_bb != nullptr; child_bb = child_iter.Next()) {
+        DCHECK(!child_bb->hidden);
+        if (child_bb->visited ||                            // Already processed, or
+            (current_loop != nullptr &&                     // outside current loop.
+             !current_loop->IsBitSet(child_bb->id))) {
+          continue;
+        }
+        if (!candidate_reachable.IsBitSet(child_bb->id)) {
+          candidate_reachable.SetBit(child_bb->id);
+          tmp_stack->push_back(child_bb->id);
+          num_reachable += 1u;
+        }
+      }
+    }
+    if (fall_back_num_reachable < num_reachable) {
+      fall_back_num_reachable = num_reachable;
+      fall_back = candidate;
+    }
+  }
+  return fall_back;
+}
 
+// Compute from which unvisited blocks is bb_id reachable through unvisited blocks.
+static void ComputeUnvisitedReachableFrom(MIRGraph* mir_graph, BasicBlockId bb_id,
+                                          ArenaBitVector* reachable,
+                                          ScopedArenaVector<BasicBlockId>* tmp_stack) {
+  // NOTE: Loop heads indicated by the "visited" flag.
+  DCHECK(tmp_stack->empty());
+  reachable->ClearAllBits();
+  tmp_stack->push_back(bb_id);
+  while (!tmp_stack->empty()) {
+    BasicBlockId current_id = tmp_stack->back();
+    tmp_stack->pop_back();
+    BasicBlock* current_bb = mir_graph->GetBasicBlock(current_id);
+    DCHECK(current_bb != nullptr);
+    GrowableArray<BasicBlockId>::Iterator iter(current_bb->predecessors);
+    BasicBlock* pred_bb = mir_graph->GetBasicBlock(iter.Next());
+    for ( ; pred_bb != nullptr; pred_bb = mir_graph->GetBasicBlock(iter.Next())) {
+      if (!pred_bb->visited && !reachable->IsBitSet(pred_bb->id)) {
+        reachable->SetBit(pred_bb->id);
+        tmp_stack->push_back(pred_bb->id);
+      }
+    }
+  }
+}
+
+void MIRGraph::ComputeTopologicalSortOrder() {
+  ScopedArenaAllocator allocator(&cu_->arena_stack);
+  unsigned int num_blocks = GetNumBlocks();
+
+  ScopedArenaQueue<BasicBlock*> q(allocator.Adapter());
+  ScopedArenaVector<size_t> visited_cnt_values(num_blocks, 0u, allocator.Adapter());
+  ScopedArenaVector<BasicBlockId> loop_head_stack(allocator.Adapter());
+  size_t max_nested_loops = 0u;
+  ArenaBitVector loop_exit_blocks(&allocator, num_blocks, false, kBitMapMisc);
+  loop_exit_blocks.ClearAllBits();
+
+  // Count the number of blocks to process and add the entry block(s).
+  GrowableArray<BasicBlock*>::Iterator iterator(&block_list_);
+  unsigned int num_blocks_to_process = 0u;
+  for (BasicBlock* bb = iterator.Next(); bb != nullptr; bb = iterator.Next()) {
     if (bb->hidden == true) {
       continue;
     }
 
-    num_blocks += 1u;
-    size_t unvisited_predecessor_count = bb->predecessors->Size();
+    num_blocks_to_process += 1u;
 
-    GrowableArray<BasicBlockId>::Iterator pred_iterator(bb->predecessors);
-    // To process loops we should not wait for dominators.
-    while (true) {
-      BasicBlock* pred_bb = GetBasicBlock(pred_iterator.Next());
-
-      if (pred_bb == nullptr) {
-        break;
-      }
-
-      // Skip the backward branch or hidden predecessor.
-      if (pred_bb->hidden ||
-          (pred_bb->dominators != nullptr && pred_bb->dominators->IsBitSet(bb->id))) {
-        unvisited_predecessor_count -= 1u;
-      }
-    }
-
-    visited_cnt_values[bb->id] = unvisited_predecessor_count;
-
-    // Add entry block to queue.
-    if (unvisited_predecessor_count == 0) {
+    if (bb->predecessors->Size() == 0u) {
+      // Add entry block to the queue.
       q.push(bb);
     }
   }
 
-  // We can get a cycle where none of the blocks dominates the other. Therefore don't
-  // stop when the queue is empty, continue until we've processed all the blocks.
-  AllNodesIterator candidate_iter(this);  // For the empty queue case.
-  while (num_blocks != 0u) {
-    num_blocks -= 1u;
+  // Create the topological order if need be.
+  if (topological_order_ == nullptr) {
+    topological_order_ = new (arena_) GrowableArray<BasicBlockId>(arena_, num_blocks);
+    topological_order_loop_ends_ = new (arena_) GrowableArray<uint16_t>(arena_, num_blocks);
+    topological_order_indexes_ = new (arena_) GrowableArray<uint16_t>(arena_, num_blocks);
+  }
+  topological_order_->Reset();
+  topological_order_loop_ends_->Reset();
+  topological_order_indexes_->Reset();
+  topological_order_loop_ends_->Resize(num_blocks);
+  topological_order_indexes_->Resize(num_blocks);
+  for (BasicBlockId i = 0; i != num_blocks; ++i) {
+    topological_order_loop_ends_->Insert(0u);
+    topological_order_indexes_->Insert(static_cast<uint16_t>(-1));
+  }
+
+  // Mark all blocks as unvisited.
+  ClearAllVisitedFlags();
+
+  // For loop heads, keep track from which blocks they are reachable not going through other
+  // loop heads. Other loop heads are excluded to detect the heads of nested loops. The children
+  // in this set go into the loop body, the other children are jumping over the loop.
+  ScopedArenaVector<ArenaBitVector*> loop_head_reachable_from(allocator.Adapter());
+  loop_head_reachable_from.resize(num_blocks, nullptr);
+  // Reuse the same temp stack whenever calculating a loop_head_reachable_from[loop_head_id].
+  ScopedArenaVector<BasicBlockId> tmp_stack(allocator.Adapter());
+
+  while (num_blocks_to_process != 0u) {
     BasicBlock* bb = nullptr;
     if (!q.empty()) {
+      num_blocks_to_process -= 1u;
       // Get top.
       bb = q.front();
       q.pop();
-    } else {
-      // Find some block we didn't visit yet that has at least one visited predecessor.
-      while (bb == nullptr) {
-        BasicBlock* candidate = candidate_iter.Next();
-        DCHECK(candidate != nullptr);
-        if (candidate->visited || candidate->hidden) {
-          continue;
-        }
-        GrowableArray<BasicBlockId>::Iterator iter(candidate->predecessors);
-        for (BasicBlock* pred_bb = GetBasicBlock(iter.Next()); pred_bb != nullptr;
-            pred_bb = GetBasicBlock(iter.Next())) {
-          if (!pred_bb->hidden && pred_bb->visited) {
-            bb = candidate;
-            break;
+      if (bb->visited) {
+        // Loop head: it was already processed, mark end and copy exit blocks to the queue.
+        DCHECK(q.empty()) << PrettyMethod(cu_->method_idx, *cu_->dex_file);
+        uint16_t idx = static_cast<uint16_t>(topological_order_->Size());
+        topological_order_loop_ends_->Put(topological_order_indexes_->Get(bb->id), idx);
+        DCHECK_EQ(loop_head_stack.back(), bb->id);
+        loop_head_stack.pop_back();
+        ArenaBitVector* reachable =
+            loop_head_stack.empty() ? nullptr : loop_head_reachable_from[loop_head_stack.back()];
+        for (BasicBlockId candidate_id : loop_exit_blocks.Indexes()) {
+          if (reachable == nullptr || reachable->IsBitSet(candidate_id)) {
+            q.push(GetBasicBlock(candidate_id));
+            // NOTE: The BitVectorSet::IndexIterator will not check the pointed-to bit again,
+            // so clearing the bit has no effect on the iterator.
+            loop_exit_blocks.ClearBit(candidate_id);
           }
         }
+        continue;
       }
+    } else {
+      // Find the new loop head.
+      AllNodesIterator iter(this);
+      while (true) {
+        BasicBlock* candidate = iter.Next();
+        if (candidate == nullptr) {
+          // We did not find a true loop head, fall back to a reachable block in any loop.
+          ArenaBitVector* current_loop =
+              loop_head_stack.empty() ? nullptr : loop_head_reachable_from[loop_head_stack.back()];
+          bb = SelectTopologicalSortOrderFallBack(this, current_loop, &visited_cnt_values,
+                                                  &allocator, &tmp_stack);
+          DCHECK(bb != nullptr) << PrettyMethod(cu_->method_idx, *cu_->dex_file);
+          if (kIsDebugBuild && cu_->dex_file != nullptr) {
+            LOG(INFO) << "Topological sort order: Using fall-back in "
+                << PrettyMethod(cu_->method_idx, *cu_->dex_file) << " BB #" << bb->id
+                << " @0x" << std::hex << bb->start_offset
+                << ", num_blocks = " << std::dec << num_blocks;
+          }
+          break;
+        }
+        if (candidate->hidden ||                            // Hidden, or
+            candidate->visited ||                           // already processed, or
+            visited_cnt_values[candidate->id] == 0u ||      // no processed predecessors, or
+            (!loop_head_stack.empty() &&                    // outside current loop.
+             !loop_head_reachable_from[loop_head_stack.back()]->IsBitSet(candidate->id))) {
+          continue;
+        }
+
+        GrowableArray<BasicBlockId>::Iterator pred_iter(candidate->predecessors);
+        BasicBlock* pred_bb = GetBasicBlock(pred_iter.Next());
+        for ( ; pred_bb != nullptr; pred_bb = GetBasicBlock(pred_iter.Next())) {
+          if (pred_bb != candidate && !pred_bb->visited &&
+              !pred_bb->dominators->IsBitSet(candidate->id)) {
+            break;  // Keep non-null pred_bb to indicate failure.
+          }
+        }
+        if (pred_bb == nullptr) {
+          bb = candidate;
+          break;
+        }
+      }
+      // Compute blocks from which the loop head is reachable and process those blocks first.
+      ArenaBitVector* reachable =
+          new (&allocator) ArenaBitVector(&allocator, num_blocks, false, kBitMapMisc);
+      loop_head_reachable_from[bb->id] = reachable;
+      ComputeUnvisitedReachableFrom(this, bb->id, reachable, &tmp_stack);
+      // Now mark as loop head. (Even if it's only a fall back when we don't find a true loop.)
+      loop_head_stack.push_back(bb->id);
+      max_nested_loops = std::max(max_nested_loops, loop_head_stack.size());
     }
 
     DCHECK_EQ(bb->hidden, false);
     DCHECK_EQ(bb->visited, false);
-
-    // We've visited all the predecessors. So, we can visit bb.
     bb->visited = true;
 
     // Now add the basic block.
+    uint16_t idx = static_cast<uint16_t>(topological_order_->Size());
+    topological_order_indexes_->Put(bb->id, idx);
     topological_order_->Insert(bb->id);
 
-    // Reduce visitedCnt for all the successors and add into the queue ones with visitedCnt equals to zero.
+    // Update visited_cnt_values for children.
     ChildBlockIterator succIter(bb, this);
     BasicBlock* successor = succIter.Next();
     for ( ; successor != nullptr; successor = succIter.Next()) {
-      if (successor->visited || successor->hidden) {
+      if (successor->hidden) {
         continue;
       }
 
-      // one more predecessor was visited.
-      DCHECK_NE(visited_cnt_values[successor->id], 0u);
-      visited_cnt_values[successor->id] -= 1u;
-      if (visited_cnt_values[successor->id] == 0u) {
-        q.push(successor);
+      // One more predecessor was visited.
+      visited_cnt_values[successor->id] += 1u;
+      if (visited_cnt_values[successor->id] == successor->predecessors->Size()) {
+        if (loop_head_stack.empty() ||
+            loop_head_reachable_from[loop_head_stack.back()]->IsBitSet(successor->id)) {
+          q.push(successor);
+        } else {
+          DCHECK(!loop_exit_blocks.IsBitSet(successor->id));
+          loop_exit_blocks.SetBit(successor->id);
+        }
       }
     }
   }
+
+  // Prepare the loop head stack for iteration.
+  topological_order_loop_head_stack_ =
+      new (arena_) GrowableArray<std::pair<uint16_t, bool>>(arena_, max_nested_loops);
 }
 
 bool BasicBlock::IsExceptionBlock() const {
diff --git a/compiler/dex/mir_graph.h b/compiler/dex/mir_graph.h
index 79b3edf..768ae21 100644
--- a/compiler/dex/mir_graph.h
+++ b/compiler/dex/mir_graph.h
@@ -27,6 +27,7 @@
 #include "mir_method_info.h"
 #include "utils/arena_bit_vector.h"
 #include "utils/growable_array.h"
+#include "utils/scoped_arena_containers.h"
 #include "reg_location.h"
 #include "reg_storage.h"
 
@@ -689,6 +690,21 @@
     return topological_order_;
   }
 
+  GrowableArray<BasicBlockId>* GetTopologicalSortOrderLoopEnds() {
+    DCHECK(topological_order_loop_ends_ != nullptr);
+    return topological_order_loop_ends_;
+  }
+
+  GrowableArray<BasicBlockId>* GetTopologicalSortOrderIndexes() {
+    DCHECK(topological_order_indexes_ != nullptr);
+    return topological_order_indexes_;
+  }
+
+  GrowableArray<std::pair<uint16_t, bool>>* GetTopologicalSortOrderLoopHeadStack() {
+    DCHECK(topological_order_loop_head_stack_ != nullptr);
+    return topological_order_loop_head_stack_;
+  }
+
   bool IsConst(int32_t s_reg) const {
     return is_constant_v_->IsBitSet(s_reg);
   }
@@ -1132,6 +1148,14 @@
   GrowableArray<BasicBlockId>* dfs_post_order_;
   GrowableArray<BasicBlockId>* dom_post_order_traversal_;
   GrowableArray<BasicBlockId>* topological_order_;
+  // Indexes in topological_order_ need to be only as big as the BasicBlockId.
+  COMPILE_ASSERT(sizeof(BasicBlockId) == sizeof(uint16_t), assuming_16_bit_BasicBlockId);
+  // For each loop head, remember the past-the-end index of the end of the loop. 0 if not loop head.
+  GrowableArray<uint16_t>* topological_order_loop_ends_;
+  // Map BB ids to topological_order_ indexes. 0xffff if not included (hidden or null block).
+  GrowableArray<uint16_t>* topological_order_indexes_;
+  // Stack of the loop head indexes and recalculation flags for RepeatingTopologicalSortIterator.
+  GrowableArray<std::pair<uint16_t, bool>>* topological_order_loop_head_stack_;
   int* i_dom_list_;
   ArenaBitVector** def_block_matrix_;    // num_dalvik_register x num_blocks.
   std::unique_ptr<ScopedArenaAllocator> temp_scoped_alloc_;
@@ -1177,6 +1201,7 @@
   friend class ClassInitCheckEliminationTest;
   friend class GlobalValueNumberingTest;
   friend class LocalValueNumberingTest;
+  friend class TopologicalSortOrderTest;
 };
 
 }  // namespace art
diff --git a/compiler/dex/mir_graph_test.cc b/compiler/dex/mir_graph_test.cc
new file mode 100644
index 0000000..932f453
--- /dev/null
+++ b/compiler/dex/mir_graph_test.cc
@@ -0,0 +1,381 @@
+/*
+ * 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 "mir_graph.h"
+#include "gtest/gtest.h"
+
+namespace art {
+
+class TopologicalSortOrderTest : public testing::Test {
+ protected:
+  struct BBDef {
+    static constexpr size_t kMaxSuccessors = 4;
+    static constexpr size_t kMaxPredecessors = 4;
+
+    BBType type;
+    size_t num_successors;
+    BasicBlockId successors[kMaxPredecessors];
+    size_t num_predecessors;
+    BasicBlockId predecessors[kMaxPredecessors];
+  };
+
+#define DEF_SUCC0() \
+    0u, { }
+#define DEF_SUCC1(s1) \
+    1u, { s1 }
+#define DEF_SUCC2(s1, s2) \
+    2u, { s1, s2 }
+#define DEF_SUCC3(s1, s2, s3) \
+    3u, { s1, s2, s3 }
+#define DEF_SUCC4(s1, s2, s3, s4) \
+    4u, { s1, s2, s3, s4 }
+#define DEF_PRED0() \
+    0u, { }
+#define DEF_PRED1(p1) \
+    1u, { p1 }
+#define DEF_PRED2(p1, p2) \
+    2u, { p1, p2 }
+#define DEF_PRED3(p1, p2, p3) \
+    3u, { p1, p2, p3 }
+#define DEF_PRED4(p1, p2, p3, p4) \
+    4u, { p1, p2, p3, p4 }
+#define DEF_BB(type, succ, pred) \
+    { type, succ, pred }
+
+  void DoPrepareBasicBlocks(const BBDef* defs, size_t count) {
+    cu_.mir_graph->block_id_map_.clear();
+    cu_.mir_graph->block_list_.Reset();
+    ASSERT_LT(3u, count);  // null, entry, exit and at least one bytecode block.
+    ASSERT_EQ(kNullBlock, defs[0].type);
+    ASSERT_EQ(kEntryBlock, defs[1].type);
+    ASSERT_EQ(kExitBlock, defs[2].type);
+    for (size_t i = 0u; i != count; ++i) {
+      const BBDef* def = &defs[i];
+      BasicBlock* bb = cu_.mir_graph->NewMemBB(def->type, i);
+      cu_.mir_graph->block_list_.Insert(bb);
+      if (def->num_successors <= 2) {
+        bb->successor_block_list_type = kNotUsed;
+        bb->successor_blocks = nullptr;
+        bb->fall_through = (def->num_successors >= 1) ? def->successors[0] : 0u;
+        bb->taken = (def->num_successors >= 2) ? def->successors[1] : 0u;
+      } else {
+        bb->successor_block_list_type = kPackedSwitch;
+        bb->fall_through = 0u;
+        bb->taken = 0u;
+        bb->successor_blocks = new (&cu_.arena) GrowableArray<SuccessorBlockInfo*>(
+            &cu_.arena, def->num_successors, kGrowableArraySuccessorBlocks);
+        for (size_t j = 0u; j != def->num_successors; ++j) {
+          SuccessorBlockInfo* successor_block_info =
+              static_cast<SuccessorBlockInfo*>(cu_.arena.Alloc(sizeof(SuccessorBlockInfo),
+                                                               kArenaAllocSuccessor));
+          successor_block_info->block = j;
+          successor_block_info->key = 0u;  // Not used by class init check elimination.
+          bb->successor_blocks->Insert(successor_block_info);
+        }
+      }
+      bb->predecessors = new (&cu_.arena) GrowableArray<BasicBlockId>(
+          &cu_.arena, def->num_predecessors, kGrowableArrayPredecessors);
+      for (size_t j = 0u; j != def->num_predecessors; ++j) {
+        ASSERT_NE(0u, def->predecessors[j]);
+        bb->predecessors->Insert(def->predecessors[j]);
+      }
+      if (def->type == kDalvikByteCode || def->type == kEntryBlock || def->type == kExitBlock) {
+        bb->data_flow_info = static_cast<BasicBlockDataFlow*>(
+            cu_.arena.Alloc(sizeof(BasicBlockDataFlow), kArenaAllocDFInfo));
+      }
+    }
+    cu_.mir_graph->num_blocks_ = count;
+    ASSERT_EQ(count, cu_.mir_graph->block_list_.Size());
+    cu_.mir_graph->entry_block_ = cu_.mir_graph->block_list_.Get(1);
+    ASSERT_EQ(kEntryBlock, cu_.mir_graph->entry_block_->block_type);
+    cu_.mir_graph->exit_block_ = cu_.mir_graph->block_list_.Get(2);
+    ASSERT_EQ(kExitBlock, cu_.mir_graph->exit_block_->block_type);
+  }
+
+  template <size_t count>
+  void PrepareBasicBlocks(const BBDef (&defs)[count]) {
+    DoPrepareBasicBlocks(defs, count);
+  }
+
+  void ComputeTopologicalSortOrder() {
+    cu_.mir_graph->SSATransformationStart();
+    cu_.mir_graph->ComputeDFSOrders();
+    cu_.mir_graph->ComputeDominators();
+    cu_.mir_graph->ComputeTopologicalSortOrder();
+    cu_.mir_graph->SSATransformationEnd();
+    ASSERT_NE(cu_.mir_graph->topological_order_, nullptr);
+    ASSERT_NE(cu_.mir_graph->topological_order_loop_ends_, nullptr);
+    ASSERT_NE(cu_.mir_graph->topological_order_indexes_, nullptr);
+    ASSERT_EQ(cu_.mir_graph->GetNumBlocks(), cu_.mir_graph->topological_order_indexes_->Size());
+    for (size_t i = 0, size = cu_.mir_graph->GetTopologicalSortOrder()->Size(); i != size; ++i) {
+      ASSERT_LT(cu_.mir_graph->topological_order_->Get(i), cu_.mir_graph->GetNumBlocks());
+      BasicBlockId id = cu_.mir_graph->topological_order_->Get(i);
+      EXPECT_EQ(i, cu_.mir_graph->topological_order_indexes_->Get(id));
+    }
+  }
+
+  void DoCheckOrder(const BasicBlockId* ids, size_t count) {
+    ASSERT_EQ(count, cu_.mir_graph->GetTopologicalSortOrder()->Size());
+    for (size_t i = 0; i != count; ++i) {
+      EXPECT_EQ(ids[i], cu_.mir_graph->GetTopologicalSortOrder()->Get(i)) << i;
+    }
+  }
+
+  template <size_t count>
+  void CheckOrder(const BasicBlockId (&ids)[count]) {
+    DoCheckOrder(ids, count);
+  }
+
+  void DoCheckLoopEnds(const uint16_t* ends, size_t count) {
+    for (size_t i = 0; i != count; ++i) {
+      ASSERT_LT(i, cu_.mir_graph->GetTopologicalSortOrderLoopEnds()->Size());
+      EXPECT_EQ(ends[i], cu_.mir_graph->GetTopologicalSortOrderLoopEnds()->Get(i)) << i;
+    }
+  }
+
+  template <size_t count>
+  void CheckLoopEnds(const uint16_t (&ends)[count]) {
+    DoCheckLoopEnds(ends, count);
+  }
+
+  TopologicalSortOrderTest()
+      : pool_(),
+        cu_(&pool_) {
+    cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena));
+  }
+
+  ArenaPool pool_;
+  CompilationUnit cu_;
+};
+
+TEST_F(TopologicalSortOrderTest, DoWhile) {
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED2(3, 4)),  // "taken" loops to self.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(4)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 5, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 0, 3, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, While) {
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED2(1, 4)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(3)),     // Loops to 3.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 5, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 3, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, WhileWithTwoBackEdges) {
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED3(1, 4, 5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED1(3)),     // Loops to 3.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)),        // Loops to 3.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 5, 6, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 4, 0, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, NestedLoop) {
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED2(1, 6)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED2(3, 5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)),            // Loops to 4.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(3), DEF_PRED1(4)),            // Loops to 3.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 5, 6, 7, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 5, 4, 0, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, NestedLoopHeadLoops) {
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 4)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 3), DEF_PRED2(3, 5)),      // Nested head, loops to 3.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)),            // Loops to 4.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 5, 6, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 4, 4, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, NestedLoopSameBackBranchBlock) {
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 6), DEF_PRED2(1, 5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 3), DEF_PRED1(4)),         // Loops to 4 and 3.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 5, 6, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 4, 4, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, TwoReorderedInnerLoops) {
+  // This is a simplified version of real code graph where the branch from 8 to 5 must prevent
+  // the block 5 from being considered a loop head before processing the loop 7-8.
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(9)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 9), DEF_PRED2(1, 5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 7), DEF_PRED1(3)),         // Branch over loop in 5.
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(6, 3), DEF_PRED3(4, 6, 8)),   // Loops to 4; inner loop.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(5)),            // Loops to 5.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(8), DEF_PRED2(4, 8)),         // Loop head.
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 5), DEF_PRED1(7)),         // Loops to 7; branches to 5.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(3)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 7, 8, 5, 6, 9, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 7, 0, 5, 0, 7, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, NestedLoopWithBackEdgeAfterOuterLoopBackEdge) {
+  // This is a simplified version of real code graph. The back-edge from 7 to the inner
+  // loop head 4 comes after the back-edge from 6 to the outer loop head 3. To make this
+  // appear a bit more complex, there's also a back-edge from 5 to 4.
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED2(1, 6)),         // Outer loop head.
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 6), DEF_PRED3(3, 5, 7)),   // Inner loop head.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(4)),            // Loops to inner loop head 4.
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(7, 3), DEF_PRED1(4)),         // Loops to outer loop head 3.
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(2, 4), DEF_PRED1(6)),         // Loops to inner loop head 4.
+  };
+  const BasicBlockId expected_order[] = {
+      // NOTE: The 5 goes before 6 only because 5 is a "fall-through" from 4 while 6 is "taken".
+      1, 3, 4, 5, 6, 7, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 6, 6, 0, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+TEST_F(TopologicalSortOrderTest, LoopWithTwoEntryPoints) {
+  const BBDef bbs[] = {
+      DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
+      DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED1(1)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED2(3, 6)),  // Fall-back block is chosen as
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED2(3, 4)),  // the earlier from these two.
+      DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 7), DEF_PRED1(5)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED1(6)),
+  };
+  const BasicBlockId expected_order[] = {
+      1, 3, 4, 5, 6, 7, 2
+  };
+  const uint16_t loop_ends[] = {
+      0, 0, 5, 0, 0, 0, 0
+  };
+
+  PrepareBasicBlocks(bbs);
+  ComputeTopologicalSortOrder();
+  CheckOrder(expected_order);
+  CheckLoopEnds(loop_ends);
+}
+
+}  // namespace art
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 869c48f..5c98654 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -321,7 +321,7 @@
     return true;
   }
   // Don't do a separate LVN if we did the GVN.
-  bool use_lvn = bb->use_lvn && (cu_->disable_opt & (1 << kGlobalValueNumbering)) != 0;
+  bool use_lvn = bb->use_lvn && (cu_->disable_opt & (1u << kGlobalValueNumbering)) != 0u;
   std::unique_ptr<ScopedArenaAllocator> allocator;
   std::unique_ptr<GlobalValueNumbering> global_valnum;
   std::unique_ptr<LocalValueNumbering> local_valnum;
@@ -737,11 +737,9 @@
   ArenaBitVector* ssa_regs_to_check = temp_bit_vector_;
   if (do_nce) {
     /*
-     * Set initial state.  Be conservative with catch
-     * blocks and start with no assumptions about null check
-     * status (except for "this").
+     * Set initial state. Catch blocks don't need any special treatment.
      */
-    if ((bb->block_type == kEntryBlock) | bb->catch_entry) {
+    if (bb->block_type == kEntryBlock) {
       ssa_regs_to_check->ClearAllBits();
       // Assume all ins are objects.
       for (uint16_t in_reg = cu_->num_dalvik_registers - cu_->num_ins;
@@ -1047,12 +1045,11 @@
   }
 
   /*
-   * Set initial state.  Be conservative with catch
-   * blocks and start with no assumptions about class init check status.
+   * Set initial state.  Catch blocks don't need any special treatment.
    */
   ArenaBitVector* classes_to_check = temp_bit_vector_;
   DCHECK(classes_to_check != nullptr);
-  if ((bb->block_type == kEntryBlock) | bb->catch_entry) {
+  if (bb->block_type == kEntryBlock) {
     classes_to_check->SetInitialBits(temp_bit_vector_size_);
   } else if (bb->predecessors->Size() == 1) {
     BasicBlock* pred_bb = GetBasicBlock(bb->predecessors->Get(0));
@@ -1142,11 +1139,7 @@
 }
 
 bool MIRGraph::ApplyGlobalValueNumberingGate() {
-  if ((cu_->disable_opt & (1 << kGlobalValueNumbering)) != 0) {
-    return false;
-  }
-
-  if ((merged_df_flags_ & DF_LVN) == 0) {
+  if ((cu_->disable_opt & (1u << kGlobalValueNumbering)) != 0u) {
     return false;
   }
 
@@ -1182,7 +1175,7 @@
           lvn->GetValueNumber(mir);
         }
         bool change = temp_gvn_->FinishBasicBlock(bb);
-        DCHECK(!change);
+        DCHECK(!change) << PrettyMethod(cu_->method_idx, *cu_->dex_file);
       }
     }
   } else {
diff --git a/compiler/dex/mir_optimization_test.cc b/compiler/dex/mir_optimization_test.cc
index 8c70b5c..c510b52 100644
--- a/compiler/dex/mir_optimization_test.cc
+++ b/compiler/dex/mir_optimization_test.cc
@@ -195,7 +195,7 @@
     cu_.mir_graph->SSATransformationEnd();
     bool gate_result = cu_.mir_graph->EliminateClassInitChecksGate();
     ASSERT_TRUE(gate_result);
-    RepeatingTopologicalSortIterator iterator(cu_.mir_graph.get());
+    LoopRepeatingTopologicalSortIterator iterator(cu_.mir_graph.get());
     bool change = false;
     for (BasicBlock* bb = iterator.Next(change); bb != nullptr; bb = iterator.Next(change)) {
       change = cu_.mir_graph->EliminateClassInitChecks(bb);
@@ -373,30 +373,47 @@
   static const SFieldDef sfields[] = {
       { 0u, 1u, 0u, 0u },
       { 1u, 1u, 1u, 1u },
+      { 2u, 1u, 2u, 2u },
+      { 3u, 1u, 3u, 3u },
   };
   static const BBDef bbs[] = {
       DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()),
       DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()),
-      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(5)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC2(5, 4), DEF_PRED1(1)),
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(5), DEF_PRED1(3)),  // Catch handler.
-      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(3, 4)),
+      DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(6)),
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(4), DEF_PRED1(1)),     // The top.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),     // The throwing insn.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)),     // Catch handler.
+      DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 5)),  // The merged block.
   };
   static const MIRDef mirs[] = {
-      DEF_MIR(Instruction::SGET, 3u, 0u),
-      DEF_MIR(Instruction::SGET, 3u, 1u),
-      DEF_MIR(Instruction::SGET, 4u, 1u),
-      DEF_MIR(Instruction::SGET, 5u, 0u),  // Not eliminated.
-      DEF_MIR(Instruction::SGET, 5u, 1u),  // Eliminated.
+      DEF_MIR(Instruction::SGET, 3u, 0u),  // Before the exception edge.
+      DEF_MIR(Instruction::SGET, 3u, 1u),  // Before the exception edge.
+      DEF_MIR(Instruction::SGET, 4u, 2u),  // After the exception edge.
+      DEF_MIR(Instruction::SGET, 4u, 3u),  // After the exception edge.
+      DEF_MIR(Instruction::SGET, 5u, 0u),  // In catch handler; class init check eliminated.
+      DEF_MIR(Instruction::SGET, 5u, 2u),  // In catch handler; class init check not eliminated.
+      DEF_MIR(Instruction::SGET, 6u, 0u),  // Class init check eliminated.
+      DEF_MIR(Instruction::SGET, 6u, 1u),  // Class init check eliminated.
+      DEF_MIR(Instruction::SGET, 6u, 2u),  // Class init check eliminated.
+      DEF_MIR(Instruction::SGET, 6u, 3u),  // Class init check not eliminated.
   };
   static const bool expected_ignore_clinit_check[] = {
-      false, false, false, false, true
+      false, false, false, false, true, false, true, true, true, false
   };
 
   PrepareSFields(sfields);
   PrepareBasicBlocks(bbs);
-  BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(4u);
+  BasicBlock* catch_handler = cu_.mir_graph->GetBasicBlock(5u);
   catch_handler->catch_entry = true;
+  // Add successor block info to the check block.
+  BasicBlock* check_bb = cu_.mir_graph->GetBasicBlock(3u);
+  check_bb->successor_block_list_type = kCatch;
+  check_bb->successor_blocks = new (&cu_.arena) GrowableArray<SuccessorBlockInfo*>(
+      &cu_.arena, 2, kGrowableArraySuccessorBlocks);
+  SuccessorBlockInfo* successor_block_info = reinterpret_cast<SuccessorBlockInfo*>
+      (cu_.arena.Alloc(sizeof(SuccessorBlockInfo), kArenaAllocSuccessor));
+  successor_block_info->block = catch_handler->id;
+  check_bb->successor_blocks->Insert(successor_block_info);
   PrepareMIRs(mirs);
   PerformClassInitCheckElimination();
   ASSERT_EQ(arraysize(expected_ignore_clinit_check), mir_count_);
diff --git a/compiler/dex/pass_driver_me.h b/compiler/dex/pass_driver_me.h
index 031c5cf..133593c 100644
--- a/compiler/dex/pass_driver_me.h
+++ b/compiler/dex/pass_driver_me.h
@@ -68,6 +68,9 @@
       case kRepeatingTopologicalSortTraversal:
         DoWalkBasicBlocks<RepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
         break;
+      case kLoopRepeatingTopologicalSortTraversal:
+        DoWalkBasicBlocks<LoopRepeatingTopologicalSortIterator>(&pass_me_data_holder_, me_pass);
+        break;
       case kAllNodes:
         DoWalkBasicBlocks<AllNodesIterator>(&pass_me_data_holder_, me_pass);
         break;
diff --git a/compiler/dex/pass_me.h b/compiler/dex/pass_me.h
index ff69865..c7276eb 100644
--- a/compiler/dex/pass_me.h
+++ b/compiler/dex/pass_me.h
@@ -55,6 +55,7 @@
   kPostOrderDOMTraversal,                  /**< @brief Dominator tree / Post-Order. */
   kTopologicalSortTraversal,               /**< @brief Topological Order traversal. */
   kRepeatingTopologicalSortTraversal,      /**< @brief Repeating Topological Order traversal. */
+  kLoopRepeatingTopologicalSortTraversal,  /**< @brief Loop-repeating Topological Order traversal. */
   kNoNodes,                                /**< @brief Skip BasicBlock traversal. */
 };
 
diff --git a/compiler/dex/vreg_analysis.cc b/compiler/dex/vreg_analysis.cc
index 892b302..4a3e071 100644
--- a/compiler/dex/vreg_analysis.cc
+++ b/compiler/dex/vreg_analysis.cc
@@ -324,13 +324,15 @@
     }
 
     for (int i = 0; ssa_rep->fp_use && i< ssa_rep->num_uses; i++) {
-      if (ssa_rep->fp_use[i])
+      if (ssa_rep->fp_use[i]) {
         changed |= SetFp(uses[i]);
       }
+    }
     for (int i = 0; ssa_rep->fp_def && i< ssa_rep->num_defs; i++) {
-      if (ssa_rep->fp_def[i])
+      if (ssa_rep->fp_def[i]) {
         changed |= SetFp(defs[i]);
       }
+    }
     // Special-case handling for moves & Phi
     if (attrs & (DF_IS_MOVE | DF_NULL_TRANSFER_N)) {
       /*
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index f1eb372..251a2ad 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -202,20 +202,21 @@
   static const int kFakeReturnRegister = 8;
   core_spill_mask_ |= (1 << kFakeReturnRegister);
 
+  bool skip_overflow_check = IsLeafMethod() && !IsLargeFrame(GetFrameSize(), InstructionSet::kX86);
+  if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
+    __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
+    RecordPcInfo(0);
+  }
+
   // The return PC has already been pushed on the stack.
   __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
 
-  bool skip_overflow_check = IsLeafMethod() && !IsLargeFrame(GetFrameSize(), InstructionSet::kX86);
-  if (!skip_overflow_check) {
-    if (kExplicitStackOverflowCheck) {
-      SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
-      AddSlowPath(slow_path);
+  if (!skip_overflow_check && kExplicitStackOverflowCheck) {
+    SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
+    AddSlowPath(slow_path);
 
-      __ fs()->cmpl(ESP, Address::Absolute(Thread::StackEndOffset<kX86WordSize>()));
-      __ j(kLess, slow_path->GetEntryLabel());
-    } else {
-      __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
-    }
+    __ fs()->cmpl(ESP, Address::Absolute(Thread::StackEndOffset<kX86WordSize>()));
+    __ j(kLess, slow_path->GetEntryLabel());
   }
 
   __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 55d582f..4c88c9e 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -1024,6 +1024,9 @@
     } else {
       CHECK(!input_oat_filename.empty());
       input_oat.reset(OS::OpenFileForReading(input_oat_filename.c_str()));
+      if (input_oat.get() == nullptr) {
+        LOG(ERROR) << "Could not open input oat file: " << strerror(errno);
+      }
     }
 
     if (output_oat_fd != -1) {
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 3d87297..1522129 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1277,12 +1277,12 @@
     mov  %esp, %ecx               // Remember SP
     subl LITERAL(8), %esp         // Save float return value.
     CFI_ADJUST_CFA_OFFSET(8)
-    movsd %xmm0, (%esp)
+    movq %xmm0, (%esp)
     PUSH edx                      // Save gpr return value.
     PUSH eax
     subl LITERAL(16), %esp        // Align stack
     CFI_ADJUST_CFA_OFFSET(16)
-    movsd %xmm0, (%esp)           // Pass float return value.
+    movq %xmm0, (%esp)            // Pass float return value.
     PUSH edx                      // Pass gpr return value.
     PUSH eax
     PUSH ecx                      // Pass SP.
@@ -1297,7 +1297,7 @@
                                   // (ebx is pretending to be our LR).
     POP eax                       // Restore gpr return value.
     POP edx
-    movsd (%esp), %xmm0           // Restore fpr return value.
+    movq (%esp), %xmm0            // Restore fpr return value.
     addl LITERAL(8), %esp
     CFI_ADJUST_CFA_OFFSET(-8)
     RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 50b2de4..48bc240 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -1495,7 +1495,7 @@
     PUSH rax                  // Save integer result.
     subq LITERAL(8), %rsp     // Save floating-point result.
     CFI_ADJUST_CFA_OFFSET(8)
-    movd %xmm0, (%rsp)
+    movq %xmm0, (%rsp)
 
     movq  %gs:THREAD_SELF_OFFSET, %rdi        // Pass Thread.
     movq  %rax, %rdx                          // Pass integer result.
@@ -1506,7 +1506,7 @@
     movq  %rax, %rdi          // Store return PC
     movq  %rdx, %rsi          // Store second return PC in hidden arg.
 
-    movd (%rsp), %xmm0        // Restore floating-point result.
+    movq (%rsp), %xmm0        // Restore floating-point result.
     addq LITERAL(8), %rsp
     CFI_ADJUST_CFA_OFFSET(-8)
     POP rax                   // Restore integer result.
diff --git a/test/001-nop/build b/test/000-nop/build
similarity index 100%
rename from test/001-nop/build
rename to test/000-nop/build
diff --git a/test/001-nop/expected.txt b/test/000-nop/expected.txt
similarity index 100%
rename from test/001-nop/expected.txt
rename to test/000-nop/expected.txt
diff --git a/test/001-nop/info.txt b/test/000-nop/info.txt
similarity index 100%
rename from test/001-nop/info.txt
rename to test/000-nop/info.txt
diff --git a/test/001-nop/run b/test/000-nop/run
similarity index 100%
rename from test/001-nop/run
rename to test/000-nop/run
diff --git a/test/001-HelloWorld/expected.txt b/test/001-HelloWorld/expected.txt
new file mode 100644
index 0000000..af5626b
--- /dev/null
+++ b/test/001-HelloWorld/expected.txt
@@ -0,0 +1 @@
+Hello, world!
diff --git a/test/001-HelloWorld/info.txt b/test/001-HelloWorld/info.txt
new file mode 100644
index 0000000..641dd9a
--- /dev/null
+++ b/test/001-HelloWorld/info.txt
@@ -0,0 +1 @@
+Imported from oat test. Print "Hello World."
diff --git a/test/HelloWorld/HelloWorld.java b/test/001-HelloWorld/src/Main.java
similarity index 90%
rename from test/HelloWorld/HelloWorld.java
rename to test/001-HelloWorld/src/Main.java
index c6861ce..1ef6289 100644
--- a/test/HelloWorld/HelloWorld.java
+++ b/test/001-HelloWorld/src/Main.java
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-class HelloWorld {
+public class Main {
   public static void main(String[] args) {
-    System.logI("Hello, world!");
+    System.out.println("Hello, world!");
   }
 }
diff --git a/test/001-Main/expected.txt b/test/001-Main/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/001-Main/expected.txt
diff --git a/test/001-Main/info.txt b/test/001-Main/info.txt
new file mode 100644
index 0000000..e4b33a0
--- /dev/null
+++ b/test/001-Main/info.txt
@@ -0,0 +1 @@
+Import of a previous oat test. Empty main, just test starting up the runtime.
diff --git a/test/HelloWorld/HelloWorld.java b/test/001-Main/src/Main.java
similarity index 85%
copy from test/HelloWorld/HelloWorld.java
copy to test/001-Main/src/Main.java
index c6861ce..3486866 100644
--- a/test/HelloWorld/HelloWorld.java
+++ b/test/001-Main/src/Main.java
@@ -14,8 +14,7 @@
  * limitations under the License.
  */
 
-class HelloWorld {
-  public static void main(String[] args) {
-    System.logI("Hello, world!");
-  }
+public class Main {
+    public static void main(String args[]) {
+    }
 }
diff --git a/test/004-InterfaceTest/expected.txt b/test/004-InterfaceTest/expected.txt
new file mode 100644
index 0000000..4854e24
--- /dev/null
+++ b/test/004-InterfaceTest/expected.txt
@@ -0,0 +1,2 @@
+test_virtual done
+test_interface done
diff --git a/test/004-InterfaceTest/info.txt b/test/004-InterfaceTest/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-InterfaceTest/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/InterfaceTest/InterfaceTest.java b/test/004-InterfaceTest/src/Main.java
similarity index 91%
rename from test/InterfaceTest/InterfaceTest.java
rename to test/004-InterfaceTest/src/Main.java
index ed18eb3..9ebac59 100644
--- a/test/InterfaceTest/InterfaceTest.java
+++ b/test/004-InterfaceTest/src/Main.java
@@ -17,7 +17,7 @@
 import java.util.Map;
 import java.util.HashMap;
 
-class InterfaceTest {
+public class Main {
 
   public static long test_virtual(HashMap map) {
     Integer intobj = new Integer(0);
@@ -44,10 +44,10 @@
   public static void main(String[] args) {
     HashMap hashmap = new HashMap();
     long elapsed = test_virtual(hashmap);
-    System.logI("virtual map put: " + elapsed);
+    System.out.println("test_virtual done");
     hashmap.clear();
 
     elapsed = test_interface(hashmap);
-    System.logI("interface map put: " + elapsed);
+    System.out.println("test_interface done");
   }
 }
diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/004-JniTest/expected.txt
diff --git a/test/004-JniTest/info.txt b/test/004-JniTest/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-JniTest/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
similarity index 86%
rename from test/JniTest/jni_test.cc
rename to test/004-JniTest/jni_test.cc
index 36cad72..4909a4a 100644
--- a/test/JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -42,7 +42,7 @@
   int attach_result = jvm->AttachCurrentThread(&env, &args);
   assert(attach_result == 0);
 
-  jclass clazz = env->FindClass("JniTest");
+  jclass clazz = env->FindClass("Main");
   assert(clazz != NULL);
   assert(!env->ExceptionCheck());
 
@@ -56,7 +56,7 @@
 }
 
 // http://b/10994325
-extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindClassOnAttachedNativeThread(JNIEnv*,
+extern "C" JNIEXPORT void JNICALL Java_Main_testFindClassOnAttachedNativeThread(JNIEnv*,
                                                                                    jclass) {
   pthread_t pthread;
   int pthread_create_result = pthread_create(&pthread,
@@ -76,7 +76,7 @@
   int attach_result = jvm->AttachCurrentThread(&env, &args);
   assert(attach_result == 0);
 
-  jclass clazz = env->FindClass("JniTest");
+  jclass clazz = env->FindClass("Main");
   assert(clazz != NULL);
   assert(!env->ExceptionCheck());
 
@@ -91,7 +91,7 @@
   return NULL;
 }
 
-extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindFieldOnAttachedNativeThreadNative(JNIEnv*,
+extern "C" JNIEXPORT void JNICALL Java_Main_testFindFieldOnAttachedNativeThreadNative(JNIEnv*,
                                                                                          jclass) {
   pthread_t pthread;
   int pthread_create_result = pthread_create(&pthread,
@@ -111,7 +111,7 @@
   int attach_result = jvm->AttachCurrentThread(&env, &args);
   assert(attach_result == 0);
 
-  jclass clazz = env->FindClass("JniTest");
+  jclass clazz = env->FindClass("Main");
   assert(clazz != NULL);
   assert(!env->ExceptionCheck());
 
@@ -151,7 +151,7 @@
 }
 
 // http://b/15539150
-extern "C" JNIEXPORT void JNICALL Java_JniTest_testReflectFieldGetFromAttachedNativeThreadNative(
+extern "C" JNIEXPORT void JNICALL Java_Main_testReflectFieldGetFromAttachedNativeThreadNative(
     JNIEnv*, jclass) {
   pthread_t pthread;
   int pthread_create_result = pthread_create(&pthread,
@@ -165,22 +165,22 @@
 
 
 // http://b/11243757
-extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
+extern "C" JNIEXPORT void JNICALL Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
                                                                                         jclass) {
-  jclass super_class = env->FindClass("JniTest$testCallStaticVoidMethodOnSubClass_SuperClass");
+  jclass super_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SuperClass");
   assert(super_class != NULL);
 
   jmethodID execute = env->GetStaticMethodID(super_class, "execute", "()V");
   assert(execute != NULL);
 
-  jclass sub_class = env->FindClass("JniTest$testCallStaticVoidMethodOnSubClass_SubClass");
+  jclass sub_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SubClass");
   assert(sub_class != NULL);
 
   env->CallStaticVoidMethod(sub_class, execute);
 }
 
-extern "C" JNIEXPORT jobject JNICALL Java_JniTest_testGetMirandaMethodNative(JNIEnv* env, jclass) {
-  jclass abstract_class = env->FindClass("JniTest$testGetMirandaMethod_MirandaAbstract");
+extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass) {
+  jclass abstract_class = env->FindClass("Main$testGetMirandaMethod_MirandaAbstract");
   assert(abstract_class != NULL);
   jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z");
   assert(miranda_method != NULL);
@@ -188,7 +188,7 @@
 }
 
 // https://code.google.com/p/android/issues/detail?id=63055
-extern "C" void JNICALL Java_JniTest_testZeroLengthByteBuffers(JNIEnv* env, jclass) {
+extern "C" void JNICALL Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass) {
   std::vector<uint8_t> buffer(1);
   jobject byte_buffer = env->NewDirectByteBuffer(&buffer[0], 0);
   assert(byte_buffer != NULL);
@@ -201,7 +201,7 @@
 constexpr size_t kByteReturnSize = 7;
 jbyte byte_returns[kByteReturnSize] = { 0, 1, 2, 127, -1, -2, -128 };
 
-extern "C" jbyte JNICALL Java_JniTest_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2,
+extern "C" jbyte JNICALL Java_Main_byteMethod(JNIEnv* env, jclass klass, jbyte b1, jbyte b2,
                                                     jbyte b3, jbyte b4, jbyte b5, jbyte b6,
                                                     jbyte b7, jbyte b8, jbyte b9, jbyte b10) {
   // We use b1 to drive the output.
@@ -226,7 +226,7 @@
     static_cast<jshort>(0x8000) };
 // The weird static_cast is because short int is only guaranteed down to -32767, not Java's -32768.
 
-extern "C" jshort JNICALL Java_JniTest_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2,
+extern "C" jshort JNICALL Java_Main_shortMethod(JNIEnv* env, jclass klass, jshort s1, jshort s2,
                                                     jshort s3, jshort s4, jshort s5, jshort s6,
                                                     jshort s7, jshort s8, jshort s9, jshort s10) {
   // We use s1 to drive the output.
@@ -246,7 +246,7 @@
   return short_returns[s1];
 }
 
-extern "C" jboolean JNICALL Java_JniTest_booleanMethod(JNIEnv* env, jclass klass, jboolean b1,
+extern "C" jboolean JNICALL Java_Main_booleanMethod(JNIEnv* env, jclass klass, jboolean b1,
                                                        jboolean b2, jboolean b3, jboolean b4,
                                                        jboolean b5, jboolean b6, jboolean b7,
                                                        jboolean b8, jboolean b9, jboolean b10) {
@@ -268,7 +268,7 @@
 constexpr size_t kCharReturnSize = 8;
 jchar char_returns[kCharReturnSize] = { 0, 1, 2, 127, 255, 256, 15000, 34000 };
 
-extern "C" jchar JNICALL Java_JniTest_charMethod(JNIEnv* env, jclass klacc, jchar c1, jchar c2,
+extern "C" jchar JNICALL Java_Main_charMethod(JNIEnv* env, jclass klacc, jchar c1, jchar c2,
                                                     jchar c3, jchar c4, jchar c5, jchar c6,
                                                     jchar c7, jchar c8, jchar c9, jchar c10) {
   // We use c1 to drive the output.
diff --git a/test/JniTest/JniTest.java b/test/004-JniTest/src/Main.java
similarity index 98%
rename from test/JniTest/JniTest.java
rename to test/004-JniTest/src/Main.java
index 33418a9..11c80f5 100644
--- a/test/JniTest/JniTest.java
+++ b/test/004-JniTest/src/Main.java
@@ -16,7 +16,7 @@
 
 import java.lang.reflect.Method;
 
-class JniTest {
+public class Main {
     public static void main(String[] args) {
         System.loadLibrary("arttest");
         testFindClassOnAttachedNativeThread();
diff --git a/test/004-NativeAllocations/expected.txt b/test/004-NativeAllocations/expected.txt
new file mode 100644
index 0000000..f75da10
--- /dev/null
+++ b/test/004-NativeAllocations/expected.txt
@@ -0,0 +1 @@
+Test complete
diff --git a/test/004-NativeAllocations/info.txt b/test/004-NativeAllocations/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-NativeAllocations/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/NativeAllocations/NativeAllocations.java b/test/004-NativeAllocations/src/Main.java
similarity index 98%
rename from test/NativeAllocations/NativeAllocations.java
rename to test/004-NativeAllocations/src/Main.java
index 9423b91..483c667 100644
--- a/test/NativeAllocations/NativeAllocations.java
+++ b/test/004-NativeAllocations/src/Main.java
@@ -16,7 +16,7 @@
 
 import java.lang.reflect.*;
 
-class NativeAllocations {
+public class Main {
     static Object nativeLock = new Object();
     static int nativeBytes = 0;
     static Object runtime;
diff --git a/test/004-ReferenceMap/expected.txt b/test/004-ReferenceMap/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/004-ReferenceMap/expected.txt
diff --git a/test/004-ReferenceMap/info.txt b/test/004-ReferenceMap/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-ReferenceMap/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/ReferenceMap/ReferenceMap.java b/test/004-ReferenceMap/src/Main.java
similarity index 91%
rename from test/ReferenceMap/ReferenceMap.java
rename to test/004-ReferenceMap/src/Main.java
index c746b68..f9a5498 100644
--- a/test/ReferenceMap/ReferenceMap.java
+++ b/test/004-ReferenceMap/src/Main.java
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-public class ReferenceMap {
-  public ReferenceMap() {
+public class Main {
+  public Main() {
   }
 
   Object f() {
@@ -41,7 +41,7 @@
   }
 
   public static void main(String[] args) {
-    ReferenceMap rm = new ReferenceMap();
+    Main rm = new Main();
     rm.f();
   }
 }
diff --git a/test/ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
similarity index 99%
rename from test/ReferenceMap/stack_walk_refmap_jni.cc
rename to test/004-ReferenceMap/stack_walk_refmap_jni.cc
index e5a1786..7929554 100644
--- a/test/ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -271,7 +271,7 @@
 //        0x0032 - 0x0033 reg=2 y Ljava/lang/Object;
 //        0x0000 - 0x0033 reg=8 this LReferenceMap;
 
-extern "C" JNIEXPORT jint JNICALL Java_ReferenceMap_refmap(JNIEnv*, jobject, jint count) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_refmap(JNIEnv*, jobject, jint count) {
   // Visitor
   ScopedObjectAccess soa(Thread::Current());
   ReferenceMap2Visitor mapper(soa.Self());
diff --git a/test/004-SignalTest/expected.txt b/test/004-SignalTest/expected.txt
new file mode 100644
index 0000000..fd5ec00
--- /dev/null
+++ b/test/004-SignalTest/expected.txt
@@ -0,0 +1,5 @@
+init signal test
+Caught NullPointerException
+Caught StackOverflowError
+signal caught
+Signal test OK
diff --git a/test/004-SignalTest/info.txt b/test/004-SignalTest/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-SignalTest/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/SignalTest/signaltest.cc b/test/004-SignalTest/signaltest.cc
similarity index 88%
rename from test/SignalTest/signaltest.cc
rename to test/004-SignalTest/signaltest.cc
index dfe3197..a2dd664 100644
--- a/test/SignalTest/signaltest.cc
+++ b/test/004-SignalTest/signaltest.cc
@@ -41,7 +41,7 @@
 
 static struct sigaction oldaction;
 
-extern "C" JNIEXPORT void JNICALL Java_SignalTest_initSignalTest(JNIEnv*, jclass) {
+extern "C" JNIEXPORT void JNICALL Java_Main_initSignalTest(JNIEnv*, jclass) {
   struct sigaction action;
   action.sa_sigaction = signalhandler;
   sigemptyset(&action.sa_mask);
@@ -53,7 +53,7 @@
   sigaction(SIGSEGV, &action, &oldaction);
 }
 
-extern "C" JNIEXPORT void JNICALL Java_SignalTest_terminateSignalTest(JNIEnv*, jclass) {
+extern "C" JNIEXPORT void JNICALL Java_Main_terminateSignalTest(JNIEnv*, jclass) {
   sigaction(SIGSEGV, &oldaction, nullptr);
 }
 
@@ -61,7 +61,7 @@
 // to nullptr.
 char *p = nullptr;
 
-extern "C" JNIEXPORT jint JNICALL Java_SignalTest_testSignal(JNIEnv*, jclass) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_testSignal(JNIEnv*, jclass) {
 #ifdef __arm__
   // On ARM we cause a real SEGV.
   *p = 'a';
diff --git a/test/SignalTest/SignalTest.java b/test/004-SignalTest/src/Main.java
similarity index 98%
rename from test/SignalTest/SignalTest.java
rename to test/004-SignalTest/src/Main.java
index 7f15aea..0391592 100644
--- a/test/SignalTest/SignalTest.java
+++ b/test/004-SignalTest/src/Main.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-class SignalTest {
+public class Main {
     private static native void initSignalTest();
     private static native void terminateSignalTest();
     private static native int testSignal();
diff --git a/test/004-StackWalk/expected.txt b/test/004-StackWalk/expected.txt
new file mode 100644
index 0000000..bde0024
--- /dev/null
+++ b/test/004-StackWalk/expected.txt
@@ -0,0 +1,4 @@
+1st call
+172001234567891011121314151617181920652310201919
+2nd call
+172001234567891011121314151617181920652310201919
diff --git a/test/004-StackWalk/info.txt b/test/004-StackWalk/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-StackWalk/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/StackWalk/StackWalk.java b/test/004-StackWalk/src/Main.java
similarity index 92%
rename from test/StackWalk/StackWalk.java
rename to test/004-StackWalk/src/Main.java
index f7c78ff..1e2a91b 100644
--- a/test/StackWalk/StackWalk.java
+++ b/test/004-StackWalk/src/Main.java
@@ -1,5 +1,5 @@
-public class StackWalk {
-  public StackWalk() {
+public class Main {
+  public Main() {
   }
 
   int f() {
@@ -76,18 +76,18 @@
     s4 = s18 = s19;
     s += s4;
     s += s18;
-    refmap(0);
+    stackmap(0);
     return s;
   }
 
-  native int refmap(int x);
+  native int stackmap(int x);
 
   static {
     System.loadLibrary("arttest");
   }
 
   public static void main(String[] args) {
-    StackWalk st = new StackWalk();
+    Main st = new Main();
     st.f();
   }
 }
diff --git a/test/StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc
similarity index 93%
rename from test/StackWalk/stack_walk_jni.cc
rename to test/004-StackWalk/stack_walk_jni.cc
index e404f6a..30a0d59 100644
--- a/test/StackWalk/stack_walk_jni.cc
+++ b/test/004-StackWalk/stack_walk_jni.cc
@@ -95,13 +95,12 @@
         CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
       }
     }
-    LOG(INFO) << reinterpret_cast<const void*>(reg_bitmap);
 
     return true;
   }
 };
 
-extern "C" JNIEXPORT jint JNICALL Java_StackWalk_refmap(JNIEnv*, jobject, jint count) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_stackmap(JNIEnv*, jobject, jint count) {
   ScopedObjectAccess soa(Thread::Current());
   CHECK_EQ(count, 0);
   gJava_StackWalk_refmap_calls++;
@@ -113,7 +112,7 @@
   return count + 1;
 }
 
-extern "C" JNIEXPORT jint JNICALL Java_StackWalk2_refmap2(JNIEnv*, jobject, jint count) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_refmap2(JNIEnv*, jobject, jint count) {
   ScopedObjectAccess soa(Thread::Current());
   gJava_StackWalk_refmap_calls++;
 
diff --git a/test/004-ThreadStress/check b/test/004-ThreadStress/check
new file mode 100755
index 0000000..ffbb8cf
--- /dev/null
+++ b/test/004-ThreadStress/check
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Only compare the last line.
+tail -n 1 "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
\ No newline at end of file
diff --git a/test/004-ThreadStress/expected.txt b/test/004-ThreadStress/expected.txt
new file mode 100644
index 0000000..a26fb4f
--- /dev/null
+++ b/test/004-ThreadStress/expected.txt
@@ -0,0 +1 @@
+Finishing worker
diff --git a/test/004-ThreadStress/info.txt b/test/004-ThreadStress/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-ThreadStress/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/ThreadStress/ThreadStress.java b/test/004-ThreadStress/src/Main.java
similarity index 89%
rename from test/ThreadStress/ThreadStress.java
rename to test/004-ThreadStress/src/Main.java
index 5dccc68..0c1c97d 100644
--- a/test/ThreadStress/ThreadStress.java
+++ b/test/004-ThreadStress/src/Main.java
@@ -14,9 +14,7 @@
  * limitations under the License.
  */
 
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
+import java.lang.reflect.*;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -26,7 +24,7 @@
 
 // Run on host with:
 //   javac ThreadTest.java && java ThreadStress && rm *.class
-class ThreadStress implements Runnable {
+public class Main implements Runnable {
 
     public static final boolean DEBUG = false;
 
@@ -80,7 +78,7 @@
         // Fill in the Operation[] array for each thread by laying
         // down references to operation according to their desired
         // frequency.
-        final ThreadStress[] threadStresses = new ThreadStress[numberOfThreads];
+        final Main[] threadStresses = new Main[numberOfThreads];
         for (int t = 0; t < threadStresses.length; t++) {
             Operation[] operations = new Operation[operationsPerThread];
             int o = 0;
@@ -98,7 +96,7 @@
             }
             // Randomize the oepration order
             Collections.shuffle(Arrays.asList(operations));
-            threadStresses[t] = new ThreadStress(lock, t, operations);
+            threadStresses[t] = new Main(lock, t, operations);
         }
 
         // Enable to dump operation counds per thread to make sure its
@@ -129,9 +127,9 @@
         // operationsPerThread.
         Thread[] runners = new Thread[numberOfThreads];
         for (int r = 0; r < runners.length; r++) {
-            final ThreadStress ts = threadStresses[r];
+            final Main ts = threadStresses[r];
             runners[r] = new Thread("Runner thread " + r) {
-                final ThreadStress threadStress = ts;
+                final Main threadStress = ts;
                 public void run() {
                     int id = threadStress.id;
                     System.out.println("Starting worker for " + id);
@@ -146,7 +144,7 @@
                                            + (operationsPerThread - threadStress.nextOperation)
                                            + " operations remaining.");
                     }
-                    System.out.println("Finishing worker for " + id);
+                    System.out.println("Finishing worker");
                 }
             };
         }
@@ -179,7 +177,7 @@
 
     private int nextOperation;
 
-    private ThreadStress(Object lock, int id, Operation[] operations) {
+    private Main(Object lock, int id, Operation[] operations) {
         this.lock = lock;
         this.id = id;
         this.operations = operations;
@@ -204,8 +202,8 @@
                     }
                     case SIGQUIT: {
                         try {
-                            Os.kill(Os.getpid(), OsConstants.SIGQUIT);
-                        } catch (ErrnoException ex) {
+                            SIGQUIT();
+                        } catch (Exception ex) {
                         }
                     }
                     case SLEEP: {
@@ -267,4 +265,17 @@
             }
         }
     }
+
+    private static void SIGQUIT() throws Exception {
+        Class<?> osClass = Class.forName("android.system.Os");
+        Method getpid = osClass.getDeclaredMethod("getpid");
+        int pid = (Integer)getpid.invoke(null);
+
+        Class<?> osConstants = Class.forName("android.system.OsConstants");
+        Field sigquitField = osConstants.getDeclaredField("SIGQUIT");
+        int sigquit = (Integer)sigquitField.get(null);
+
+        Method kill = osClass.getDeclaredMethod("kill", int.class, int.class);
+        kill.invoke(null, pid, sigquit);
+    }
 }
diff --git a/test/004-UnsafeTest/expected.txt b/test/004-UnsafeTest/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/004-UnsafeTest/expected.txt
diff --git a/test/004-UnsafeTest/info.txt b/test/004-UnsafeTest/info.txt
new file mode 100644
index 0000000..00b0d9a
--- /dev/null
+++ b/test/004-UnsafeTest/info.txt
@@ -0,0 +1 @@
+Imported from oat tests.
diff --git a/test/UnsafeTest/UnsafeTest.java b/test/004-UnsafeTest/src/Main.java
similarity index 95%
rename from test/UnsafeTest/UnsafeTest.java
rename to test/004-UnsafeTest/src/Main.java
index 9e2ff87..8c8ad16 100644
--- a/test/UnsafeTest/UnsafeTest.java
+++ b/test/004-UnsafeTest/src/Main.java
@@ -17,21 +17,21 @@
 import java.lang.reflect.Field;
 import sun.misc.Unsafe;
 
-public class UnsafeTest {
+public class Main {
   static {
     System.loadLibrary("arttest");
   }
 
   private static void check(int actual, int expected, String msg) {
     if (actual != expected) {
-      System.logE(msg + " : " + actual + " != " + expected);
+      System.out.println(msg + " : " + actual + " != " + expected);
       System.exit(-1);
     }
   }
 
   private static void check(long actual, long expected, String msg) {
     if (actual != expected) {
-      System.logE(msg + " : " + actual + " != " + expected);
+      System.out.println(msg + " : " + actual + " != " + expected);
       System.exit(-1);
     }
   }
diff --git a/test/UnsafeTest/unsafe_test.cc b/test/004-UnsafeTest/unsafe_test.cc
similarity index 85%
rename from test/UnsafeTest/unsafe_test.cc
rename to test/004-UnsafeTest/unsafe_test.cc
index e36ee14..ca0e39e 100644
--- a/test/UnsafeTest/unsafe_test.cc
+++ b/test/004-UnsafeTest/unsafe_test.cc
@@ -24,14 +24,14 @@
 
 namespace art {
 
-extern "C" JNIEXPORT jint JNICALL Java_UnsafeTest_vmArrayBaseOffset(JNIEnv* env, jclass, jobject classObj) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayBaseOffset(JNIEnv* env, jclass, jobject classObj) {
   ScopedObjectAccess soa(env);
   mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
   return mirror::Array::DataOffset(
       Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType())).Int32Value();
 }
 
-extern "C" JNIEXPORT jint JNICALL Java_UnsafeTest_vmArrayIndexScale(JNIEnv* env, jclass, jobject classObj) {
+extern "C" JNIEXPORT jint JNICALL Java_Main_vmArrayIndexScale(JNIEnv* env, jclass, jobject classObj) {
   ScopedObjectAccess soa(env);
   mirror::Class* klass = soa.Decode<mirror::Class*>(classObj);
   return Primitive::ComponentSize(klass->GetComponentType()->GetPrimitiveType());
diff --git a/test/004-annotations/build b/test/005-annotations/build
similarity index 100%
rename from test/004-annotations/build
rename to test/005-annotations/build
diff --git a/test/004-annotations/expected.txt b/test/005-annotations/expected.txt
similarity index 100%
rename from test/004-annotations/expected.txt
rename to test/005-annotations/expected.txt
diff --git a/test/004-annotations/info.txt b/test/005-annotations/info.txt
similarity index 100%
rename from test/004-annotations/info.txt
rename to test/005-annotations/info.txt
diff --git a/test/004-annotations/src/Main.java b/test/005-annotations/src/Main.java
similarity index 100%
rename from test/004-annotations/src/Main.java
rename to test/005-annotations/src/Main.java
diff --git a/test/004-annotations/src/android/test/AnnoSimplePackage1.java b/test/005-annotations/src/android/test/AnnoSimplePackage1.java
similarity index 100%
rename from test/004-annotations/src/android/test/AnnoSimplePackage1.java
rename to test/005-annotations/src/android/test/AnnoSimplePackage1.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoArrayField.java b/test/005-annotations/src/android/test/anno/AnnoArrayField.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoArrayField.java
rename to test/005-annotations/src/android/test/anno/AnnoArrayField.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoFancyConstructor.java b/test/005-annotations/src/android/test/anno/AnnoFancyConstructor.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoFancyConstructor.java
rename to test/005-annotations/src/android/test/anno/AnnoFancyConstructor.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoFancyField.java b/test/005-annotations/src/android/test/anno/AnnoFancyField.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoFancyField.java
rename to test/005-annotations/src/android/test/anno/AnnoFancyField.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoFancyMethod.java b/test/005-annotations/src/android/test/anno/AnnoFancyMethod.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoFancyMethod.java
rename to test/005-annotations/src/android/test/anno/AnnoFancyMethod.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoFancyParameter.java b/test/005-annotations/src/android/test/anno/AnnoFancyParameter.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoFancyParameter.java
rename to test/005-annotations/src/android/test/anno/AnnoFancyParameter.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoFancyType.java b/test/005-annotations/src/android/test/anno/AnnoFancyType.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoFancyType.java
rename to test/005-annotations/src/android/test/anno/AnnoFancyType.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java b/test/005-annotations/src/android/test/anno/AnnoSimpleConstructor.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleConstructor.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleConstructor.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleField.java b/test/005-annotations/src/android/test/anno/AnnoSimpleField.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleField.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleField.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java b/test/005-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleLocalVariable.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleMethod.java b/test/005-annotations/src/android/test/anno/AnnoSimpleMethod.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleMethod.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleMethod.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimplePackage.java b/test/005-annotations/src/android/test/anno/AnnoSimplePackage.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimplePackage.java
rename to test/005-annotations/src/android/test/anno/AnnoSimplePackage.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleParameter.java b/test/005-annotations/src/android/test/anno/AnnoSimpleParameter.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleParameter.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleParameter.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleType.java b/test/005-annotations/src/android/test/anno/AnnoSimpleType.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleType.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleType.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleType2.java b/test/005-annotations/src/android/test/anno/AnnoSimpleType2.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleType2.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleType2.java
diff --git a/test/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java b/test/005-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
rename to test/005-annotations/src/android/test/anno/AnnoSimpleTypeInvis.java
diff --git a/test/004-annotations/src/android/test/anno/ExportedProperty.java b/test/005-annotations/src/android/test/anno/ExportedProperty.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/ExportedProperty.java
rename to test/005-annotations/src/android/test/anno/ExportedProperty.java
diff --git a/test/004-annotations/src/android/test/anno/FullyNoted.java b/test/005-annotations/src/android/test/anno/FullyNoted.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/FullyNoted.java
rename to test/005-annotations/src/android/test/anno/FullyNoted.java
diff --git a/test/004-annotations/src/android/test/anno/INoted.java b/test/005-annotations/src/android/test/anno/INoted.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/INoted.java
rename to test/005-annotations/src/android/test/anno/INoted.java
diff --git a/test/004-annotations/src/android/test/anno/IntToString.java b/test/005-annotations/src/android/test/anno/IntToString.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/IntToString.java
rename to test/005-annotations/src/android/test/anno/IntToString.java
diff --git a/test/004-annotations/src/android/test/anno/MissingAnnotation.java b/test/005-annotations/src/android/test/anno/MissingAnnotation.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/MissingAnnotation.java
rename to test/005-annotations/src/android/test/anno/MissingAnnotation.java
diff --git a/test/004-annotations/src/android/test/anno/SimplyNoted.java b/test/005-annotations/src/android/test/anno/SimplyNoted.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/SimplyNoted.java
rename to test/005-annotations/src/android/test/anno/SimplyNoted.java
diff --git a/test/004-annotations/src/android/test/anno/SomeClass.java b/test/005-annotations/src/android/test/anno/SomeClass.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/SomeClass.java
rename to test/005-annotations/src/android/test/anno/SomeClass.java
diff --git a/test/004-annotations/src/android/test/anno/SubNoted.java b/test/005-annotations/src/android/test/anno/SubNoted.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/SubNoted.java
rename to test/005-annotations/src/android/test/anno/SubNoted.java
diff --git a/test/004-annotations/src/android/test/anno/TestAnnotations.java b/test/005-annotations/src/android/test/anno/TestAnnotations.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/TestAnnotations.java
rename to test/005-annotations/src/android/test/anno/TestAnnotations.java
diff --git a/test/004-annotations/src/android/test/anno/package-info.java b/test/005-annotations/src/android/test/anno/package-info.java
similarity index 100%
rename from test/004-annotations/src/android/test/anno/package-info.java
rename to test/005-annotations/src/android/test/anno/package-info.java
diff --git a/test/004-annotations/src/android/test/package-info.java b/test/005-annotations/src/android/test/package-info.java
similarity index 100%
rename from test/004-annotations/src/android/test/package-info.java
rename to test/005-annotations/src/android/test/package-info.java
diff --git a/test/005-args/expected.txt b/test/006-args/expected.txt
similarity index 100%
rename from test/005-args/expected.txt
rename to test/006-args/expected.txt
diff --git a/test/005-args/info.txt b/test/006-args/info.txt
similarity index 100%
rename from test/005-args/info.txt
rename to test/006-args/info.txt
diff --git a/test/005-args/src/ArgsTest.java b/test/006-args/src/ArgsTest.java
similarity index 100%
rename from test/005-args/src/ArgsTest.java
rename to test/006-args/src/ArgsTest.java
diff --git a/test/005-args/src/Main.java b/test/006-args/src/Main.java
similarity index 100%
rename from test/005-args/src/Main.java
rename to test/006-args/src/Main.java
diff --git a/test/006-count10/expected.txt b/test/007-count10/expected.txt
similarity index 100%
rename from test/006-count10/expected.txt
rename to test/007-count10/expected.txt
diff --git a/test/006-count10/info.txt b/test/007-count10/info.txt
similarity index 100%
rename from test/006-count10/info.txt
rename to test/007-count10/info.txt
diff --git a/test/006-count10/src/Main.java b/test/007-count10/src/Main.java
similarity index 100%
rename from test/006-count10/src/Main.java
rename to test/007-count10/src/Main.java
diff --git a/test/007-exceptions/expected.txt b/test/008-exceptions/expected.txt
similarity index 100%
rename from test/007-exceptions/expected.txt
rename to test/008-exceptions/expected.txt
diff --git a/test/007-exceptions/info.txt b/test/008-exceptions/info.txt
similarity index 100%
rename from test/007-exceptions/info.txt
rename to test/008-exceptions/info.txt
diff --git a/test/007-exceptions/src/Main.java b/test/008-exceptions/src/Main.java
similarity index 100%
rename from test/007-exceptions/src/Main.java
rename to test/008-exceptions/src/Main.java
diff --git a/test/008-instanceof/expected.txt b/test/008-instanceof/expected.txt
deleted file mode 100644
index 77fd0cb..0000000
--- a/test/008-instanceof/expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-iface1.mFloaty = 5.0 wahoo
-aa.mFloaty = 5.0 wahoo
-bb.mWhoami = ImplB!
-aaOkay (false) = false
-bbOkay (true) = true
-Caught a ClassCastException (expected)
diff --git a/test/008-instanceof/src/Iface1.java b/test/008-instanceof/src/Iface1.java
deleted file mode 100644
index d7f5376..0000000
--- a/test/008-instanceof/src/Iface1.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2005 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Test stuff.
- */
-public interface Iface1 {
-
-    public int iFunc1(int ii);
-
-    public float mFloaty = 5.0f;
-
-    public String mWahoo = new String("wahoo");
-}
diff --git a/test/008-instanceof/src/Iface2.java b/test/008-instanceof/src/Iface2.java
deleted file mode 100644
index 2b33c39..0000000
--- a/test/008-instanceof/src/Iface2.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-/**
- * Another interface.
- */
-public interface Iface2 {
-
-    public int iFunc2(int ii);
-}
diff --git a/test/008-instanceof/src/Iface2Sub1.java b/test/008-instanceof/src/Iface2Sub1.java
deleted file mode 100644
index bcff8ab..0000000
--- a/test/008-instanceof/src/Iface2Sub1.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-/**
- * Another interface.
- */
-public interface Iface2Sub1 extends Iface2, Cloneable {
-
-    //public int iFunc2(int ii);
-}
diff --git a/test/008-instanceof/src/ImplA.java b/test/008-instanceof/src/ImplA.java
deleted file mode 100644
index 27364f2..0000000
--- a/test/008-instanceof/src/ImplA.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-/**
- * Blah.
- */
-public class ImplA implements Iface1, Iface2 {
-
-    public int iFunc1(int ii) {
-        return ii+1;
-    }
-    public int iFunc2(int ii) {
-        return ii+2;
-    }
-}
diff --git a/test/008-instanceof/src/ImplB.java b/test/008-instanceof/src/ImplB.java
deleted file mode 100644
index 8b05702..0000000
--- a/test/008-instanceof/src/ImplB.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2006 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.
- */
-
-/**
- * Blah.
- */
-public class ImplB implements Iface1, Iface2 {
-
-    public int iFunc1(int ii) {
-        return ii+10;
-    }
-    public int iFunc2(int ii) {
-        return ii+20;
-    }
-
-    public static String mWhoami = new String("ImplB!");
-}
diff --git a/test/008-instanceof/src/ImplBSub.java b/test/008-instanceof/src/ImplBSub.java
deleted file mode 100644
index a94ae4d..0000000
--- a/test/008-instanceof/src/ImplBSub.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2006 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Interface test.
- */
-public class ImplBSub extends ImplB implements /*Iface2,*/ Iface2Sub1 {
-
-    public int iFunc1(int ii) {
-        return ii+100;
-    }
-    public int iFunc2(int ii) {
-        return ii+200;
-    }
-}
diff --git a/test/008-instanceof/src/Main.java b/test/008-instanceof/src/Main.java
deleted file mode 100644
index 77f3f51..0000000
--- a/test/008-instanceof/src/Main.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/**
- * Test instanceof
- */
-public class Main {
-    public static void main(String args[]) {
-        Iface1 face1;
-        ImplA aa = new ImplA();
-        ImplBSub bb = new ImplBSub();
-        boolean aaOkay, bbOkay;
-
-        face1 = aa;
-        face1 = bb;
-
-        System.out.println("iface1.mFloaty = " + face1.mFloaty + " " + face1.mWahoo);
-        System.out.println("aa.mFloaty = " + aa.mFloaty + " " + aa.mWahoo);
-        System.out.println("bb.mWhoami = " + bb.mWhoami);
-
-        aaOkay = face1 instanceof ImplA;
-        System.out.print("aaOkay (false) = ");
-        System.out.println(aaOkay);
-        bbOkay = face1 instanceof ImplB;
-        System.out.print("bbOkay (true) = ");
-        System.out.println(bbOkay);
-
-        bb = (ImplBSub) face1;
-        try {
-            aa = (ImplA) face1;
-        }
-        catch (ClassCastException cce) {
-            System.out.println("Caught a ClassCastException (expected)");
-        }
-    }
-}
diff --git a/test/009-instanceof/expected.txt b/test/009-instanceof/expected.txt
new file mode 100644
index 0000000..967c0bf
--- /dev/null
+++ b/test/009-instanceof/expected.txt
@@ -0,0 +1,11 @@
+iface1.mFloaty = 5.0 wahoo
+aa.mFloaty = 5.0 wahoo
+bb.mWhoami = ImplB!
+aaOkay (false) = false
+bbOkay (true) = true
+Caught a ClassCastException (expected)
+instanceof Serializable = true
+instanceof Cloneable = true
+instanceof Runnable = false
+aaOkay (false) = false
+bbOkay (true) = true
diff --git a/test/008-instanceof/info.txt b/test/009-instanceof/info.txt
similarity index 100%
rename from test/008-instanceof/info.txt
rename to test/009-instanceof/info.txt
diff --git a/test/009-instanceof2/src/Iface1.java b/test/009-instanceof/src/Iface1.java
similarity index 100%
rename from test/009-instanceof2/src/Iface1.java
rename to test/009-instanceof/src/Iface1.java
diff --git a/test/009-instanceof2/src/Iface2.java b/test/009-instanceof/src/Iface2.java
similarity index 100%
rename from test/009-instanceof2/src/Iface2.java
rename to test/009-instanceof/src/Iface2.java
diff --git a/test/009-instanceof2/src/Iface2Sub1.java b/test/009-instanceof/src/Iface2Sub1.java
similarity index 100%
rename from test/009-instanceof2/src/Iface2Sub1.java
rename to test/009-instanceof/src/Iface2Sub1.java
diff --git a/test/009-instanceof2/src/ImplA.java b/test/009-instanceof/src/ImplA.java
similarity index 100%
rename from test/009-instanceof2/src/ImplA.java
rename to test/009-instanceof/src/ImplA.java
diff --git a/test/009-instanceof2/src/ImplB.java b/test/009-instanceof/src/ImplB.java
similarity index 100%
rename from test/009-instanceof2/src/ImplB.java
rename to test/009-instanceof/src/ImplB.java
diff --git a/test/009-instanceof2/src/ImplBSub.java b/test/009-instanceof/src/ImplBSub.java
similarity index 100%
rename from test/009-instanceof2/src/ImplBSub.java
rename to test/009-instanceof/src/ImplBSub.java
diff --git a/test/009-instanceof2/src/Main.java b/test/009-instanceof/src/Main.java
similarity index 66%
rename from test/009-instanceof2/src/Main.java
rename to test/009-instanceof/src/Main.java
index 15a1e50..807ae69 100644
--- a/test/009-instanceof2/src/Main.java
+++ b/test/009-instanceof/src/Main.java
@@ -19,10 +19,36 @@
  */
 public class Main {
     public static void main(String args[]) {
+        Iface1 face1;
+        ImplA aa = new ImplA();
+        ImplBSub bb = new ImplBSub();
+        boolean aaOkay, bbOkay;
+
+        face1 = aa;
+        face1 = bb;
+
+        System.out.println("iface1.mFloaty = " + face1.mFloaty + " " + face1.mWahoo);
+        System.out.println("aa.mFloaty = " + aa.mFloaty + " " + aa.mWahoo);
+        System.out.println("bb.mWhoami = " + bb.mWhoami);
+
+        aaOkay = face1 instanceof ImplA;
+        System.out.print("aaOkay (false) = ");
+        System.out.println(aaOkay);
+        bbOkay = face1 instanceof ImplB;
+        System.out.print("bbOkay (true) = ");
+        System.out.println(bbOkay);
+
+        bb = (ImplBSub) face1;
+        try {
+            aa = (ImplA) face1;
+        }
+        catch (ClassCastException cce) {
+            System.out.println("Caught a ClassCastException (expected)");
+        }
+
         Iface1[] faceArray;
         ImplA[] aaArray = new ImplA[5];
         ImplBSub[] bbArray = new ImplBSub[5];
-        boolean aaOkay, bbOkay;
 
         faceArray = aaArray;
         faceArray = bbArray;
diff --git a/test/009-instanceof2/expected.txt b/test/009-instanceof2/expected.txt
deleted file mode 100644
index 74ad202..0000000
--- a/test/009-instanceof2/expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-instanceof Serializable = true
-instanceof Cloneable = true
-instanceof Runnable = false
-aaOkay (false) = false
-bbOkay (true) = true
diff --git a/test/009-instanceof2/info.txt b/test/009-instanceof2/info.txt
deleted file mode 100644
index 08127da..0000000
--- a/test/009-instanceof2/info.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a miscellaneous test that was imported into the new-at-the-time
-runtime test framework. The test is intended to exercise basic features,
-and as such cannot be build on top of junit, since failure of such basic
-features might disrupt junit.
-
-TODO: Real description goes here.
diff --git a/test/083-compiler-regressions/expected.txt b/test/083-compiler-regressions/expected.txt
index 10406c7..9f57dbd 100644
--- a/test/083-compiler-regressions/expected.txt
+++ b/test/083-compiler-regressions/expected.txt
@@ -14,6 +14,7 @@
 false
 b13679511Test finishing
 b16177324TestWrapper caught NPE as expected.
+b16230771TestWrapper caught NPE as expected.
 largeFrame passes
 largeFrameFloat passes
 mulBy1Test passes
diff --git a/test/083-compiler-regressions/src/Main.java b/test/083-compiler-regressions/src/Main.java
index 18bc674..748b0de 100644
--- a/test/083-compiler-regressions/src/Main.java
+++ b/test/083-compiler-regressions/src/Main.java
@@ -36,6 +36,7 @@
         b5884080Test();
         b13679511Test();
         b16177324TestWrapper();
+        b16230771TestWrapper();
         largeFrameTest();
         largeFrameTestFloat();
         mulBy1Test();
@@ -927,6 +928,28 @@
       System.out.println("Unexpectedly retrieved all values: " + v1 + ", " + v2 + ", " + v3);
     }
 
+    static void b16230771TestWrapper() {
+      try {
+        b16230771Test();
+      } catch (NullPointerException expected) {
+        System.out.println("b16230771TestWrapper caught NPE as expected.");
+      }
+    }
+
+    static void b16230771Test() {
+      Integer[] array = { null };
+      for (Integer i : array) {
+        try {
+          int value = i;  // Null check on unboxing should fail.
+          System.out.println("Unexpectedly retrieved value " + value);
+        } catch (NullPointerException e) {
+          int value = i;  // Null check on unboxing should fail.
+          // The bug was a missing null check, so this would actually cause SIGSEGV.
+          System.out.println("Unexpectedly retrieved value " + value + " in NPE catch handler");
+        }
+      }
+    }
+
     static double TooManyArgs(
           long l00,
           long l01,
diff --git a/test/114-ParallelGC/expected.txt b/test/114-ParallelGC/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/114-ParallelGC/expected.txt
diff --git a/test/114-ParallelGC/info.txt b/test/114-ParallelGC/info.txt
new file mode 100644
index 0000000..246b4e6
--- /dev/null
+++ b/test/114-ParallelGC/info.txt
@@ -0,0 +1 @@
+Imported from oat tests. Allocates and frees objects with multiple threads.
diff --git a/test/ParallelGC/ParallelGC.java b/test/114-ParallelGC/src/Main.java
similarity index 87%
rename from test/ParallelGC/ParallelGC.java
rename to test/114-ParallelGC/src/Main.java
index eb9e04e..01a3023 100644
--- a/test/ParallelGC/ParallelGC.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -17,11 +17,11 @@
 import java.util.ArrayList;
 import java.util.List;
 
-class ParallelGC implements Runnable {
+public class Main implements Runnable {
     public static void main(String[] args) throws Exception {
         Thread[] threads = new Thread[16];
         for (int i = 0; i < threads.length; i++) {
-            threads[i] = new Thread(new ParallelGC(i));
+            threads[i] = new Thread(new Main(i));
         }
         for (Thread thread : threads) {
             thread.start();
@@ -33,7 +33,7 @@
 
     private final int id;
 
-    private ParallelGC(int id) {
+    private Main(int id) {
         this.id = id;
     }
 
@@ -41,7 +41,6 @@
         List l = new ArrayList();
         for (int i = 0; i < 1000; i++) {
             l.add(new ArrayList(i));
-            System.out.print(id);
         }
     }
 }
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index bf3e2aa..f3563a4 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -19,11 +19,11 @@
 include art/build/Android.common_build.mk
 
 LIBARTTEST_COMMON_SRC_FILES := \
-  JniTest/jni_test.cc \
-  SignalTest/signaltest.cc \
-  ReferenceMap/stack_walk_refmap_jni.cc \
-  StackWalk/stack_walk_jni.cc \
-  UnsafeTest/unsafe_test.cc
+  004-JniTest/jni_test.cc \
+  004-SignalTest/signaltest.cc \
+  004-ReferenceMap/stack_walk_refmap_jni.cc \
+  004-StackWalk/stack_walk_jni.cc \
+  004-UnsafeTest/unsafe_test.cc
 
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
 ifdef TARGET_2ND_ARCH
diff --git a/test/Android.oat.mk b/test/Android.oat.mk
deleted file mode 100644
index 7a43575..0000000
--- a/test/Android.oat.mk
+++ /dev/null
@@ -1,525 +0,0 @@
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-LOCAL_PID := $(shell echo $$PPID)
-
-include art/build/Android.common_test.mk
-
-########################################################################
-
-# Subdirectories in art/test which contain dex files used as inputs for oat tests. Declare the
-# simplest tests (Main, HelloWorld) first, the rest are alphabetical.
-TEST_OAT_DIRECTORIES := \
-  Main \
-  HelloWorld \
-  InterfaceTest \
-  JniTest \
-  SignalTest \
-  NativeAllocations \
-  ParallelGC \
-  ReferenceMap \
-  StackWalk \
-  ThreadStress \
-  UnsafeTest
-
-# TODO: Enable when the StackWalk2 tests are passing
-#  StackWalk2 \
-
-# Create build rules for each dex file recording the dependency.
-$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call build-art-test-dex,art-oat-test,$(dir), \
-  $(ART_TARGET_TEST_OUT),$(LOCAL_PATH)/Android.oat.mk,ART_TEST_TARGET_OAT_$(dir)_DEX, \
-  ART_TEST_HOST_OAT_$(dir)_DEX)))
-
-########################################################################
-
-include $(LOCAL_PATH)/Android.libarttest.mk
-
-ART_TEST_TARGET_OAT_DEFAULT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_DEFAULT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_DEFAULT_RULES :=
-ART_TEST_TARGET_OAT_OPTIMIZING$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_OPTIMIZING_RULES :=
-ART_TEST_TARGET_OAT_INTERPRETER$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_INTERPRETER_RULES :=
-ART_TEST_TARGET_OAT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_RULES :=
-
-# We need dex2oat and dalvikvm on the target as well as the core image.
-TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUT) $(2ND_TARGET_CORE_IMG_OUT) $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
-ifdef TARGET_2ND_ARCH
-TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_2ND_ARCH)/libarttest.so
-endif
-
-# Define rule to run an individual oat test on the host. Output from the test is written to the
-# host in /tmp/android-data in a directory named after test's rule name (its target) and the parent
-# process' PID (ie the PID of make). On failure the output is dumped to the console. To test for
-# success on the target device a file is created following a successful test and this is pulled
-# onto the host. If the pull fails then the file wasn't created because the test failed.
-# $(1): directory - the name of the test we're building such as HelloWorld.
-# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
-# $(3): the target (rule name), e.g. test-art-target-oat-default-HelloWorld64
-# $(4): -Xint or undefined - do we want to run with the interpreter or default.
-define define-test-art-oat-rule-target
-  # Add the test dependencies to test-art-target-sync, which will be a prerequisite for the test
-  # to ensure files are pushed to the device.
-  TEST_ART_TARGET_SYNC_DEPS += $$(ART_TEST_TARGET_OAT_$(1)_DEX)
-
-.PHONY: $(3)
-$(3): test-art-target-sync
-	$(hide) mkdir -p $(ART_HOST_TEST_DIR)/android-data-$$@
-	$(hide) echo Running: $$@
-	$(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID)
-	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID)
-	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  adb shell "/system/bin/dalvikvm$($(2)ART_PHONY_TEST_TARGET_SUFFIX) \
-	    $(DALVIKVM_FLAGS) $(4) -XXlib:libartd.so -Ximage:$(ART_TARGET_TEST_DIR)/core.art \
-	    -classpath $(ART_TARGET_TEST_DIR)/art-oat-test-$(1).jar \
-	    -Djava.library.path=$(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH) $(1) \
-	      && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID)" \
-	        > $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt 2>&1 && \
-	  (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$(LOCAL_PID) $(ART_HOST_TEST_DIR)/android-data-$$@ \
-	    && $$(call ART_TEST_PASSED,$$@)) \
-	    || (([ ! -f $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt ] || \
-	         cat $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt >&2 ) && $$(call ART_TEST_FAILED,$$@))
-	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
-	  echo "run-test run as top-level target, removing test directory $(ART_HOST_TEST_DIR)" && \
-	  rm -r $(ART_HOST_TEST_DIR)) || true
-
-endef  # define-test-art-oat-rule-target
-
-# Define rules to run oat tests on the target.
-# $(1): directory - the name of the test we're building such as HelloWorld.
-# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
-# $(3): additional options
-# $(4): name-addition
-define define-test-art-oat-rules-target
-  # Define a phony rule to run a target oat test using the default compiler.
-  default_test_rule := test-art-target-oat-default$(4)-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
-  $(call define-test-art-oat-rule-target,$(1),$(2),$$(default_test_rule),$(3))
-
-  ART_TEST_TARGET_OAT_DEFAULT$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(default_test_rule)
-  ART_TEST_TARGET_OAT_DEFAULT_RULES += $$(default_test_rule)
-  ART_TEST_TARGET_OAT_DEFAULT_$(1)_RULES += $$(default_test_rule)
-
-  optimizing_test_rule := test-art-target-oat-optimizing$(4)-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
-  ifeq ($$(ART_TEST_OPTIMIZING),true)
-    $(call define-test-art-oat-rule-target,$(1),$(2),$$(optimizing_test_rule), \
-      -Xcompiler-option --compiler-backend=Optimizing $(3))
-  else
-    .PHONY: $$(optimizing_test_rule)
-$$(optimizing_test_rule):
-
-  endif
-
-  ART_TEST_TARGET_OAT_OPTIMIZING$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(optimizing_test_rule)
-  ART_TEST_TARGET_OAT_OPTIMIZING_RULES += $$(optimizing_test_rule)
-  ART_TEST_TARGET_OAT_OPTIMIZING_$(1)_RULES += $$(optimizing_test_rule)
-
-  # Define a phony rule to run a target oat test using the interpeter.
-  interpreter_test_rule := test-art-target-oat-interpreter$(4)-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
-  $(call define-test-art-oat-rule-target,$(1),$(2),$$(interpreter_test_rule),-Xint $(3))
-
-  ART_TEST_TARGET_OAT_INTERPRETER$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(interpreter_test_rule)
-  ART_TEST_TARGET_OAT_INTERPRETER_RULES += $$(interpreter_test_rule)
-  ART_TEST_TARGET_OAT_INTERPRETER_$(1)_RULES += $$(interpreter_test_rule)
-
-  # Define a phony rule to run both the default and interpreter variants.
-  all_test_rule :=  test-art-target-oat$(4)-$(1)$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
-.PHONY: $$(all_test_rule)
-$$(all_test_rule): $$(default_test_rule) $$(optimizing_test_rule) $$(interpreter_test_rule)
-	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
-
-  ART_TEST_TARGET_OAT$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(all_test_rule)
-  ART_TEST_TARGET_OAT_RULES += $$(all_test_rule)
-  ART_TEST_TARGET_OAT_$(1)_RULES += $$(all_test_rule)
-
-  # Clear locally defined variables.
-  interpreter_test_rule :=
-  default_test_rule :=
-  optimizing_test_rule :=
-  all_test_rule :=
-endef  # define-test-art-oat-rules-target
-
-ART_TEST_HOST_OAT_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_DEFAULT_RULES :=
-ART_TEST_HOST_OAT_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_OPTIMIZING_RULES :=
-ART_TEST_HOST_OAT_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_INTERPRETER_RULES :=
-ART_TEST_HOST_OAT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_RULES :=
-
-# All tests require the host executables, libarttest and the core images.
-ART_TEST_HOST_OAT_DEPENDENCIES := \
-  $(ART_HOST_EXECUTABLES) \
-  $(ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
-  $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
-  $(HOST_CORE_IMG_OUT)
-
-ifneq ($(HOST_PREFER_32_BIT),true)
-ART_TEST_HOST_OAT_DEPENDENCIES += \
-  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
-  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
-  $(2ND_HOST_CORE_IMG_OUT)
-endif
-
-# Define rule to run an individual oat test on the host. Output from the test is written to the
-# host in /tmp/android-data in a directory named after test's rule name (its target) and the parent
-# process' PID (ie the PID of make). On failure the output is dumped to the console.
-# $(1): directory - the name of the test we're building such as HelloWorld.
-# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
-# $(3): the target (rule name), e.g. test-art-host-oat-default-HelloWorld64
-# $(4): argument to dex2oat
-# $(5): argument to runtime, e.g. -Xint or undefined
-define define-test-art-oat-rule-host
-  # Remove the leading / from /tmp for the test directory.
-  dex_file := $$(subst /tmp,tmp,$(ART_HOST_TEST_DIR))/android-data-$(3)/oat-test-dex-$(1).jar
-  oat_file := $(ART_HOST_TEST_DIR)/android-data-$(3)/dalvik-cache/$$($(2)HOST_ARCH)/$$(subst /,@,$$(dex_file))@classes.dex
-$(3): PRIVATE_DEX_FILE := /$$(dex_file)
-$(3): PRIVATE_OAT_FILE := $$(oat_file)
-.PHONY: $(3)
-$(3): $$(ART_TEST_HOST_OAT_$(1)_DEX) $(ART_TEST_HOST_OAT_DEPENDENCIES)
-	$(hide) mkdir -p $(ART_HOST_TEST_DIR)/android-data-$$@/dalvik-cache/$$($(2)HOST_ARCH)
-	$(hide) cp $$(realpath $$<) $(ART_HOST_TEST_DIR)/android-data-$$@/oat-test-dex-$(1).jar
-	$(hide) $(DEX2OATD) $(DEX2OAT_FLAGS) --runtime-arg -Xms$(DEX2OAT_XMS) --runtime-arg -Xmx$(DEX2OAT_XMX) $(4) \
-	  --boot-image=$$(HOST_CORE_IMG_LOCATION) --include-patch-information \
-	  --dex-file=$$(PRIVATE_DEX_FILE) --oat-file=$$(PRIVATE_OAT_FILE) \
-	  --instruction-set=$($(2)ART_HOST_ARCH) --host --android-root=$(HOST_OUT) \
-	  || $$(call ART_TEST_FAILED,$$@)
-	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	ANDROID_DATA=$(ART_HOST_TEST_DIR)/android-data-$$@/ \
-	ANDROID_ROOT=$(HOST_OUT) \
-	ANDROID_LOG_TAGS='*:d' \
-	LD_LIBRARY_PATH=$$($(2)ART_HOST_OUT_SHARED_LIBRARIES) \
-	LD_PRELOAD=libsigchain$$(ART_HOST_SHLIB_EXTENSION) \
-	$(HOST_OUT_EXECUTABLES)/dalvikvm$$($(2)ART_PHONY_TEST_HOST_SUFFIX) $(DALVIKVM_FLAGS) $(5) \
-	    -XXlib:libartd$(HOST_SHLIB_SUFFIX) -Ximage:$$(HOST_CORE_IMG_LOCATION) \
-	    -classpath $(ART_HOST_TEST_DIR)/android-data-$$@/oat-test-dex-$(1).jar \
-	    -Djava.library.path=$$($(2)ART_HOST_OUT_SHARED_LIBRARIES) $(1) \
-	      > $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt 2>&1 \
-	  && $$(call ART_TEST_PASSED,$$@) \
-	  || (([ ! -f $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt ] || \
-	       cat $(ART_HOST_TEST_DIR)/android-data-$$@/output.txt >&2 ) && $$(call ART_TEST_FAILED,$$@))
-	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
-	  echo "run-test run as top-level target, removing test directory $(ART_HOST_TEST_DIR)" && \
-	  rm -r $(ART_HOST_TEST_DIR)) || true
-endef  # define-test-art-oat-rule-host
-
-# Define rules to run oat tests on the host.
-# $(1): directory - the name of the test we're building such as HelloWorld.
-# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
-define define-test-art-oat-rules-host
-  # Create a rule to run the host oat test with the default compiler.
-  default_test_rule := test-art-host-oat-default-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
-  $(call define-test-art-oat-rule-host,$(1),$(2),$$(default_test_rule),,)
-
-  ART_TEST_HOST_OAT_DEFAULT$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(default_test_rule)
-  ART_TEST_HOST_OAT_DEFAULT_RULES += $$(default_test_rule)
-  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES += $$(default_test_rule)
-
-  gcverify_test_rule := test-art-host-oat-gcverify-default-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
-  ifeq ($$(ART_TEST_GC_VERIFY),true)
-    $(call define-test-art-oat-rule-host,$(1),$(2),$$(gcverify_test_rule),,-Xgc:preverify -Xgc:postverify -Xgc:preverify_rosalloc -Xgc:postverify_rosalloc)
-  else
-    .PHONY: $$(gcverify_test_rule)
-$$(gcverify_test_rule):
-
-  endif
-
-  ART_TEST_HOST_OAT_DEFAULT$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(gcverify_test_rule)
-  ART_TEST_HOST_OAT_DEFAULT_RULES += $$(gcverify_test_rule)
-  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES += $$(gcverify_test_rule)
-
-  gcstress_test_rule := test-art-host-oat-gcstress-default-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
-  ifeq ($$(ART_TEST_GC_STRESS),true)
-    $(call define-test-art-oat-rule-host,$(1),$(2),$$(gcstress_test_rule),,-Xgc:SS -Xms2m -Xmx2m -Xgc:preverify -Xgc:postverify)
-  else
-    .PHONY: $$(gcstress_test_rule)
-$$(gcstress_test_rule):
-
-  endif
-
-  ART_TEST_HOST_OAT_DEFAULT$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(gcstress_test_rule)
-  ART_TEST_HOST_OAT_DEFAULT_RULES += $$(gcstress_test_rule)
-  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES += $$(gcstress_test_rule)
-
-  # Create a rule to run the host oat test with the optimizing compiler.
-  optimizing_test_rule := test-art-host-oat-optimizing-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
-  ifeq ($$(ART_TEST_OPTIMIZING),true)
-    $(call define-test-art-oat-rule-host,$(1),$(2),$$(optimizing_test_rule),--compiler-backend=Optimizing,)
-  else
-    .PHONY: $$(optimizing_test_rule)
-$$(optimizing_test_rule):
-
-  endif
-
-  ART_TEST_HOST_OAT_OPTIMIZING$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(optimizing_test_rule)
-  ART_TEST_HOST_OAT_OPTIMIZING_RULES += $$(optimizing_test_rule)
-  ART_TEST_HOST_OAT_OPTIMIZING_$(1)_RULES += $$(optimizing_test_rule)
-
-  # Create a rule to run the host oat test with the interpreter.
-  interpreter_test_rule := test-art-host-oat-interpreter-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
-  $(call define-test-art-oat-rule-host,$(1),$(2),$$(interpreter_test_rule),--compiler-filter=interpret-only,-Xint)
-
-  ART_TEST_HOST_OAT_INTERPRETER$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(interpreter_test_rule)
-  ART_TEST_HOST_OAT_INTERPRETER_RULES += $$(interpreter_test_rule)
-  ART_TEST_HOST_OAT_INTERPRETER_$(1)_RULES += $$(interpreter_test_rule)
-
-  # Define a phony rule to run both the default and interpreter variants.
-  all_test_rule :=  test-art-host-oat-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
-.PHONY: $$(all_test_rule)
-$$(all_test_rule): $$(default_test_rule) $$(gcverify_test_rule) $$(gcstress_test_rule) $$(interpreter_test_rule) $$(optimizing_test_rule)
-	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
-
-  ART_TEST_HOST_OAT$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(all_test_rule)
-  ART_TEST_HOST_OAT_RULES += $$(all_test_rule)
-  ART_TEST_HOST_OAT_$(1)_RULES += $$(all_test_rule)
-
-  # Clear locally defined variables.
-  default_test_rule :=
-  gcverify_test_rule :=
-  optimizing_test_rule :=
-  interpreter_test_rule :=
-  all_test_rule :=
-endef  # define-test-art-oat-rules-host
-
-# For a given test create all the combinations of host/target, compiler and suffix such as:
-# test-art-host-oat-HelloWord or test-art-target-oat-interpreter-HelloWorld64
-# $(1): test name, e.g. HelloWorld
-# $(2): host or target
-# $(3): HOST or TARGET
-# $(4): undefined, -default, -optimizing or -interpreter
-# $(5): undefined, _DEFAULT, _OPTIMIZING or _INTERPRETER
-define define-test-art-oat-combination-for-test
-  ifeq ($(2),host)
-    ifneq ($(3),HOST)
-      $$(error argument mismatch $(2) and ($3))
-    endif
-  else
-    ifneq ($(2),target)
-      $$(error found $(2) expected host or target)
-    endif
-    ifneq ($(3),TARGET)
-      $$(error argument mismatch $(2) and ($3))
-    endif
-  endif
-
-  rule_name := test-art-$(2)-oat$(4)-$(1)
-  dependencies := $$(ART_TEST_$(3)_OAT$(5)_$(1)_RULES)
-
-  ifeq ($$(dependencies),)
-    ifneq ($(4),-optimizing)
-      $$(error $$(rule_name) has no dependencies)
-    endif
-  endif
-
-.PHONY: $$(rule_name)
-$$(rule_name): $$(dependencies)
-	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
-
-  # Clear locally defined variables.
-  rule_name :=
-  dependencies :=
-endef  # define-test-art-oat-combination
-
-# Define target and host oat test rules for the differing multilib flavors and default vs
-# interpreter runs. The format of the generated rules (for running an individual test) is:
-#   test-art-(host|target)-oat-(default|interpreter)-${directory}(32|64)
-# The rules are appended to various lists to enable shorter phony build rules to be built.
-# $(1): directory
-define define-test-art-oat-rules
-  # Define target tests.
-  ART_TEST_TARGET_OAT_DEFAULT_$(1)_RULES :=
-  ART_TEST_TARGET_OAT_OPTIMIZING_$(1)_RULES :=
-  ART_TEST_TARGET_OAT_INTERPRETER_$(1)_RULES :=
-  ART_TEST_TARGET_OAT_$(1)_RULES :=
-  ifeq ($(ART_TEST_OAT_NO_RELOCATE),true)
-    $(call define-test-art-oat-rules-target,$(1),, \
-          -Xnorelocate -Xcompiler-option --no-include-patch-information,-norelocate)
-    ifdef TARGET_2ND_ARCH
-      $(call define-test-art-oat-rules-target,$(1),2ND_, \
-          -Xnorelocate -Xcompiler-option --no-include-patch-information,-norelocate)
-    endif
-  endif
-  ifeq ($(ART_TEST_OAT_RELOCATE),true)
-    $(call define-test-art-oat-rules-target,$(1),, \
-          -Xrelocate -Xcompiler-option --include-patch-information,-relocate)
-    ifdef TARGET_2ND_ARCH
-      $(call define-test-art-oat-rules-target,$(1),2ND_, \
-          -Xrelocate -Xcompiler-option --include-patch-information,-relocate)
-    endif
-  endif
-  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,,))
-  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,-default,_DEFAULT))
-  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,-optimizing,_OPTIMIZING))
-  $(call define-test-art-oat-combination-for-test,$(1),target,TARGET,-interpreter,_INTERPRETER))
-
-  # Define host tests.
-  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES :=
-  ART_TEST_HOST_OAT_OPTIMIZING_$(1)_RULES :=
-  ART_TEST_HOST_OAT_INTERPRETER_$(1)_RULES :=
-  ART_TEST_HOST_OAT_$(1)_RULES :=
-  $(call define-test-art-oat-rules-host,$(1),)
-  ifneq ($(HOST_PREFER_32_BIT),true)
-    $(call define-test-art-oat-rules-host,$(1),2ND_)
-  endif
-  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,,)
-  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,-default,_DEFAULT)
-  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,-optimizing,_OPTIMIZING)
-  $(call define-test-art-oat-combination-for-test,$(1),host,HOST,-interpreter,_INTERPRETER)
-
-  # Clear locally defined variables.
-  ART_TEST_TARGET_OAT_DEFAULT_$(1)_RULES :=
-  ART_TEST_TARGET_OAT_OPTIMIZING_$(1)_RULES :=
-  ART_TEST_TARGET_OAT_INTERPRETER_$(1)_RULES :=
-  ART_TEST_TARGET_OAT_$(1)_RULES :=
-  ART_TEST_HOST_OAT_DEFAULT_$(1)_RULES :=
-  ART_TEST_HOST_OAT_OPTIMIZING_$(1)_RULES :=
-  ART_TEST_HOST_OAT_INTERPRETER_$(1)_RULES :=
-  ART_TEST_HOST_OAT_$(1)_RULES :=
-endef  # define-test-art-oat-rules
-$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval $(call define-test-art-oat-rules,$(dir))))
-
-# Define all the combinations of host/target, compiler and suffix such as:
-# test-art-host-oat or test-art-target-oat-interpreter64
-# $(1): host or target
-# $(2): HOST or TARGET
-# $(3): undefined, -default, -optimizing or -interpreter
-# $(4): undefined, _DEFAULT, _OPTIMIZING or _INTERPRETER
-# $(5): undefined, 32 or 64
-define define-test-art-oat-combination
-  ifeq ($(1),host)
-    ifneq ($(2),HOST)
-      $$(error argument mismatch $(1) and ($2))
-    endif
-  else
-    ifneq ($(1),target)
-      $$(error found $(1) expected host or target)
-    endif
-    ifneq ($(2),TARGET)
-      $$(error argument mismatch $(1) and ($2))
-    endif
-  endif
-
-  rule_name := test-art-$(1)-oat$(3)$(5)
-  dependencies := $$(ART_TEST_$(2)_OAT$(4)$(5)_RULES)
-
-  ifeq ($$(dependencies),)
-    ifneq ($(3),-optimizing)
-      $$(error $$(rule_name) has no dependencies)
-    endif
-  endif
-
-.PHONY: $$(rule_name)
-$$(rule_name): $$(dependencies)
-	$(hide) $$(call ART_TEST_PREREQ_FINISHED,$$@)
-
-  # Clear locally defined variables.
-  rule_name :=
-  dependencies :=
-
-endef  # define-test-art-oat-combination
-
-$(eval $(call define-test-art-oat-combination,target,TARGET,,,))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-default,_DEFAULT,))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-optimizing,_OPTIMIZING,))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-interpreter,_INTERPRETER,))
-$(eval $(call define-test-art-oat-combination,target,TARGET,,,$(ART_PHONY_TEST_TARGET_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-default,_DEFAULT,$(ART_PHONY_TEST_TARGET_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-optimizing,_OPTIMIZING,$(ART_PHONY_TEST_TARGET_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-interpreter,_INTERPRETER,$(ART_PHONY_TEST_TARGET_SUFFIX)))
-ifdef TARGET_2ND_ARCH
-$(eval $(call define-test-art-oat-combination,target,TARGET,,,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-default,_DEFAULT,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-optimizing,_OPTIMIZING,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,target,TARGET,-interpreter,_INTERPRETER,$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)))
-endif
-
-$(eval $(call define-test-art-oat-combination,host,HOST,,,))
-$(eval $(call define-test-art-oat-combination,host,HOST,-default,_DEFAULT,))
-$(eval $(call define-test-art-oat-combination,host,HOST,-optimizing,_OPTIMIZING,))
-$(eval $(call define-test-art-oat-combination,host,HOST,-interpreter,_INTERPRETER,))
-$(eval $(call define-test-art-oat-combination,host,HOST,,,$(ART_PHONY_TEST_HOST_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,host,HOST,-default,_DEFAULT,$(ART_PHONY_TEST_HOST_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,host,HOST,-optimizing,_OPTIMIZING,$(ART_PHONY_TEST_HOST_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,host,HOST,-interpreter,_INTERPRETER,$(ART_PHONY_TEST_HOST_SUFFIX)))
-ifneq ($(HOST_PREFER_32_BIT),true)
-$(eval $(call define-test-art-oat-combination,host,HOST,,,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,host,HOST,-default,_DEFAULT,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,host,HOST,-optimizing,_OPTIMIZING,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
-$(eval $(call define-test-art-oat-combination,host,HOST,-interpreter,_INTERPRETER,$(2ND_ART_PHONY_TEST_HOST_SUFFIX)))
-endif
-
-# List -relocate version on the target as broken.
-
-# List all the test names for target and compiler variants.
-# $(1): test name, e.g. Main
-# $(2): -relocate, -norelocate, -prebuild, or undefined.
-define all-oat-test-target-names
-  test-art-target-oat-default$(2)-$(1)32 \
-  test-art-target-oat-optimizing$(2)-$(1)32 \
-  test-art-target-oat-interpreter$(2)-$(1)32 \
-  test-art-target-oat-default$(2)-$(1)64 \
-  test-art-target-oat-optimizing$(2)-$(1)64 \
-  test-art-target-oat-interpreter$(2)-$(1)64
-endef  # all-oat-test-target-names
-
-ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_OAT_DIRECTORIES), $(call all-oat-test-target-names,$(test),-relocate))
-
-# Clear locally defined variables.
-define-test-art-oat-rule-target :=
-define-test-art-oat-rules-target :=
-define-test-art-oat-rule-host :=
-define-test-art-oat-rules-host :=
-define-test-art-oat-combination-for-test :=
-define-test-art-oat-combination :=
-ART_TEST_TARGET_OAT_DEFAULT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_DEFAULT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_DEFAULT_RULES :=
-ART_TEST_TARGET_OAT_OPTIMIZING$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_OPTIMIZING_RULES :=
-ART_TEST_TARGET_OAT_INTERPRETER$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_INTERPRETER_RULES :=
-ART_TEST_TARGET_OAT$(ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)_RULES :=
-ART_TEST_TARGET_OAT_RULES :=
-ART_TEST_HOST_OAT_DEFAULT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_DEFAULT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_DEFAULT_RULES :=
-ART_TEST_HOST_OAT_OPTIMIZING$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_OPTIMIZING$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_OPTIMIZING_RULES :=
-ART_TEST_HOST_OAT_INTERPRETER$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_INTERPRETER$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_INTERPRETER_RULES :=
-ART_TEST_HOST_OAT$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
-ART_TEST_HOST_OAT_RULES :=
-ART_TEST_HOST_OAT_DEPENDENCIES :=
-$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval ART_TEST_TARGET_OAT_$(dir)_DEX :=))
-$(foreach dir,$(TEST_OAT_DIRECTORIES), $(eval ART_TEST_HOST_OAT_$(dir)_DEX :=))
-TEST_OAT_DIRECTORIES :=
-LOCAL_PID :=
-LOCAL_PATH :=
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 4f03347..ac47da6 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -72,7 +72,10 @@
 # Tests that are broken in --trace mode.
 TEST_ART_BROKEN_TRACE_RUN_TESTS := \
   003-omnibus-opcodes \
-  004-annotations \
+  004-InterfaceTest \
+  004-SignalTest \
+  004-ThreadStress \
+  005-annotations \
   012-math \
   018-stack-overflow \
   023-many-interfaces \
@@ -97,6 +100,7 @@
   103-string-append \
   107-int-math2 \
   112-double-math \
+  114-ParallelGC \
   700-LoadArgRegs \
   701-easy-div-rem
 
@@ -108,7 +112,8 @@
 
 # Tests that need more than 2MB of RAM or are running into other corner cases in GC stress related
 # to OOMEs.
-TEST_ART_BROKEN_GCSTRESS_RUN_TESTS :=
+TEST_ART_BROKEN_GCSTRESS_RUN_TESTS := \
+  114-ParallelGC
 
 ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(call all-run-test-names,$(test),-gcstress,-relocate))
 ART_TEST_KNOWN_BROKEN += $(foreach test, $(TEST_ART_BROKEN_GCSTRESS_RUN_TESTS), $(call all-run-test-names,$(test),-gcstress,-no-prebuild))
@@ -280,14 +285,22 @@
 # We need dex2oat and dalvikvm on the target as well as the core image.
 TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_EXECUTABLES) $(TARGET_CORE_IMG_OUT) $(2ND_TARGET_CORE_IMG_OUT)
 
+# Also need libarttest.
+TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
+ifdef TARGET_2ND_ARCH
+TEST_ART_TARGET_SYNC_DEPS += $(ART_TARGET_TEST_OUT)/$(TARGET_2ND_ARCH)/libarttest.so
+endif
+
 # All tests require the host executables and the core images.
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
   $(ART_HOST_EXECUTABLES) \
+  $(ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
   $(HOST_CORE_IMG_OUT)
 
 ifneq ($(HOST_PREFER_32_BIT),true)
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \
+  $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) \
   $(2ND_ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION) \
   $(2ND_HOST_CORE_IMG_OUT)
 endif
@@ -424,6 +437,7 @@
   ART_TEST_$$(uc_host_or_target)_RUN_TEST_$$(uc_compiler)_$(1)_RULES += $$(run_test_rule_name)
   ART_TEST_$$(uc_host_or_target)_RUN_TEST_$$(uc_compiler)_$$(uc_reloc_type)_RULES += $$(run_test_rule_name)
   ART_TEST_$$(uc_host_or_target)_RUN_TEST_$(1)_RULES += $$(run_test_rule_name)
+  ART_TEST_$$(uc_host_or_target)_RUN_TEST_$(1)$(4)_RULES += $$(run_test_rule_name)
   ART_TEST_$$(uc_host_or_target)_RUN_TEST_ALL_RULES += $$(run_test_rule_name)
   ART_TEST_$$(uc_host_or_target)_RUN_TEST_$$(uc_reloc_type)_RULES += $$(run_test_rule_name)
   ART_TEST_$$(uc_host_or_target)_RUN_TEST_ALL$(4)_RULES += $$(run_test_rule_name)
@@ -464,10 +478,6 @@
     endif
   endif
 
-  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_DEFAULT_$(1)_RULES :=
-  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_INTERPRETER_$(1)_RULES :=
-  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES :=
-  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES :=
   $$(eval $$(call define-test-art-run-test,$(1),$(2),default,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),,$(3)))
   $$(eval $$(call define-test-art-run-test,$(1),$(2),interpreter,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),,$(3)))
   $$(eval $$(call define-test-art-run-test,$(1),$(2),optimizing,$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX),,$(3)))
@@ -520,10 +530,24 @@
       $$(error found $(2) expected host or target)
     endif
   endif
+  do_second := false
+  ifeq ($(2),host)
+    ifneq ($$(HOST_PREFER_32_BIT),true)
+      do_second := true
+    endif
+  else
+    ifdef TARGET_2ND_ARCH
+      do_second := true
+    endif
+  endif
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_DEFAULT_$(1)_RULES :=
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_INTERPRETER_$(1)_RULES :=
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES :=
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)_RULES :=
+  ifeq ($$(do_second),true)
+    ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)_RULES :=
+  endif
   $$(eval $$(call define-test-art-run-test-group-type,$(1),$(2),prebuild))
   $$(eval $$(call define-test-art-run-test-group-type,$(1),$(2),norelocate))
   $$(eval $$(call define-test-art-run-test-group-type,$(1),$(2),relocate))
@@ -536,12 +560,22 @@
     $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES)))
   $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-$(1), \
     $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES)))
+  $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-$(1)$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX), \
+    $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)_RULES)))
+  ifeq ($$(do_second),true)
+    $$(eval $$(call define-test-art-run-test-group-rule,test-art-$(2)-run-test-$(1)$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX), \
+      $$(ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)_RULES)))
+  endif
 
   # Clear locally defined variables.
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_DEFAULT_$(1)_RULES :=
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_INTERPRETER_$(1)_RULES :=
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_OPTIMIZING_$(1)_RULES :=
   ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)_RULES :=
+  ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)$$(ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)_RULES :=
+  ifeq ($$(do_second),true)
+    ART_TEST_$$(group_uc_host_or_target)_RUN_TEST_$(1)$$(2ND_ART_PHONY_TEST_$$(group_uc_host_or_target)_SUFFIX)_RULES :=
+  endif
   group_uc_host_or_target :=
   do_second :=
 endef  # define-test-art-run-test-group
@@ -795,6 +829,9 @@
     $(ART_TEST_HOST_RUN_TEST_OPTIMIZING_RELOCATE$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES)))
 endif
 
+# include libarttest build rules.
+include $(LOCAL_PATH)/Android.libarttest.mk
+
 define-test-art-run-test :=
 define-test-art-run-test-group-rule :=
 define-test-art-run-test-group :=
diff --git a/test/etc/default-check b/test/etc/default-check
new file mode 100755
index 0000000..46a095c
--- /dev/null
+++ b/test/etc/default-check
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+diff --strip-trailing-cr -q "$1" "$2" >/dev/null
\ No newline at end of file
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index d69180b..d72e997 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -183,4 +183,4 @@
 fi
 
 cd $ANDROID_BUILD_TOP
-$mkdir_cmd && $prebuild_cmd && $cmdline "$@"
+$mkdir_cmd && $prebuild_cmd && LD_PRELOAD=libsigchain.so $cmdline "$@"
diff --git a/test/run-test b/test/run-test
index 5bfa687..1ed03ea 100755
--- a/test/run-test
+++ b/test/run-test
@@ -56,6 +56,7 @@
 build="build"
 run="run"
 expected="expected.txt"
+check_cmd="check"
 output="output.txt"
 build_output="build-output.txt"
 lib="libartd.so"
@@ -71,6 +72,7 @@
 usage="no"
 build_only="no"
 suffix64=""
+trace="false"
 
 while true; do
     if [ "x$1" = "x--host" ]; then
@@ -175,7 +177,7 @@
         suffix64="64"
         shift
     elif [ "x$1" = "x--trace" ]; then
-        run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file:${DEX_LOCATION}/trace.bin --runtime-option -Xmethod-trace-file-size:2000000"
+        trace="true"
         shift
     elif expr "x$1" : "x--" >/dev/null 2>&1; then
         echo "unknown $0 option: $1" 1>&2
@@ -187,6 +189,22 @@
 done
 mkdir -p $tmp_dir
 
+if [ "$trace" = "true" ]; then
+    run_args="${run_args} --runtime-option -Xmethod-trace --runtime-option -Xmethod-trace-file:${DEX_LOCATION}/trace.bin --runtime-option -Xmethod-trace-file-size:2000000"
+fi
+
+# Most interesting target architecture variables are Makefile variables, not environment variables.
+# Try to map the suffix64 flag and what we find in ${OUT}/data/art-test to an architecture name.
+function guess_arch_name() {
+    grep32bit=`ls ${OUT}/data/art-test | grep -E '^(arm|x86|mips)$'`
+    grep64bit=`ls ${OUT}/data/art-test | grep -E '^(arm64|x86_64)$'`
+    if [ "x${suffix64}" = "x64" ]; then
+        target_arch_name=${grep64bit}
+    else
+        target_arch_name=${grep32bit}
+    fi
+}
+
 if [ "$target_mode" = "no" ]; then
     if [ "$runtime" = "jvm" ]; then
         RUN="${progdir}/etc/reference-run-test-classes"
@@ -228,7 +246,10 @@
 	    export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
         fi
         run_args="${run_args} --boot -Ximage:${ANDROID_HOST_OUT}/framework/core.art"
+        run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}"
     else
+        guess_arch_name
+        run_args="${run_args} --runtime-option -Djava.library.path=/data/art-test/${target_arch_name}"
         run_args="${run_args} --boot -Ximage:/data/art-test/core.art"
     fi
     if [ "$relocate" = "yes" ]; then
@@ -340,8 +361,13 @@
     cp "${progdir}/etc/default-run" run
 fi
 
+if [ '!' -r "$check_cmd" ]; then
+    cp "${progdir}/etc/default-check" check
+fi
+
 chmod 755 "$build"
 chmod 755 "$run"
+chmod 755 "$check_cmd"
 
 export TEST_NAME=`basename ${test_dir}`
 
@@ -408,7 +434,7 @@
         cp "$build_output" "$output"
         echo "build exit status: $build_exit" >>"$output"
     fi
-    diff --strip-trailing-cr -q "$expected" "$output" >/dev/null
+    ./$check_cmd "$expected" "$output"
     if [ "$?" = "0" ]; then
         # output == expected
         good="yes"