Merge "Initialize pDeoptimize quick entry pointer for Mips."
diff --git a/Android.mk b/Android.mk
index a050c58..c01464a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,6 +79,7 @@
 include $(art_path)/runtime/Android.mk
 include $(art_path)/compiler/Android.mk
 include $(art_path)/dexdump/Android.mk
+include $(art_path)/dexlist/Android.mk
 include $(art_path)/dex2oat/Android.mk
 include $(art_path)/disassembler/Android.mk
 include $(art_path)/oatdump/Android.mk
@@ -237,10 +238,10 @@
 	$(hide) $(call ART_TEST_PREREQ_FINISHED,$@)
 endif
 
-# Dexdump regression test.
+# Dexdump/list regression test.
 .PHONY: test-art-host-dexdump
-test-art-host-dexdump: dexdump2
-	art/test/dexdump/run-all-tests
+test-art-host-dexdump: $(addprefix $(HOST_OUT_EXECUTABLES)/, dexdump2 dexlist2)
+	ANDROID_HOST_OUT=$(realpath $(HOST_OUT)) art/test/dexdump/run-all-tests
 
 # Valgrind. Currently only 32b gtests.
 .PHONY: valgrind-test-art-host
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 77f39c4..ee0cb09 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -40,7 +40,7 @@
   ART_BUILD_HOST_STATIC := false
 endif
 
-ifneq ($$(HOST_OS),linux)
+ifneq ($(HOST_OS),linux)
   ART_BUILD_HOST_STATIC := false
 endif
 
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 183f4e3..a561c5f 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -88,4 +88,8 @@
 
 HOST_CORE_DEX_FILES   := $(foreach jar,$(HOST_CORE_JARS),  $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
 TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
+
+# Classpath for Jack compilation: we only need core-libart.
+HOST_JACK_CLASSPATH   := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart-hostdex,t,COMMON)/classes.jack)
+TARGET_JACK_CLASSPATH := $(abspath $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart, ,COMMON)/classes.jack)
 endif # ART_ANDROID_COMMON_PATH_MK
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 273ae0e..0958c64 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -104,6 +104,17 @@
   $(TARGET_CORE_IMAGE_default_no-pic_32) \
   dexdump2
 
+# The dexlist test requires an image and the dexlist utility.
+# TODO: rename into dexlist when migration completes
+ART_GTEST_dexlist_test_HOST_DEPS := \
+  $(HOST_CORE_IMAGE_default_no-pic_64) \
+  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_OUT_EXECUTABLES)/dexlist2
+ART_GTEST_dexlist_test_TARGET_DEPS := \
+  $(TARGET_CORE_IMAGE_default_no-pic_64) \
+  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  dexlist2
+
 # The imgdiag test has dependencies on core.oat since it needs to load it during the test.
 # For the host, also add the installed tool (in the base size, that should suffice). For the
 # target, just the module is fine, the sync will happen late enough.
@@ -132,6 +143,7 @@
 RUNTIME_GTEST_COMMON_SRC_FILES := \
   cmdline/cmdline_parser_test.cc \
   dexdump/dexdump_test.cc \
+  dexlist/dexlist_test.cc \
   imgdiag/imgdiag_test.cc \
   oatdump/oatdump_test.cc \
   runtime/arch/arch_test.cc \
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index d993d93..d1fe167 100755
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -1336,9 +1336,24 @@
     }
     OpRegReg(kOpRev, rl_result.reg.GetLow(), rl_i.reg.GetHigh());
     OpRegReg(kOpRev, rl_result.reg.GetHigh(), r_i_low);
+    // Free up at least one input register if it was a temp. Otherwise we may be in the bad
+    // situation of not having a temp available for SwapBits. Make sure it's not overlapping
+    // with the output, though.
     if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) {
+      // There's definitely a free temp after this.
       FreeTemp(r_i_low);
+    } else {
+      // We opportunistically release both here. That saves duplication of the register state
+      // lookup (to see if it's actually a temp).
+      if (rl_i.reg.GetLowReg() != rl_result.reg.GetHighReg()) {
+        FreeTemp(rl_i.reg.GetLow());
+      }
+      if (rl_i.reg.GetHighReg() != rl_result.reg.GetLowReg() &&
+          rl_i.reg.GetHighReg() != rl_result.reg.GetHighReg()) {
+        FreeTemp(rl_i.reg.GetHigh());
+      }
     }
+
     SwapBits(rl_result.reg.GetLow(), 1, 0x55555555);
     SwapBits(rl_result.reg.GetLow(), 2, 0x33333333);
     SwapBits(rl_result.reg.GetLow(), 4, 0x0f0f0f0f);
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 73e121f..fdfeb48 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -989,6 +989,8 @@
   CHECK_EQ(image_objects_offset_begin_ + bin_slot_previous_sizes_[kBinArtMethodClean],
            methods_section->Offset());
   cur_pos = methods_section->End();
+  // Round up to the alignment the string table expects. See HashSet::WriteToMemory.
+  cur_pos = RoundUp(cur_pos, sizeof(uint64_t));
   // Calculate the size of the interned strings.
   auto* interned_strings_section = &sections[ImageHeader::kSectionInternedStrings];
   *interned_strings_section = ImageSection(cur_pos, intern_table_bytes_);
@@ -1417,9 +1419,6 @@
     if (UNLIKELY(orig->IsAbstract())) {
       copy->SetEntryPointFromQuickCompiledCodePtrSize(
           GetOatAddress(quick_to_interpreter_bridge_offset_), target_ptr_size_);
-      copy->SetEntryPointFromInterpreterPtrSize(
-          reinterpret_cast<EntryPointFromInterpreter*>(const_cast<uint8_t*>(
-                  GetOatAddress(interpreter_to_interpreter_bridge_offset_))), target_ptr_size_);
     } else {
       bool quick_is_interpreted;
       const uint8_t* quick_code = GetQuickCode(orig, &quick_is_interpreted);
@@ -1432,16 +1431,6 @@
         copy->SetEntryPointFromJniPtrSize(
             GetOatAddress(jni_dlsym_lookup_offset_), target_ptr_size_);
       }
-
-      // Interpreter entrypoint:
-      // Set the interpreter entrypoint depending on whether there is compiled code or not.
-      uint32_t interpreter_code = (quick_is_interpreted)
-          ? interpreter_to_interpreter_bridge_offset_
-          : interpreter_to_compiled_code_bridge_offset_;
-      EntryPointFromInterpreter* interpreter_entrypoint =
-          reinterpret_cast<EntryPointFromInterpreter*>(
-              const_cast<uint8_t*>(GetOatAddress(interpreter_code)));
-      copy->SetEntryPointFromInterpreterPtrSize(interpreter_entrypoint, target_ptr_size_);
     }
   }
 }
diff --git a/compiler/optimizing/boolean_simplifier.cc b/compiler/optimizing/boolean_simplifier.cc
index daf7d67..329112a 100644
--- a/compiler/optimizing/boolean_simplifier.cc
+++ b/compiler/optimizing/boolean_simplifier.cc
@@ -119,6 +119,14 @@
   // Check if the selection negates/preserves the value of the condition and
   // if so, generate a suitable replacement instruction.
   HInstruction* if_condition = if_instruction->InputAt(0);
+
+  // Don't change FP compares.  The definition of compares involving NaNs forces
+  // the compares to be done as written by the user.
+  if (if_condition->IsCondition() &&
+      Primitive::IsFloatingPointType(if_condition->InputAt(0)->GetType())) {
+    return;
+  }
+
   HInstruction* replacement;
   if (NegatesCondition(true_value, false_value)) {
     replacement = GetOppositeCondition(if_condition);
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 732630d..fe52c44 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -259,14 +259,20 @@
   return false;
 }
 
-bool HGraphBuilder::IsBlockInPcRange(HBasicBlock* block,
-                                     uint32_t dex_pc_start,
-                                     uint32_t dex_pc_end) {
-  uint32_t dex_pc = block->GetDexPc();
-  return block != entry_block_
-      && block != exit_block_
-      && dex_pc >= dex_pc_start
-      && dex_pc < dex_pc_end;
+static const DexFile::TryItem* GetTryItem(HBasicBlock* block,
+                                          const DexFile::CodeItem& code_item,
+                                          const ArenaBitVector& can_block_throw) {
+  DCHECK(!block->IsSingleTryBoundary());
+
+  // Block does not contain throwing instructions. Even if it is covered by
+  // a TryItem, we will consider it not in a try block.
+  if (!can_block_throw.IsBitSet(block->GetBlockId())) {
+    return nullptr;
+  }
+
+  // Instructions in the block may throw. Find a TryItem covering this block.
+  int32_t try_item_idx = DexFile::FindTryItem(code_item, block->GetDexPc());
+  return (try_item_idx == -1) ? nullptr : DexFile::GetTryItems(code_item, try_item_idx);
 }
 
 void HGraphBuilder::CreateBlocksForTryCatch(const DexFile::CodeItem& code_item) {
@@ -327,80 +333,90 @@
     return;
   }
 
+  // Bit vector stores information on which blocks contain throwing instructions.
+  // Must be expandable because catch blocks may be split into two.
+  ArenaBitVector can_block_throw(arena_, graph_->GetBlocks().Size(), /* expandable */ true);
+
+  // Scan blocks and mark those which contain throwing instructions.
+  for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) {
+    HBasicBlock* block = graph_->GetBlocks().Get(block_id);
+    bool can_throw = false;
+    for (HInstructionIterator insn(block->GetInstructions()); !insn.Done(); insn.Advance()) {
+      if (insn.Current()->CanThrow()) {
+        can_throw = true;
+        break;
+      }
+    }
+
+    if (can_throw) {
+      if (block->IsCatchBlock()) {
+        // Catch blocks are always considered an entry point into the TryItem in
+        // order to avoid splitting exceptional edges. We split the block after
+        // the move-exception (if present) and mark the first part non-throwing.
+        // Later on, a TryBoundary will be inserted between the two blocks.
+        HInstruction* first_insn = block->GetFirstInstruction();
+        if (first_insn->IsLoadException()) {
+          // Catch block starts with a LoadException. Split the block after the
+          // StoreLocal that must come after the load.
+          DCHECK(first_insn->GetNext()->IsStoreLocal());
+          block = block->SplitBefore(first_insn->GetNext()->GetNext());
+        } else {
+          // Catch block does not load the exception. Split at the beginning to
+          // create an empty catch block.
+          block = block->SplitBefore(first_insn);
+        }
+      }
+      can_block_throw.SetBit(block->GetBlockId());
+    }
+  }
+
   // Iterate over all blocks, find those covered by some TryItem and:
   //   (a) split edges which enter/exit the try range,
   //   (b) create TryBoundary instructions in the new blocks,
   //   (c) link the new blocks to corresponding exception handlers.
   // We cannot iterate only over blocks in `branch_targets_` because switch-case
   // blocks share the same dex_pc.
-  for (size_t block_id = 1, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) {
+  for (size_t block_id = 0, e = graph_->GetBlocks().Size(); block_id < e; ++block_id) {
     HBasicBlock* try_block = graph_->GetBlocks().Get(block_id);
 
-    // Iteration starts from 1 to skip the entry block.
-    DCHECK_NE(try_block, entry_block_);
-    // Exit block has not yet been added to the graph at this point.
-    DCHECK_NE(try_block, exit_block_);
     // TryBoundary blocks are added at the end of the list and not iterated over.
     DCHECK(!try_block->IsSingleTryBoundary());
 
     // Find the TryItem for this block.
-    int32_t try_item_idx = DexFile::FindTryItem(code_item, try_block->GetDexPc());
-    if (try_item_idx == -1) {
+    const DexFile::TryItem* try_item = GetTryItem(try_block, code_item, can_block_throw);
+    if (try_item == nullptr) {
       continue;
     }
-    const DexFile::TryItem& try_item = *DexFile::GetTryItems(code_item, try_item_idx);
-    uint32_t try_start = try_item.start_addr_;
-    uint32_t try_end = try_start + try_item.insn_count_;
 
-    if (try_block->IsCatchBlock()) {
-      // Catch blocks are always considered an entry point into the TryItem in
-      // order to avoid splitting exceptional edges (they might not have been
-      // created yet). We separate the move-exception (if present) from the
-      // rest of the block and insert a TryBoundary after it, creating a
-      // landing pad for the exceptional edges.
-      HInstruction* first_insn = try_block->GetFirstInstruction();
-      HInstruction* split_position = nullptr;
-      if (first_insn->IsLoadException()) {
-        // Catch block starts with a LoadException. Split the block after the
-        // StoreLocal that must come after the load.
-        DCHECK(first_insn->GetNext()->IsStoreLocal());
-        split_position = first_insn->GetNext()->GetNext();
-      } else {
-        // Catch block does not obtain the exception. Split at the beginning
-        // to create an empty catch block.
-        split_position = first_insn;
-      }
-      DCHECK(split_position != nullptr);
-      HBasicBlock* catch_block = try_block;
-      try_block = catch_block->SplitBefore(split_position);
-      SplitTryBoundaryEdge(catch_block, try_block, HTryBoundary::kEntry, code_item, try_item);
-    } else {
-      // For non-catch blocks, find predecessors which are not covered by the
-      // same TryItem range. Such edges enter the try block and will have
-      // a TryBoundary inserted.
-      for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) {
-        HBasicBlock* predecessor = try_block->GetPredecessors().Get(i);
-        if (predecessor->IsSingleTryBoundary()) {
-          // The edge was already split because of an exit from a neighbouring
-          // TryItem. We split it again and insert an entry point.
-          if (kIsDebugBuild) {
-            HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary();
-            DCHECK(!last_insn->IsEntry());
-            DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block);
-            DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i));
-            DCHECK(!IsBlockInPcRange(predecessor->GetSinglePredecessor(), try_start, try_end));
-          }
-        } else if (!IsBlockInPcRange(predecessor, try_start, try_end)) {
-          // This is an entry point into the TryItem and the edge has not been
-          // split yet. That means that `predecessor` is not in a TryItem, or
-          // it is in a different TryItem and we happened to iterate over this
-          // block first. We split the edge and insert an entry point.
-        } else {
-          // Not an edge on the boundary of the try block.
-          continue;
+    // Catch blocks were split earlier and cannot throw.
+    DCHECK(!try_block->IsCatchBlock());
+
+    // Find predecessors which are not covered by the same TryItem range. Such
+    // edges enter the try block and will have a TryBoundary inserted.
+    for (size_t i = 0; i < try_block->GetPredecessors().Size(); ++i) {
+      HBasicBlock* predecessor = try_block->GetPredecessors().Get(i);
+      if (predecessor->IsSingleTryBoundary()) {
+        // The edge was already split because of an exit from a neighbouring
+        // TryItem. We split it again and insert an entry point.
+        if (kIsDebugBuild) {
+          HTryBoundary* last_insn = predecessor->GetLastInstruction()->AsTryBoundary();
+          const DexFile::TryItem* predecessor_try_item =
+              GetTryItem(predecessor->GetSinglePredecessor(), code_item, can_block_throw);
+          DCHECK(!last_insn->IsEntry());
+          DCHECK_EQ(last_insn->GetNormalFlowSuccessor(), try_block);
+          DCHECK(try_block->IsFirstIndexOfPredecessor(predecessor, i));
+          DCHECK_NE(try_item, predecessor_try_item);
         }
-        SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, try_item);
+      } else if (GetTryItem(predecessor, code_item, can_block_throw) != try_item) {
+        // This is an entry point into the TryItem and the edge has not been
+        // split yet. That means that `predecessor` is not in a TryItem, or
+        // it is in a different TryItem and we happened to iterate over this
+        // block first. We split the edge and insert an entry point.
+      } else {
+        // Not an edge on the boundary of the try block.
+        continue;
       }
+      SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, *try_item);
     }
 
     // Find successors which are not covered by the same TryItem range. Such
@@ -416,11 +432,13 @@
         // TryItem. We split it again and insert an exit.
         if (kIsDebugBuild) {
           HTryBoundary* last_insn = successor->GetLastInstruction()->AsTryBoundary();
+          const DexFile::TryItem* successor_try_item =
+              GetTryItem(last_insn->GetNormalFlowSuccessor(), code_item, can_block_throw);
           DCHECK_EQ(try_block, successor->GetSinglePredecessor());
           DCHECK(last_insn->IsEntry());
-          DCHECK(!IsBlockInPcRange(last_insn->GetNormalFlowSuccessor(), try_start, try_end));
+          DCHECK_NE(try_item, successor_try_item);
         }
-      } else if (!IsBlockInPcRange(successor, try_start, try_end)) {
+      } else if (GetTryItem(successor, code_item, can_block_throw) != try_item) {
         // This is an exit out of the TryItem and the edge has not been split
         // yet. That means that either `successor` is not in a TryItem, or it
         // is in a different TryItem and we happened to iterate over this
@@ -437,7 +455,7 @@
         // Not an edge on the boundary of the try block.
         continue;
       }
-      SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, try_item);
+      SplitTryBoundaryEdge(try_block, successor, HTryBoundary::kExit, code_item, *try_item);
     }
   }
 }
@@ -496,14 +514,14 @@
   // Add the suspend check to the entry block.
   entry_block_->AddInstruction(new (arena_) HSuspendCheck(0));
   entry_block_->AddInstruction(new (arena_) HGoto());
+  // Add the exit block at the end.
+  graph_->AddBlock(exit_block_);
 
   // Iterate over blocks covered by TryItems and insert TryBoundaries at entry
   // and exit points. This requires all control-flow instructions and
   // non-exceptional edges to have been created.
   InsertTryBoundaryBlocks(code_item);
 
-  // Add the exit block at the end to give it the highest id.
-  graph_->AddBlock(exit_block_);
   return true;
 }
 
@@ -657,7 +675,7 @@
 
 void HGraphBuilder::Binop_23x_cmp(const Instruction& instruction,
                                   Primitive::Type type,
-                                  HCompare::Bias bias,
+                                  ComparisonBias bias,
                                   uint32_t dex_pc) {
   HInstruction* first = LoadLocal(instruction.VRegB(), type);
   HInstruction* second = LoadLocal(instruction.VRegC(), type);
@@ -2311,27 +2329,27 @@
     }
 
     case Instruction::CMP_LONG: {
-      Binop_23x_cmp(instruction, Primitive::kPrimLong, HCompare::kNoBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimLong, kNoBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPG_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kGtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, kGtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_FLOAT: {
-      Binop_23x_cmp(instruction, Primitive::kPrimFloat, HCompare::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimFloat, kLtBias, dex_pc);
       break;
     }
 
     case Instruction::CMPL_DOUBLE: {
-      Binop_23x_cmp(instruction, Primitive::kPrimDouble, HCompare::kLtBias, dex_pc);
+      Binop_23x_cmp(instruction, Primitive::kPrimDouble, kLtBias, dex_pc);
       break;
     }
 
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index cae762b..7098eb8 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -98,9 +98,6 @@
   HBasicBlock* FindBlockStartingAt(int32_t dex_pc) const;
   HBasicBlock* FindOrCreateBlockStartingAt(int32_t dex_pc);
 
-  // Returns whether the dex_pc of `block` lies within the given range.
-  bool IsBlockInPcRange(HBasicBlock* block, uint32_t dex_pc_start, uint32_t dex_pc_end);
-
   // Adds new blocks to `branch_targets_` starting at the limits of TryItems and
   // their exception handlers.
   void CreateBlocksForTryCatch(const DexFile::CodeItem& code_item);
@@ -139,7 +136,7 @@
 
   void Binop_23x_cmp(const Instruction& instruction,
                      Primitive::Type type,
-                     HCompare::Bias bias,
+                     ComparisonBias bias,
                      uint32_t dex_pc);
 
   template<typename T>
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 262b234..be71443 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -889,6 +889,180 @@
   UNUSED(exit);
 }
 
+void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
+                                                  Label* true_label,
+                                                  Label* false_label) {
+  bool gt_bias = cond->IsGtBias();
+  IfCondition if_cond = cond->GetCondition();
+  Condition ccode = X86Condition(if_cond);
+  switch (if_cond) {
+    case kCondEQ:
+      if (!gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      break;
+    case kCondNE:
+      if (!gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      break;
+    case kCondLT:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelow;
+      break;
+    case kCondLE:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelowEqual;
+      break;
+    case kCondGT:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAbove;
+      break;
+    case kCondGE:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAboveEqual;
+      break;
+  }
+  __ j(ccode, true_label);
+}
+
+void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
+                                                               Label* true_label,
+                                                               Label* false_label) {
+  LocationSummary* locations = cond->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+  IfCondition if_cond = cond->GetCondition();
+
+  Register left_low = left.AsRegisterPairLow<Register>();
+  Register left_high = left.AsRegisterPairHigh<Register>();
+  IfCondition true_high_cond = if_cond;
+  IfCondition false_high_cond = cond->GetOppositeCondition();
+  Condition final_condition = X86Condition(if_cond);
+
+  // Set the conditions for the test, remembering that == needs to be
+  // decided using the low words.
+  switch (if_cond) {
+    case kCondEQ:
+      false_high_cond = kCondNE;
+      break;
+    case kCondNE:
+      false_high_cond = kCondEQ;
+      break;
+    case kCondLT:
+      false_high_cond = kCondGT;
+      final_condition = kBelow;
+      break;
+    case kCondLE:
+      true_high_cond = kCondLT;
+      final_condition = kBelowEqual;
+      break;
+    case kCondGT:
+      false_high_cond = kCondLT;
+      final_condition = kAbove;
+      break;
+    case kCondGE:
+      true_high_cond = kCondGT;
+      final_condition = kAboveEqual;
+      break;
+  }
+
+  if (right.IsConstant()) {
+    int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
+    int32_t val_low = Low32Bits(value);
+    int32_t val_high = High32Bits(value);
+
+    if (val_high == 0) {
+      __ testl(left_high, left_high);
+    } else {
+      __ cmpl(left_high, Immediate(val_high));
+    }
+    if (if_cond == kCondNE) {
+      __ j(X86Condition(true_high_cond), true_label);
+    } else if (if_cond == kCondEQ) {
+      __ j(X86Condition(false_high_cond), false_label);
+    } else {
+      __ j(X86Condition(true_high_cond), true_label);
+      __ j(X86Condition(false_high_cond), false_label);
+    }
+    // Must be equal high, so compare the lows.
+    if (val_low == 0) {
+      __ testl(left_low, left_low);
+    } else {
+      __ cmpl(left_low, Immediate(val_low));
+    }
+  } else {
+    Register right_low = right.AsRegisterPairLow<Register>();
+    Register right_high = right.AsRegisterPairHigh<Register>();
+
+    __ cmpl(left_high, right_high);
+    if (if_cond == kCondNE) {
+      __ j(X86Condition(true_high_cond), true_label);
+    } else if (if_cond == kCondEQ) {
+      __ j(X86Condition(false_high_cond), false_label);
+    } else {
+      __ j(X86Condition(true_high_cond), true_label);
+      __ j(X86Condition(false_high_cond), false_label);
+    }
+    // Must be equal high, so compare the lows.
+    __ cmpl(left_low, right_low);
+  }
+  // The last comparison might be unsigned.
+  __ j(final_condition, true_label);
+}
+
+void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr,
+                                                               HCondition* condition,
+                                                               Label* true_target,
+                                                               Label* false_target,
+                                                               Label* always_true_target) {
+  LocationSummary* locations = condition->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  // We don't want true_target as a nullptr.
+  if (true_target == nullptr) {
+    true_target = always_true_target;
+  }
+  bool falls_through = (false_target == nullptr);
+
+  // FP compares don't like null false_targets.
+  if (false_target == nullptr) {
+    false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
+  }
+
+  Primitive::Type type = condition->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong:
+      GenerateLongComparesAndJumps(condition, true_target, false_target);
+      break;
+    case Primitive::kPrimFloat:
+      DCHECK(right.IsFpuRegister());
+      __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    case Primitive::kPrimDouble:
+      DCHECK(right.IsFpuRegister());
+      __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    default:
+      LOG(FATAL) << "Unexpected compare type " << type;
+  }
+
+  if (!falls_through) {
+    __ jmp(false_target);
+  }
+}
+
 void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
                                                         Label* true_target,
                                                         Label* false_target,
@@ -910,9 +1084,12 @@
         !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
     // Moves do not affect the eflags register, so if the condition is
     // evaluated just before the if, we don't need to evaluate it
-    // again.
+    // again.  We can't use the eflags on long/FP conditions if they are
+    // materialized due to the complex branching.
+    Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
     bool eflags_set = cond->IsCondition()
-        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
+        && type == Primitive::kPrimInt;
     if (materialized) {
       if (!eflags_set) {
         // Materialized condition, compare against 0.
@@ -927,6 +1104,16 @@
         __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
       }
     } else {
+      // Is this a long or FP comparison that has been folded into the HCondition?
+      if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+        // Generate the comparison directly.
+        GenerateCompareTestAndBranch(instruction->AsIf(),
+                                     cond->AsCondition(),
+                                     true_target,
+                                     false_target,
+                                     always_true_target);
+        return;
+      }
       Location lhs = cond->GetLocations()->InAt(0);
       Location rhs = cond->GetLocations()->InAt(1);
       // LHS is guaranteed to be in a register (see
@@ -1041,36 +1228,94 @@
 void LocationsBuilderX86::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
-  if (cond->NeedsMaterialization()) {
-    // We need a byte register.
-    locations->SetOut(Location::RegisterLocation(ECX));
+  // Handle the long/FP comparisons made in instruction simplification.
+  switch (cond->InputAt(0)->GetType()) {
+    case Primitive::kPrimLong: {
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
+      if (cond->NeedsMaterialization()) {
+        locations->SetOut(Location::RequiresRegister());
+      }
+      break;
+    }
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble: {
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      if (cond->NeedsMaterialization()) {
+        locations->SetOut(Location::RequiresRegister());
+      }
+      break;
+    }
+    default:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      if (cond->NeedsMaterialization()) {
+        // We need a byte register.
+        locations->SetOut(Location::RegisterLocation(ECX));
+      }
+      break;
   }
 }
 
 void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
-  if (cond->NeedsMaterialization()) {
-    LocationSummary* locations = cond->GetLocations();
-    Register reg = locations->Out().AsRegister<Register>();
-    // Clear register: setcc only sets the low byte.
-    __ xorl(reg, reg);
-    Location lhs = locations->InAt(0);
-    Location rhs = locations->InAt(1);
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
-    } else if (rhs.IsConstant()) {
-      int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
-      if (constant == 0) {
-        __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
-      } else {
-      __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
-      }
-    } else {
-      __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
-    }
-    __ setb(X86Condition(cond->GetCondition()), reg);
+  if (!cond->NeedsMaterialization()) {
+    return;
   }
+
+  LocationSummary* locations = cond->GetLocations();
+  Location lhs = locations->InAt(0);
+  Location rhs = locations->InAt(1);
+  Register reg = locations->Out().AsRegister<Register>();
+  Label true_label, false_label;
+
+  switch (cond->InputAt(0)->GetType()) {
+    default: {
+      // Integer case.
+
+      // Clear output register: setcc only sets the low byte.
+      __ xorl(reg, reg);
+
+      if (rhs.IsRegister()) {
+        __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
+      } else if (rhs.IsConstant()) {
+        int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
+        if (constant == 0) {
+          __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
+        } else {
+          __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
+        }
+      } else {
+        __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
+      }
+      __ setb(X86Condition(cond->GetCondition()), reg);
+      return;
+    }
+    case Primitive::kPrimLong:
+      GenerateLongComparesAndJumps(cond, &true_label, &false_label);
+      break;
+    case Primitive::kPrimFloat:
+      __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+    case Primitive::kPrimDouble:
+      __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+  }
+
+  // Convert the jumps into the result.
+  Label done_label;
+
+  // false case: result = 0;
+  __ Bind(&false_label);
+  __ xorl(reg, reg);
+  __ jmp(&done_label);
+
+  // True case: result = 1
+  __ Bind(&true_label);
+  __ movl(reg, Immediate(1));
+  __ Bind(&done_label);
 }
 
 void LocationsBuilderX86::VisitEqual(HEqual* comp) {
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 623e832..65d6e0a 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -177,7 +177,7 @@
   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
   void DivByPowerOfTwo(HDiv* instruction);
   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
-  void GenerateRemFP(HRem *rem);
+  void GenerateRemFP(HRem* rem);
   void HandleShift(HBinaryOperation* instruction);
   void GenerateShlLong(const Location& loc, Register shifter);
   void GenerateShrLong(const Location& loc, Register shifter);
@@ -201,6 +201,13 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void GenerateCompareTestAndBranch(HIf* if_inst,
+                                    HCondition* condition,
+                                    Label* true_target,
+                                    Label* false_target,
+                                    Label* always_true_target);
+  void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label);
+  void GenerateLongComparesAndJumps(HCondition* cond, Label* true_label, Label* false_label);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   X86Assembler* const assembler_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index c9d19c8..ddaa60d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -833,6 +833,134 @@
   UNUSED(exit);
 }
 
+void InstructionCodeGeneratorX86_64::GenerateFPJumps(HCondition* cond,
+                                                     Label* true_label,
+                                                     Label* false_label) {
+  bool gt_bias = cond->IsGtBias();
+  IfCondition if_cond = cond->GetCondition();
+  Condition ccode = X86_64Condition(if_cond);
+  switch (if_cond) {
+    case kCondEQ:
+      if (!gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      break;
+    case kCondNE:
+      if (!gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      break;
+    case kCondLT:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelow;
+      break;
+    case kCondLE:
+      if (gt_bias) {
+        __ j(kParityEven, false_label);
+      }
+      ccode = kBelowEqual;
+      break;
+    case kCondGT:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAbove;
+      break;
+    case kCondGE:
+      if (gt_bias) {
+        __ j(kParityEven, true_label);
+      }
+      ccode = kAboveEqual;
+      break;
+  }
+  __ j(ccode, true_label);
+}
+
+void InstructionCodeGeneratorX86_64::GenerateCompareTestAndBranch(HIf* if_instr,
+                                                                  HCondition* condition,
+                                                                  Label* true_target,
+                                                                  Label* false_target,
+                                                                  Label* always_true_target) {
+  LocationSummary* locations = condition->GetLocations();
+  Location left = locations->InAt(0);
+  Location right = locations->InAt(1);
+
+  // We don't want true_target as a nullptr.
+  if (true_target == nullptr) {
+    true_target = always_true_target;
+  }
+  bool falls_through = (false_target == nullptr);
+
+  // FP compares don't like null false_targets.
+  if (false_target == nullptr) {
+    false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
+  }
+
+  Primitive::Type type = condition->InputAt(0)->GetType();
+  switch (type) {
+    case Primitive::kPrimLong: {
+      CpuRegister left_reg = left.AsRegister<CpuRegister>();
+      if (right.IsConstant()) {
+        int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
+        if (IsInt<32>(value)) {
+          if (value == 0) {
+            __ testq(left_reg, left_reg);
+          } else {
+            __ cmpq(left_reg, Immediate(static_cast<int32_t>(value)));
+          }
+        } else {
+          // Value won't fit in an 32-bit integer.
+          __ cmpq(left_reg, codegen_->LiteralInt64Address(value));
+        }
+      } else if (right.IsDoubleStackSlot()) {
+        __ cmpq(left_reg, Address(CpuRegister(RSP), right.GetStackIndex()));
+      } else {
+        __ cmpq(left_reg, right.AsRegister<CpuRegister>());
+      }
+      __ j(X86_64Condition(condition->GetCondition()), true_target);
+      break;
+    }
+    case Primitive::kPrimFloat: {
+      if (right.IsFpuRegister()) {
+        __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      } else if (right.IsConstant()) {
+        __ ucomiss(left.AsFpuRegister<XmmRegister>(),
+                   codegen_->LiteralFloatAddress(
+                     right.GetConstant()->AsFloatConstant()->GetValue()));
+      } else {
+        DCHECK(right.IsStackSlot());
+        __ ucomiss(left.AsFpuRegister<XmmRegister>(),
+                   Address(CpuRegister(RSP), right.GetStackIndex()));
+      }
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    }
+    case Primitive::kPrimDouble: {
+      if (right.IsFpuRegister()) {
+        __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
+      } else if (right.IsConstant()) {
+        __ ucomisd(left.AsFpuRegister<XmmRegister>(),
+                   codegen_->LiteralDoubleAddress(
+                     right.GetConstant()->AsDoubleConstant()->GetValue()));
+      } else {
+        DCHECK(right.IsDoubleStackSlot());
+        __ ucomisd(left.AsFpuRegister<XmmRegister>(),
+                   Address(CpuRegister(RSP), right.GetStackIndex()));
+      }
+      GenerateFPJumps(condition, true_target, false_target);
+      break;
+    }
+    default:
+      LOG(FATAL) << "Unexpected condition type " << type;
+  }
+
+  if (!falls_through) {
+    __ jmp(false_target);
+  }
+}
+
 void InstructionCodeGeneratorX86_64::GenerateTestAndBranch(HInstruction* instruction,
                                                            Label* true_target,
                                                            Label* false_target,
@@ -854,9 +982,13 @@
         !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
     // Moves do not affect the eflags register, so if the condition is
     // evaluated just before the if, we don't need to evaluate it
-    // again.
+    // again.  We can't use the eflags on FP conditions if they are
+    // materialized due to the complex branching.
+    Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
     bool eflags_set = cond->IsCondition()
-        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
+        && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
+        && !Primitive::IsFloatingPointType(type);
+
     if (materialized) {
       if (!eflags_set) {
         // Materialized condition, compare against 0.
@@ -872,6 +1004,13 @@
         __ j(X86_64Condition(cond->AsCondition()->GetCondition()), true_target);
       }
     } else {
+      // Is this a long or FP comparison that has been folded into the HCondition?
+      if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
+        // Generate the comparison directly
+        GenerateCompareTestAndBranch(instruction->AsIf(), cond->AsCondition(),
+                                     true_target, false_target, always_true_target);
+        return;
+      }
       Location lhs = cond->GetLocations()->InAt(0);
       Location rhs = cond->GetLocations()->InAt(1);
       if (rhs.IsRegister()) {
@@ -985,35 +1124,122 @@
 void LocationsBuilderX86_64::VisitCondition(HCondition* cond) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
-  locations->SetInAt(0, Location::RequiresRegister());
-  locations->SetInAt(1, Location::Any());
+  // Handle the long/FP comparisons made in instruction simplification.
+  switch (cond->InputAt(0)->GetType()) {
+    case Primitive::kPrimLong:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      break;
+    case Primitive::kPrimFloat:
+    case Primitive::kPrimDouble:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::Any());
+      break;
+    default:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::Any());
+      break;
+  }
   if (cond->NeedsMaterialization()) {
     locations->SetOut(Location::RequiresRegister());
   }
 }
 
 void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* cond) {
-  if (cond->NeedsMaterialization()) {
-    LocationSummary* locations = cond->GetLocations();
-    CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
-    // Clear register: setcc only sets the low byte.
-    __ xorl(reg, reg);
-    Location lhs = locations->InAt(0);
-    Location rhs = locations->InAt(1);
-    if (rhs.IsRegister()) {
-      __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
-    } else if (rhs.IsConstant()) {
-      int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
-      if (constant == 0) {
-        __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
-      } else {
-        __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
-      }
-    } else {
-      __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
-    }
-    __ setcc(X86_64Condition(cond->GetCondition()), reg);
+  if (!cond->NeedsMaterialization()) {
+    return;
   }
+
+  LocationSummary* locations = cond->GetLocations();
+  Location lhs = locations->InAt(0);
+  Location rhs = locations->InAt(1);
+  CpuRegister reg = locations->Out().AsRegister<CpuRegister>();
+  Label true_label, false_label;
+
+  switch (cond->InputAt(0)->GetType()) {
+    default:
+      // Integer case.
+
+      // Clear output register: setcc only sets the low byte.
+      __ xorl(reg, reg);
+
+      if (rhs.IsRegister()) {
+        __ cmpl(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
+      } else if (rhs.IsConstant()) {
+        int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
+        if (constant == 0) {
+          __ testl(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
+        } else {
+          __ cmpl(lhs.AsRegister<CpuRegister>(), Immediate(constant));
+        }
+      } else {
+        __ cmpl(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      }
+      __ setcc(X86_64Condition(cond->GetCondition()), reg);
+      return;
+    case Primitive::kPrimLong:
+      // Clear output register: setcc only sets the low byte.
+      __ xorl(reg, reg);
+
+      if (rhs.IsRegister()) {
+        __ cmpq(lhs.AsRegister<CpuRegister>(), rhs.AsRegister<CpuRegister>());
+      } else if (rhs.IsConstant()) {
+        int64_t value = rhs.GetConstant()->AsLongConstant()->GetValue();
+        if (IsInt<32>(value)) {
+          if (value == 0) {
+            __ testq(lhs.AsRegister<CpuRegister>(), lhs.AsRegister<CpuRegister>());
+          } else {
+            __ cmpq(lhs.AsRegister<CpuRegister>(), Immediate(static_cast<int32_t>(value)));
+          }
+        } else {
+          // Value won't fit in an int.
+          __ cmpq(lhs.AsRegister<CpuRegister>(), codegen_->LiteralInt64Address(value));
+        }
+      } else {
+        __ cmpq(lhs.AsRegister<CpuRegister>(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      }
+      __ setcc(X86_64Condition(cond->GetCondition()), reg);
+      return;
+    case Primitive::kPrimFloat: {
+      XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
+      if (rhs.IsConstant()) {
+        float value = rhs.GetConstant()->AsFloatConstant()->GetValue();
+        __ ucomiss(lhs_reg, codegen_->LiteralFloatAddress(value));
+      } else if (rhs.IsStackSlot()) {
+        __ ucomiss(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      } else {
+        __ ucomiss(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
+      }
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+    }
+    case Primitive::kPrimDouble: {
+      XmmRegister lhs_reg = lhs.AsFpuRegister<XmmRegister>();
+      if (rhs.IsConstant()) {
+        double value = rhs.GetConstant()->AsDoubleConstant()->GetValue();
+        __ ucomisd(lhs_reg, codegen_->LiteralDoubleAddress(value));
+      } else if (rhs.IsDoubleStackSlot()) {
+        __ ucomisd(lhs_reg, Address(CpuRegister(RSP), rhs.GetStackIndex()));
+      } else {
+        __ ucomisd(lhs_reg, rhs.AsFpuRegister<XmmRegister>());
+      }
+      GenerateFPJumps(cond, &true_label, &false_label);
+      break;
+    }
+  }
+
+  // Convert the jumps into the result.
+  Label done_label;
+
+  // false case: result = 0;
+  __ Bind(&false_label);
+  __ xorl(reg, reg);
+  __ jmp(&done_label);
+
+  // True case: result = 1
+  __ Bind(&true_label);
+  __ movl(reg, Immediate(1));
+  __ Bind(&done_label);
 }
 
 void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index c2aa56b..4b90381 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -183,7 +183,7 @@
   void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor);
   void GenerateClassInitializationCheck(SlowPathCodeX86_64* slow_path, CpuRegister class_reg);
   void HandleBitwiseOperation(HBinaryOperation* operation);
-  void GenerateRemFP(HRem *rem);
+  void GenerateRemFP(HRem* rem);
   void DivRemOneOrMinusOne(HBinaryOperation* instruction);
   void DivByPowerOfTwo(HDiv* instruction);
   void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction);
@@ -202,6 +202,12 @@
                              Label* true_target,
                              Label* false_target,
                              Label* always_true_target);
+  void GenerateCompareTestAndBranch(HIf* if_inst,
+                                    HCondition* condition,
+                                    Label* true_target,
+                                    Label* false_target,
+                                    Label* always_true_target);
+  void GenerateFPJumps(HCondition* cond, Label* true_label, Label* false_label);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
   X86_64Assembler* const assembler_;
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 504c141..37c060c 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -357,6 +357,10 @@
     StartAttributeStream("kind") << barrier->GetBarrierKind();
   }
 
+  void VisitMonitorOperation(HMonitorOperation* monitor) OVERRIDE {
+    StartAttributeStream("kind") << (monitor->IsEnter() ? "enter" : "exit");
+  }
+
   void VisitLoadClass(HLoadClass* load_class) OVERRIDE {
     StartAttributeStream("gen_clinit_check") << std::boolalpha
         << load_class->MustGenerateClinitCheck() << std::noboolalpha;
diff --git a/compiler/optimizing/instruction_simplifier.cc b/compiler/optimizing/instruction_simplifier.cc
index 62f90c2..337cf5b 100644
--- a/compiler/optimizing/instruction_simplifier.cc
+++ b/compiler/optimizing/instruction_simplifier.cc
@@ -54,6 +54,11 @@
   void VisitCheckCast(HCheckCast* instruction) OVERRIDE;
   void VisitAdd(HAdd* instruction) OVERRIDE;
   void VisitAnd(HAnd* instruction) OVERRIDE;
+  void VisitCondition(HCondition* instruction) OVERRIDE;
+  void VisitGreaterThan(HGreaterThan* condition) OVERRIDE;
+  void VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) OVERRIDE;
+  void VisitLessThan(HLessThan* condition) OVERRIDE;
+  void VisitLessThanOrEqual(HLessThanOrEqual* condition) OVERRIDE;
   void VisitDiv(HDiv* instruction) OVERRIDE;
   void VisitMul(HMul* instruction) OVERRIDE;
   void VisitNeg(HNeg* instruction) OVERRIDE;
@@ -330,7 +335,11 @@
         block->RemoveInstruction(equal);
         RecordSimplification();
       }
+    } else {
+      VisitCondition(equal);
     }
+  } else {
+    VisitCondition(equal);
   }
 }
 
@@ -358,7 +367,11 @@
         block->RemoveInstruction(not_equal);
         RecordSimplification();
       }
+    } else {
+      VisitCondition(not_equal);
     }
+  } else {
+    VisitCondition(not_equal);
   }
 }
 
@@ -485,6 +498,76 @@
   }
 }
 
+void InstructionSimplifierVisitor::VisitGreaterThan(HGreaterThan* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitGreaterThanOrEqual(HGreaterThanOrEqual* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitLessThan(HLessThan* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitLessThanOrEqual(HLessThanOrEqual* condition) {
+  VisitCondition(condition);
+}
+
+void InstructionSimplifierVisitor::VisitCondition(HCondition* condition) {
+  // Try to fold an HCompare into this HCondition.
+
+  // This simplification is currently only supported on x86 and x86_64.
+  // TODO: Implement it for ARM, ARM64 and MIPS64.
+  InstructionSet instruction_set = GetGraph()->GetInstructionSet();
+  if (instruction_set != kX86 && instruction_set != kX86_64) {
+    return;
+  }
+
+  HInstruction* left = condition->GetLeft();
+  HInstruction* right = condition->GetRight();
+  // We can only replace an HCondition which compares a Compare to 0.
+  // Both 'dx' and 'jack' generate a compare to 0 when compiling a
+  // condition with a long, float or double comparison as input.
+  if (!left->IsCompare() || !right->IsConstant() || right->AsIntConstant()->GetValue() != 0) {
+    // Conversion is not possible.
+    return;
+  }
+
+  // Is the Compare only used for this purpose?
+  if (!left->GetUses().HasOnlyOneUse()) {
+    // Someone else also wants the result of the compare.
+    return;
+  }
+
+  if (!left->GetEnvUses().IsEmpty()) {
+    // There is a reference to the compare result in an environment. Do we really need it?
+    if (GetGraph()->IsDebuggable()) {
+      return;
+    }
+
+    // We have to ensure that there are no deopt points in the sequence.
+    if (left->HasAnyEnvironmentUseBefore(condition)) {
+      return;
+    }
+  }
+
+  // Clean up any environment uses from the HCompare, if any.
+  left->RemoveEnvironmentUsers();
+
+  // We have decided to fold the HCompare into the HCondition. Transfer the information.
+  condition->SetBias(left->AsCompare()->GetBias());
+
+  // Replace the operands of the HCondition.
+  condition->ReplaceInput(left->InputAt(0), 0);
+  condition->ReplaceInput(left->InputAt(1), 1);
+
+  // Remove the HCompare.
+  left->GetBlock()->RemoveInstruction(left);
+
+  RecordSimplification();
+}
+
 void InstructionSimplifierVisitor::VisitDiv(HDiv* instruction) {
   HConstant* input_cst = instruction->GetConstantRight();
   HInstruction* input_other = instruction->GetLeastConstantLeft();
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index b82e37c..588ab70 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -940,6 +940,9 @@
                              GetRight()->AsLongConstant()->GetValue());
     if (GetResultType() == Primitive::kPrimLong) {
       return GetBlock()->GetGraph()->GetLongConstant(value);
+    } else if (GetResultType() == Primitive::kPrimBoolean) {
+      // This can be the result of an HCondition evaluation.
+      return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
     } else {
       DCHECK_EQ(GetResultType(), Primitive::kPrimInt);
       return GetBlock()->GetGraph()->GetIntConstant(static_cast<int32_t>(value));
@@ -1647,4 +1650,38 @@
   return os;
 }
 
+bool HInstruction::HasAnyEnvironmentUseBefore(HInstruction* other) {
+  // For now, assume that instructions in different blocks may use the
+  // environment.
+  // TODO: Use the control flow to decide if this is true.
+  if (GetBlock() != other->GetBlock()) {
+    return true;
+  }
+
+  // We know that we are in the same block. Walk from 'this' to 'other',
+  // checking to see if there is any instruction with an environment.
+  HInstruction* current = this;
+  for (; current != other && current != nullptr; current = current->GetNext()) {
+    // This is a conservative check, as the instruction result may not be in
+    // the referenced environment.
+    if (current->HasEnvironment()) {
+      return true;
+    }
+  }
+
+  // We should have been called with 'this' before 'other' in the block.
+  // Just confirm this.
+  DCHECK(current != nullptr);
+  return false;
+}
+
+void HInstruction::RemoveEnvironmentUsers() {
+  for (HUseIterator<HEnvironment*> use_it(GetEnvUses()); !use_it.Done(); use_it.Advance()) {
+    HUseListNode<HEnvironment*>* user_node = use_it.Current();
+    HEnvironment* user = user_node->GetUser();
+    user->SetRawEnvAt(user_node->GetIndex(), nullptr);
+  }
+  env_uses_.Clear();
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 2cffe02..59255d1 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -325,6 +325,10 @@
     return invoke_type_;
   }
 
+  InstructionSet GetInstructionSet() const {
+    return instruction_set_;
+  }
+
  private:
   void VisitBlockForDominatorTree(HBasicBlock* block,
                                   HBasicBlock* predecessor,
@@ -1659,6 +1663,14 @@
 
   virtual bool NeedsDexCache() const { return false; }
 
+  // Does this instruction have any use in an environment before
+  // control flow hits 'other'?
+  bool HasAnyEnvironmentUseBefore(HInstruction* other);
+
+  // Remove all references to environment uses of this instruction.
+  // The caller must ensure that this is safe to do.
+  void RemoveEnvironmentUsers();
+
  protected:
   virtual const HUserRecord<HInstruction*> InputRecordAt(size_t i) const = 0;
   virtual void SetRawInputRecordAt(size_t index, const HUserRecord<HInstruction*>& input) = 0;
@@ -2135,11 +2147,20 @@
   DISALLOW_COPY_AND_ASSIGN(HBinaryOperation);
 };
 
+// The comparison bias applies for floating point operations and indicates how NaN
+// comparisons are treated:
+enum ComparisonBias {
+  kNoBias,  // bias is not applicable (i.e. for long operation)
+  kGtBias,  // return 1 for NaN comparisons
+  kLtBias,  // return -1 for NaN comparisons
+};
+
 class HCondition : public HBinaryOperation {
  public:
   HCondition(HInstruction* first, HInstruction* second)
       : HBinaryOperation(Primitive::kPrimBoolean, first, second),
-        needs_materialization_(true) {}
+        needs_materialization_(true),
+        bias_(kNoBias) {}
 
   bool NeedsMaterialization() const { return needs_materialization_; }
   void ClearNeedsMaterialization() { needs_materialization_ = false; }
@@ -2152,11 +2173,24 @@
 
   virtual IfCondition GetCondition() const = 0;
 
+  virtual IfCondition GetOppositeCondition() const = 0;
+
+  bool IsGtBias() { return bias_ == kGtBias; }
+
+  void SetBias(ComparisonBias bias) { bias_ = bias; }
+
+  bool InstructionDataEquals(HInstruction* other) const OVERRIDE {
+    return bias_ == other->AsCondition()->bias_;
+  }
+
  private:
   // For register allocation purposes, returns whether this instruction needs to be
   // materialized (that is, not just be in the processor flags).
   bool needs_materialization_;
 
+  // Needed if we merge a HCompare into a HCondition.
+  ComparisonBias bias_;
+
   DISALLOW_COPY_AND_ASSIGN(HCondition);
 };
 
@@ -2181,6 +2215,10 @@
     return kCondEQ;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondNE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HEqual);
 };
@@ -2205,6 +2243,10 @@
     return kCondNE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondEQ;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HNotEqual);
 };
@@ -2227,6 +2269,10 @@
     return kCondLT;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondGE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HLessThan);
 };
@@ -2249,6 +2295,10 @@
     return kCondLE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondGT;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HLessThanOrEqual);
 };
@@ -2271,6 +2321,10 @@
     return kCondGT;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondLE;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HGreaterThan);
 };
@@ -2293,6 +2347,10 @@
     return kCondGE;
   }
 
+  IfCondition GetOppositeCondition() const OVERRIDE {
+    return kCondLT;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(HGreaterThanOrEqual);
 };
@@ -2302,18 +2360,10 @@
 // Result is 0 if input0 == input1, 1 if input0 > input1, or -1 if input0 < input1.
 class HCompare : public HBinaryOperation {
  public:
-  // The bias applies for floating point operations and indicates how NaN
-  // comparisons are treated:
-  enum Bias {
-    kNoBias,  // bias is not applicable (i.e. for long operation)
-    kGtBias,  // return 1 for NaN comparisons
-    kLtBias,  // return -1 for NaN comparisons
-  };
-
   HCompare(Primitive::Type type,
            HInstruction* first,
            HInstruction* second,
-           Bias bias,
+           ComparisonBias bias,
            uint32_t dex_pc)
       : HBinaryOperation(Primitive::kPrimInt, first, second), bias_(bias), dex_pc_(dex_pc) {
     DCHECK_EQ(type, first->GetType());
@@ -2338,6 +2388,8 @@
     return bias_ == other->AsCompare()->bias_;
   }
 
+  ComparisonBias GetBias() const { return bias_; }
+
   bool IsGtBias() { return bias_ == kGtBias; }
 
   uint32_t GetDexPc() const { return dex_pc_; }
@@ -2345,7 +2397,7 @@
   DECLARE_INSTRUCTION(Compare);
 
  private:
-  const Bias bias_;
+  const ComparisonBias bias_;
   const uint32_t dex_pc_;
 
   DISALLOW_COPY_AND_ASSIGN(HCompare);
@@ -4079,13 +4131,19 @@
   };
 
   HMonitorOperation(HInstruction* object, OperationKind kind, uint32_t dex_pc)
-    : HTemplateInstruction(SideEffects::None()), kind_(kind), dex_pc_(dex_pc) {
+    : HTemplateInstruction(SideEffects::ChangesSomething()), kind_(kind), dex_pc_(dex_pc) {
     SetRawInputAt(0, object);
   }
 
   // Instruction may throw a Java exception, so we need an environment.
-  bool NeedsEnvironment() const OVERRIDE { return true; }
-  bool CanThrow() const OVERRIDE { return true; }
+  bool NeedsEnvironment() const OVERRIDE { return CanThrow(); }
+
+  bool CanThrow() const OVERRIDE {
+    // Verifier guarantees that monitor-exit cannot throw.
+    // This is important because it allows the HGraphBuilder to remove
+    // a dead throw-catch loop generated for `synchronized` blocks/methods.
+    return IsEnter();
+  }
 
   uint32_t GetDexPc() const OVERRIDE { return dex_pc_; }
 
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index b86bc85..6da5c35 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -953,6 +953,48 @@
   DriverStr(RepeatFF(&x86_64::X86_64Assembler::orpd, "orpd %{reg2}, %{reg1}"), "orpd");
 }
 
+TEST_F(AssemblerX86_64Test, UcomissAddress) {
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM1), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM2), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM3), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), 0));
+  GetAssembler()->ucomiss(x86_64::XmmRegister(x86_64::XMM4), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
+  const char* expected =
+    "ucomiss 0xc(%RDI,%RBX,4), %xmm0\n"
+    "ucomiss 0xc(%RDI,%R9,4), %xmm1\n"
+    "ucomiss 0xc(%RDI,%R9,4), %xmm2\n"
+    "ucomiss (%R13), %xmm3\n"
+    "ucomiss (%R13,%R9,1), %xmm4\n";
+
+  DriverStr(expected, "ucomiss_address");
+}
+
+TEST_F(AssemblerX86_64Test, UcomisdAddress) {
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM0), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::RBX), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM1), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM2), x86_64::Address(
+      x86_64::CpuRegister(x86_64::RDI), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_4, 12));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM3), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), 0));
+  GetAssembler()->ucomisd(x86_64::XmmRegister(x86_64::XMM4), x86_64::Address(
+      x86_64::CpuRegister(x86_64::R13), x86_64::CpuRegister(x86_64::R9), x86_64::TIMES_1, 0));
+  const char* expected =
+    "ucomisd 0xc(%RDI,%RBX,4), %xmm0\n"
+    "ucomisd 0xc(%RDI,%R9,4), %xmm1\n"
+    "ucomisd 0xc(%RDI,%R9,4), %xmm2\n"
+    "ucomisd (%R13), %xmm3\n"
+    "ucomisd (%R13,%R9,1), %xmm4\n";
+
+  DriverStr(expected, "ucomisd_address");
+}
+
 // X87
 
 std::string x87_fn(AssemblerX86_64Test::Base* assembler_test ATTRIBUTE_UNUSED,
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
new file mode 100755
index 0000000..988fe03
--- /dev/null
+++ b/dexlist/Android.mk
@@ -0,0 +1,54 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# TODO(ajcbik): Art-i-fy this makefile
+
+# TODO(ajcbik): rename dexlist2 into dexlist when Dalvik version is removed
+
+LOCAL_PATH:= $(call my-dir)
+
+dexlist_src_files := dexlist.cc
+dexlist_c_includes := art/runtime
+dexlist_libraries := libart
+
+##
+## Build the device command line tool dexlist.
+##
+
+ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := cc
+LOCAL_SRC_FILES := $(dexlist_src_files)
+LOCAL_C_INCLUDES := $(dexlist_c_includes)
+LOCAL_CFLAGS += -Wall
+LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
+LOCAL_MODULE := dexlist2
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+include $(BUILD_EXECUTABLE)
+endif # !SDK_ONLY
+
+##
+## Build the host command line tool dexlist.
+##
+
+include $(CLEAR_VARS)
+LOCAL_CPP_EXTENSION := cc
+LOCAL_SRC_FILES := $(dexlist_src_files)
+LOCAL_C_INCLUDES := $(dexlist_c_includes)
+LOCAL_CFLAGS += -Wall
+LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
+LOCAL_MODULE := dexlist2
+LOCAL_MODULE_TAGS := optional
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
new file mode 100644
index 0000000..d7c0e4c
--- /dev/null
+++ b/dexlist/dexlist.cc
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Implementation file of the dexlist utility.
+ *
+ * This is a re-implementation of the original dexlist utility that was
+ * based on Dalvik functions in libdex into a new dexlist that is now
+ * based on Art functions in libart instead. The output is identical to
+ * the original for correct DEX files. Error messages may differ, however.
+ *
+ * List all methods in all concrete classes in one or more DEX files.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "dex_file-inl.h"
+#include "mem_map.h"
+#include "runtime.h"
+
+namespace art {
+
+static const char* gProgName = "dexlist";
+
+/* Command-line options. */
+static struct {
+  char* argCopy;
+  const char* classToFind;
+  const char* methodToFind;
+  const char* outputFileName;
+} gOptions;
+
+/*
+ * Output file. Defaults to stdout.
+ */
+static FILE* gOutFile = stdout;
+
+/*
+ * Data types that match the definitions in the VM specification.
+ */
+typedef uint8_t  u1;
+typedef uint16_t u2;
+typedef uint32_t u4;
+typedef uint64_t u8;
+typedef int32_t  s4;
+typedef int64_t  s8;
+
+/*
+ * Returns a newly-allocated string for the "dot version" of the class
+ * name for the given type descriptor. That is, The initial "L" and
+ * final ";" (if any) have been removed and all occurrences of '/'
+ * have been changed to '.'.
+ */
+static char* descriptorToDot(const char* str) {
+  size_t at = strlen(str);
+  if (str[0] == 'L') {
+    at -= 2;  // Two fewer chars to copy.
+    str++;
+  }
+  char* newStr = reinterpret_cast<char*>(malloc(at + 1));
+  newStr[at] = '\0';
+  while (at > 0) {
+    at--;
+    newStr[at] = (str[at] == '/') ? '.' : str[at];
+  }
+  return newStr;
+}
+
+/*
+ * Positions table callback; we just want to catch the number of the
+ * first line in the method, which *should* correspond to the first
+ * entry from the table.  (Could also use "min" here.)
+ */
+static bool positionsCb(void* context, u4 /*address*/, u4 lineNum) {
+  int* pFirstLine = reinterpret_cast<int *>(context);
+  if (*pFirstLine == -1) {
+    *pFirstLine = lineNum;
+  }
+  return 0;
+}
+
+/*
+ * Dumps a method.
+ */
+static void dumpMethod(const DexFile* pDexFile,
+                       const char* fileName, u4 idx, u4 flags,
+                       const DexFile::CodeItem* pCode, u4 codeOffset) {
+  // Abstract and native methods don't get listed.
+  if (pCode == nullptr || codeOffset == 0) {
+    return;
+  }
+
+  // Method information.
+  const DexFile::MethodId& pMethodId = pDexFile->GetMethodId(idx);
+  const char* methodName = pDexFile->StringDataByIdx(pMethodId.name_idx_);
+  const char* classDescriptor = pDexFile->StringByTypeIdx(pMethodId.class_idx_);
+  char* className = descriptorToDot(classDescriptor);
+  const u4 insnsOff = codeOffset + 0x10;
+
+  // Don't list methods that do not match a particular query.
+  if (gOptions.methodToFind != nullptr &&
+      (strcmp(gOptions.classToFind, className) != 0 ||
+       strcmp(gOptions.methodToFind, methodName) != 0)) {
+    free(className);
+    return;
+  }
+
+  // If the filename is empty, then set it to something printable.
+  if (fileName == nullptr || fileName[0] == 0) {
+    fileName = "(none)";
+  }
+
+  // Find the first line.
+  int firstLine = -1;
+  bool is_static = (flags & kAccStatic) != 0;
+  pDexFile->DecodeDebugInfo(
+     pCode, is_static, idx, positionsCb, nullptr, &firstLine);
+
+  // Method signature.
+  const Signature signature = pDexFile->GetMethodSignature(pMethodId);
+  char* typeDesc = strdup(signature.ToString().c_str());
+
+  // Dump actual method information.
+  fprintf(gOutFile, "0x%08x %d %s %s %s %s %d\n",
+          insnsOff, pCode->insns_size_in_code_units_ * 2,
+          className, methodName, typeDesc, fileName, firstLine);
+
+  free(typeDesc);
+  free(className);
+}
+
+/*
+ * Runs through all direct and virtual methods in the class.
+ */
+void dumpClass(const DexFile* pDexFile, u4 idx) {
+  const DexFile::ClassDef& pClassDef = pDexFile->GetClassDef(idx);
+
+  const char* fileName;
+  if (pClassDef.source_file_idx_ == DexFile::kDexNoIndex) {
+    fileName = nullptr;
+  } else {
+    fileName = pDexFile->StringDataByIdx(pClassDef.source_file_idx_);
+  }
+
+  const u1* pEncodedData = pDexFile->GetClassData(pClassDef);
+  if (pEncodedData != nullptr) {
+    ClassDataItemIterator pClassData(*pDexFile, pEncodedData);
+    // Skip the fields.
+    for (; pClassData.HasNextStaticField(); pClassData.Next()) {}
+    for (; pClassData.HasNextInstanceField(); pClassData.Next()) {}
+    // Direct methods.
+    for (; pClassData.HasNextDirectMethod(); pClassData.Next()) {
+      dumpMethod(pDexFile, fileName,
+                 pClassData.GetMemberIndex(),
+                 pClassData.GetRawMemberAccessFlags(),
+                 pClassData.GetMethodCodeItem(),
+                 pClassData.GetMethodCodeItemOffset());
+    }
+    // Virtual methods.
+    for (; pClassData.HasNextVirtualMethod(); pClassData.Next()) {
+      dumpMethod(pDexFile, fileName,
+                 pClassData.GetMemberIndex(),
+                 pClassData.GetRawMemberAccessFlags(),
+                 pClassData.GetMethodCodeItem(),
+                 pClassData.GetMethodCodeItemOffset());
+    }
+  }
+}
+
+/*
+ * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
+ */
+static int processFile(const char* fileName) {
+  // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
+  // all of which are Zip archives with "classes.dex" inside.
+  std::string error_msg;
+  std::vector<std::unique_ptr<const DexFile>> dex_files;
+  if (!DexFile::Open(fileName, fileName, &error_msg, &dex_files)) {
+    fputs(error_msg.c_str(), stderr);
+    fputc('\n', stderr);
+    return -1;
+  }
+
+  // Determine if opening file yielded a single dex file.
+  //
+  // TODO(ajcbik): this restriction is not really needed, but kept
+  //               for now to stay close to original dexlist; we can
+  //               later relax this!
+  //
+  if (dex_files.size() != 1) {
+    fprintf(stderr, "ERROR: DEX parse failed\n");
+    return -1;
+  }
+  const DexFile* pDexFile = dex_files[0].get();
+
+  // Success. Iterate over all classes.
+  fprintf(gOutFile, "#%s\n", fileName);
+  const u4 classDefsSize = pDexFile->GetHeader().class_defs_size_;
+  for (u4 idx = 0; idx < classDefsSize; idx++) {
+    dumpClass(pDexFile, idx);
+  }
+  return 0;
+}
+
+/*
+ * Shows usage.
+ */
+static void usage(void) {
+  fprintf(stderr, "Copyright (C) 2007 The Android Open Source Project\n\n");
+  fprintf(stderr, "%s: [-m p.c.m] [-o outfile] dexfile...\n", gProgName);
+  fprintf(stderr, "\n");
+}
+
+/*
+ * Main driver of the dexlist utility.
+ */
+int dexlistDriver(int argc, char** argv) {
+  // Art specific set up.
+  InitLogging(argv);
+  MemMap::Init();
+
+  // Reset options.
+  bool wantUsage = false;
+  memset(&gOptions, 0, sizeof(gOptions));
+
+  // Parse all arguments.
+  while (1) {
+    const int ic = getopt(argc, argv, "o:m:");
+    if (ic < 0) {
+      break;  // done
+    }
+    switch (ic) {
+      case 'o':  // output file
+        gOptions.outputFileName = optarg;
+        break;
+      case 'm':
+        // If -m X.Y.Z is given, then find all instances of the
+        // fully-qualified method name. This isn't really what
+        // dexlist is for, but it's easy to do it here.
+        {
+          gOptions.argCopy = strdup(optarg);
+          char* meth = strrchr(gOptions.argCopy, '.');
+          if (meth == nullptr) {
+            fprintf(stderr, "Expected: package.Class.method\n");
+            wantUsage = true;
+          } else {
+            *meth = '\0';
+            gOptions.classToFind = gOptions.argCopy;
+            gOptions.methodToFind = meth + 1;
+          }
+        }
+        break;
+      default:
+        wantUsage = true;
+        break;
+    }  // switch
+  }  // while
+
+  // Detect early problems.
+  if (optind == argc) {
+    fprintf(stderr, "%s: no file specified\n", gProgName);
+    wantUsage = true;
+  }
+  if (wantUsage) {
+    usage();
+    free(gOptions.argCopy);
+    return 2;
+  }
+
+  // Open alternative output file.
+  if (gOptions.outputFileName) {
+    gOutFile = fopen(gOptions.outputFileName, "w");
+    if (!gOutFile) {
+      fprintf(stderr, "Can't open %s\n", gOptions.outputFileName);
+      free(gOptions.argCopy);
+      return 1;
+    }
+  }
+
+  // Process all files supplied on command line. If one of them fails we
+  // continue on, only returning a failure at the end.
+  int result = 0;
+  while (optind < argc) {
+    result |= processFile(argv[optind++]);
+  }  // while
+
+  free(gOptions.argCopy);
+  return result != 0;
+}
+
+}  // namespace art
+
+int main(int argc, char** argv) {
+  return art::dexlistDriver(argc, argv);
+}
+
diff --git a/dexlist/dexlist_test.cc b/dexlist/dexlist_test.cc
new file mode 100644
index 0000000..7b1b63d
--- /dev/null
+++ b/dexlist/dexlist_test.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "base/stringprintf.h"
+#include "common_runtime_test.h"
+#include "runtime/arch/instruction_set.h"
+#include "runtime/gc/heap.h"
+#include "runtime/gc/space/image_space.h"
+#include "runtime/os.h"
+#include "runtime/utils.h"
+#include "utils.h"
+
+namespace art {
+
+class DexListTest : public CommonRuntimeTest {
+ protected:
+  virtual void SetUp() {
+    CommonRuntimeTest::SetUp();
+    // Dogfood our own lib core dex file.
+    dex_file_ = GetLibCoreDexFileName();
+  }
+
+  // Runs test with given arguments.
+  bool Exec(const std::vector<std::string>& args, std::string* error_msg) {
+    // TODO(ajcbik): dexlist2 -> dexlist
+    std::string file_path = GetTestAndroidRoot();
+    if (IsHost()) {
+      file_path += "/bin/dexlist2";
+    } else {
+      file_path += "/xbin/dexlist2";
+    }
+    EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
+    std::vector<std::string> exec_argv = { file_path };
+    exec_argv.insert(exec_argv.end(), args.begin(), args.end());
+    return ::art::Exec(exec_argv, error_msg);
+  }
+
+  std::string dex_file_;
+};
+
+
+TEST_F(DexListTest, NoInputFileGiven) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, CantOpenOutput) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({"-o", "/joho", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, IllFormedMethod) {
+  std::string error_msg;
+  ASSERT_FALSE(Exec({"-m", "joho", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, FullOutput) {
+  std::string error_msg;
+  ASSERT_TRUE(Exec({"-o", "/dev/null", dex_file_}, &error_msg)) << error_msg;
+}
+
+TEST_F(DexListTest, MethodOutput) {
+  std::string error_msg;
+  ASSERT_TRUE(Exec({"-o", "/dev/null", "-m", "java.lang.Object.toString",
+    dex_file_}, &error_msg)) << error_msg;
+}
+
+}  // namespace art
diff --git a/imgdiag/imgdiag.cc b/imgdiag/imgdiag.cc
index f324881..dce5206 100644
--- a/imgdiag/imgdiag.cc
+++ b/imgdiag/imgdiag.cc
@@ -548,10 +548,6 @@
           os << "  entryPointFromJni: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromJniPtrSize(pointer_size)) << ", ";
-          os << "  entryPointFromInterpreter: "
-             << reinterpret_cast<const void*>(
-                    art_method->GetEntryPointFromInterpreterPtrSize(pointer_size))
-             << ", ";
           os << "  entryPointFromQuickCompiledCode: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size))
@@ -631,10 +627,6 @@
           os << "  entryPointFromJni: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromJniPtrSize(pointer_size)) << ", ";
-          os << "  entryPointFromInterpreter: "
-             << reinterpret_cast<const void*>(
-                    art_method->GetEntryPointFromInterpreterPtrSize(pointer_size))
-             << ", ";
           os << "  entryPointFromQuickCompiledCode: "
              << reinterpret_cast<const void*>(
                     art_method->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size))
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index cf4f822..8dde547 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1618,7 +1618,8 @@
     stats_.alignment_bytes += bitmap_section.Offset() - image_header_.GetImageSize();
     stats_.bitmap_bytes += bitmap_section.Size();
     stats_.art_field_bytes += field_section.Size();
-    stats_.art_method_bytes += method_section.Size();
+    // RoundUp to 8 bytes to match the intern table alignment expectation.
+    stats_.art_method_bytes += RoundUp(method_section.Size(), sizeof(uint64_t));
     stats_.interned_strings_bytes += intern_section.Size();
     stats_.Dump(os);
     os << "\n";
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 3a155be..dbd1d23 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -651,8 +651,6 @@
   copy->SetDexCacheResolvedTypes(RelocatedAddressOfPointer(object->GetDexCacheResolvedTypes()));
   copy->SetEntryPointFromQuickCompiledCodePtrSize(RelocatedAddressOfPointer(
       object->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size)), pointer_size);
-  copy->SetEntryPointFromInterpreterPtrSize(RelocatedAddressOfPointer(
-      object->GetEntryPointFromInterpreterPtrSize(pointer_size)), pointer_size);
   copy->SetEntryPointFromJniPtrSize(RelocatedAddressOfPointer(
       object->GetEntryPointFromJniPtrSize(pointer_size)), pointer_size);
 }
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 4a1e2c4..e8c47d9 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -43,9 +43,6 @@
 class PointerArray;
 }  // namespace mirror
 
-typedef void (EntryPointFromInterpreter)(Thread* self, const DexFile::CodeItem* code_item,
-                                         ShadowFrame* shadow_frame, JValue* result);
-
 class ArtMethod FINAL {
  public:
   ArtMethod() : access_flags_(0), dex_code_item_offset_(0), dex_method_index_(0),
@@ -272,23 +269,6 @@
   void Invoke(Thread* self, uint32_t* args, uint32_t args_size, JValue* result, const char* shorty)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  EntryPointFromInterpreter* GetEntryPointFromInterpreter() {
-    return GetEntryPointFromInterpreterPtrSize(sizeof(void*));
-  }
-  EntryPointFromInterpreter* GetEntryPointFromInterpreterPtrSize(size_t pointer_size) {
-    return GetEntryPoint<EntryPointFromInterpreter*>(
-        EntryPointFromInterpreterOffset(pointer_size), pointer_size);
-  }
-
-  void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter) {
-    SetEntryPointFromInterpreterPtrSize(entry_point_from_interpreter, sizeof(void*));
-  }
-  void SetEntryPointFromInterpreterPtrSize(EntryPointFromInterpreter* entry_point_from_interpreter,
-                                           size_t pointer_size) {
-    SetEntryPoint(EntryPointFromInterpreterOffset(pointer_size), entry_point_from_interpreter,
-                  pointer_size);
-  }
-
   const void* GetEntryPointFromQuickCompiledCode() {
     return GetEntryPointFromQuickCompiledCodePtrSize(sizeof(void*));
   }
@@ -398,11 +378,6 @@
 
   void UnregisterNative() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static MemberOffset EntryPointFromInterpreterOffset(size_t pointer_size) {
-    return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
-        PtrSizedFields, entry_point_from_interpreter_) / sizeof(void*) * pointer_size);
-  }
-
   static MemberOffset EntryPointFromJniOffset(size_t pointer_size) {
     return MemberOffset(PtrSizedFieldsOffset(pointer_size) + OFFSETOF_MEMBER(
         PtrSizedFields, entry_point_from_jni_) / sizeof(void*) * pointer_size);
@@ -573,10 +548,6 @@
   // PACKED(4) is necessary for the correctness of
   // RoundUp(OFFSETOF_MEMBER(ArtMethod, ptr_sized_fields_), pointer_size).
   struct PACKED(4) PtrSizedFields {
-    // Method dispatch from the interpreter invokes this pointer which may cause a bridge into
-    // compiled code.
-    void* entry_point_from_interpreter_;
-
     // Pointer to JNI function registered to this method, or a function to resolve the JNI function.
     void* entry_point_from_jni_;
 
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index 10ed0f4..20d75f3 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -189,11 +189,11 @@
 ADD_TEST_EQ(ART_METHOD_DEX_CACHE_TYPES_OFFSET,
             art::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())
 
-#define ART_METHOD_QUICK_CODE_OFFSET_32 36
+#define ART_METHOD_QUICK_CODE_OFFSET_32 32
 ADD_TEST_EQ(ART_METHOD_QUICK_CODE_OFFSET_32,
             art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(4).Int32Value())
 
-#define ART_METHOD_QUICK_CODE_OFFSET_64 48
+#define ART_METHOD_QUICK_CODE_OFFSET_64 40
 ADD_TEST_EQ(ART_METHOD_QUICK_CODE_OFFSET_64,
             art::ArtMethod::EntryPointFromQuickCompiledCodeOffset(8).Int32Value())
 
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 7972158..6f45dc8 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -137,7 +137,7 @@
 }
 
 template<int n, typename T>
-static inline bool IsAligned(T x) {
+static constexpr bool IsAligned(T x) {
   static_assert((n & (n - 1)) == 0, "n is not a power of two");
   return (x & (n - 1)) == 0;
 }
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index 35b50d1..93d4edc 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -17,7 +17,6 @@
 #ifndef ART_RUNTIME_BASE_LOGGING_H_
 #define ART_RUNTIME_BASE_LOGGING_H_
 
-#include <memory>
 #include <ostream>
 
 #include "base/macros.h"
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 23c5942..0694227 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1195,13 +1195,9 @@
       if (kIsDebugBuild && !method->IsRuntimeMethod()) {
         CHECK(method->GetDeclaringClass() != nullptr);
       }
-      if (!method->IsNative()) {
-        method->SetEntryPointFromInterpreterPtrSize(
-            artInterpreterToInterpreterBridge, image_pointer_size_);
-        if (!method->IsRuntimeMethod() && method != runtime->GetResolutionMethod()) {
-          method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
-                                                            image_pointer_size_);
-        }
+      if (!method->IsNative() && !method->IsRuntimeMethod() && !method->IsResolutionMethod()) {
+        method->SetEntryPointFromQuickCompiledCodePtrSize(GetQuickToInterpreterBridge(),
+                                                          image_pointer_size_);
       }
     }
   }
@@ -2206,11 +2202,6 @@
 
   // Install entry point from interpreter.
   bool enter_interpreter = NeedsInterpreter(method, method->GetEntryPointFromQuickCompiledCode());
-  if (enter_interpreter && !method->IsNative()) {
-    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
-  } else {
-    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
-  }
 
   if (method->IsAbstract()) {
     method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
@@ -3516,7 +3507,6 @@
   // At runtime the method looks like a reference and argument saving method, clone the code
   // related parameters from this method.
   out->SetEntryPointFromQuickCompiledCode(GetQuickProxyInvokeHandler());
-  out->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
 }
 
 void ClassLinker::CheckProxyMethod(ArtMethod* method, ArtMethod* prototype) const {
@@ -5647,18 +5637,15 @@
                                                const void* method_code) const {
   OatFile::OatMethod oat_method = CreateOatMethod(method_code);
   oat_method.LinkMethod(method);
-  method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
 }
 
 void ClassLinker::SetEntryPointsToInterpreter(ArtMethod* method) const {
   if (!method->IsNative()) {
-    method->SetEntryPointFromInterpreter(artInterpreterToInterpreterBridge);
     method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
   } else {
     const void* quick_method_code = GetQuickGenericJniStub();
     OatFile::OatMethod oat_method = CreateOatMethod(quick_method_code);
     oat_method.LinkMethod(method);
-    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
   }
 }
 
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d9935cb..e4f7b7a 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -17,7 +17,6 @@
 #ifndef ART_RUNTIME_CLASS_LINKER_H_
 #define ART_RUNTIME_CLASS_LINKER_H_
 
-#include <deque>
 #include <string>
 #include <utility>
 #include <vector>
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index de46b35..97d170e 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -4836,6 +4836,9 @@
       CHECK(!Runtime::Current()->GetHeap()->IsAllocTrackingEnabled());
       records = &dummy;
     }
+    // We don't need to wait on the condition variable records->new_record_condition_, because this
+    // function only reads the class objects, which are already marked so it doesn't change their
+    // reachability.
 
     //
     // Part 1: generate string tables.
@@ -4850,7 +4853,7 @@
          count > 0 && it != end; count--, it++) {
       const gc::AllocRecord* record = it->second;
       std::string temp;
-      class_names.Add(record->GetClass()->GetDescriptor(&temp));
+      class_names.Add(record->GetClassDescriptor(&temp));
       for (size_t i = 0, depth = record->GetDepth(); i < depth; i++) {
         ArtMethod* m = record->StackElement(i).GetMethod();
         class_names.Add(m->GetDeclaringClassDescriptor());
@@ -4902,7 +4905,7 @@
       const gc::AllocRecord* record = it->second;
       size_t stack_depth = record->GetDepth();
       size_t allocated_object_class_name_index =
-          class_names.IndexOf(record->GetClass()->GetDescriptor(&temp));
+          class_names.IndexOf(record->GetClassDescriptor(&temp));
       JDWP::Append4BE(bytes, record->ByteCount());
       JDWP::Append2BE(bytes, static_cast<uint16_t>(record->GetTid()));
       JDWP::Append2BE(bytes, allocated_object_class_name_index);
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 7ac264a..3a15f1a 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -786,7 +786,10 @@
 
   // Get the pointer to the start of the debugging data
   const uint8_t* GetDebugInfoStream(const CodeItem* code_item) const {
-    if (code_item->debug_info_off_ == 0) {
+    // Check that the offset is in bounds.
+    // Note that although the specification says that 0 should be used if there
+    // is no debug information, some applications incorrectly use 0xFFFFFFFF.
+    if (code_item->debug_info_off_ == 0 || code_item->debug_info_off_ >= size_) {
       return nullptr;
     } else {
       return begin_ + code_item->debug_info_off_;
diff --git a/runtime/fault_handler.cc b/runtime/fault_handler.cc
index 762f061..5f91566 100644
--- a/runtime/fault_handler.cc
+++ b/runtime/fault_handler.cc
@@ -320,7 +320,7 @@
     return false;
   }
 
-  ArtMethod* method_obj = 0;
+  ArtMethod* method_obj = nullptr;
   uintptr_t return_pc = 0;
   uintptr_t sp = 0;
 
@@ -331,7 +331,9 @@
   // If we don't have a potential method, we're outta here.
   VLOG(signals) << "potential method: " << method_obj;
   // TODO: Check linear alloc and image.
-  if (method_obj == 0 || !IsAligned<kObjectAlignment>(method_obj)) {
+  DCHECK(IsAligned<sizeof(void*)>(ArtMethod::ObjectSize(sizeof(void*))))
+      << "ArtMethod is not pointer aligned";
+  if (method_obj == nullptr || !IsAligned<sizeof(void*)>(method_obj)) {
     VLOG(signals) << "no method";
     return false;
   }
diff --git a/runtime/gc/allocation_record.cc b/runtime/gc/allocation_record.cc
index 11921f4..6537ed2 100644
--- a/runtime/gc/allocation_record.cc
+++ b/runtime/gc/allocation_record.cc
@@ -32,6 +32,15 @@
   return method_->GetLineNumFromDexPC(dex_pc_);
 }
 
+const char* AllocRecord::GetClassDescriptor(std::string* storage) const {
+  // klass_ could contain null only if we implement class unloading.
+  if (UNLIKELY(klass_.IsNull())) {
+    return "null";
+  } else {
+    return klass_.Read()->GetDescriptor(storage);
+  }
+}
+
 void AllocRecordObjectMap::SetProperties() {
 #ifdef HAVE_ANDROID_OS
   // Check whether there's a system property overriding the max number of records.
@@ -97,7 +106,7 @@
   // Only visit the last recent_record_max_ number of allocation records in entries_ and mark the
   // klass_ fields as strong roots.
   for (auto it = entries_.rbegin(), end = entries_.rend(); count > 0 && it != end; count--, ++it) {
-    buffered_visitor.VisitRoot(it->second->GetClassGcRoot());
+    buffered_visitor.VisitRootIfNonNull(it->second->GetClassGcRoot());
   }
 }
 
@@ -107,6 +116,8 @@
   GcRoot<mirror::Class>& klass = record->GetClassGcRoot();
   // This does not need a read barrier because this is called by GC.
   mirror::Object* old_object = klass.Read<kWithoutReadBarrier>();
+  // The class object can become null if we implement class unloading.
+  // In that case we might still want to keep the class name string (not implemented).
   mirror::Object* new_object = UNLIKELY(old_object == nullptr) ?
       nullptr : callback(old_object, arg);
   if (UNLIKELY(old_object != new_object)) {
@@ -163,11 +174,6 @@
   allow_new_record_ = false;
 }
 
-void AllocRecordObjectMap::EnsureNewAllocationRecordsDisallowed() {
-  CHECK(!allow_new_record_);
-}
-
-
 struct AllocRecordStackVisitor : public StackVisitor {
   AllocRecordStackVisitor(Thread* thread, AllocRecordStackTrace* trace_in, size_t max)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
diff --git a/runtime/gc/allocation_record.h b/runtime/gc/allocation_record.h
index f567153..06721c8 100644
--- a/runtime/gc/allocation_record.h
+++ b/runtime/gc/allocation_record.h
@@ -188,7 +188,10 @@
     return klass_.Read();
   }
 
-  GcRoot<mirror::Class>& GetClassGcRoot() {
+  const char* GetClassDescriptor(std::string* storage) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  GcRoot<mirror::Class>& GetClassGcRoot() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return klass_;
   }
 
@@ -262,15 +265,18 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
 
+  // Allocation tracking could be enabled by user in between DisallowNewAllocationRecords() and
+  // AllowNewAllocationRecords(), in which case new allocation records can be added although they
+  // should be disallowed. However, this is GC-safe because new objects are not processed in this GC
+  // cycle. The only downside of not handling this case is that such new allocation records can be
+  // swept from the list. But missing the first few records is acceptable for using the button to
+  // enable allocation tracking.
   void DisallowNewAllocationRecords()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
   void AllowNewAllocationRecords()
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
-  void EnsureNewAllocationRecordsDisallowed()
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::alloc_tracker_lock_);
 
   // TODO: Is there a better way to hide the entries_'s type?
   EntryList::iterator Begin()
diff --git a/runtime/gc/allocator_type.h b/runtime/gc/allocator_type.h
index f9a2ff6..185a9b7 100644
--- a/runtime/gc/allocator_type.h
+++ b/runtime/gc/allocator_type.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_ALLOCATOR_TYPE_H_
 #define ART_RUNTIME_GC_ALLOCATOR_TYPE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index c7d2e9f..ccf5154 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -19,6 +19,7 @@
 #include "art_field-inl.h"
 #include "gc/accounting/heap_bitmap-inl.h"
 #include "gc/accounting/space_bitmap-inl.h"
+#include "gc/reference_processor.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space.h"
 #include "intern_table.h"
@@ -334,6 +335,8 @@
       }
     }
   }
+  // TODO: Other garbage collectors uses Runtime::VisitConcurrentRoots(), refactor this part
+  // to also use the same function.
   {
     TimingLogger::ScopedTiming split2("VisitConstantRoots", GetTimings());
     Runtime::Current()->VisitConstantRoots(this);
@@ -351,6 +354,7 @@
     TimingLogger::ScopedTiming split5("VisitNonThreadRoots", GetTimings());
     Runtime::Current()->VisitNonThreadRoots(this);
   }
+  Runtime::Current()->GetHeap()->VisitAllocationRecords(this);
 
   // Immune spaces.
   for (auto& space : heap_->GetContinuousSpaces()) {
diff --git a/runtime/gc/collector/gc_type.h b/runtime/gc/collector/gc_type.h
index f18e40f..401444a 100644
--- a/runtime/gc/collector/gc_type.h
+++ b/runtime/gc/collector/gc_type.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_COLLECTOR_GC_TYPE_H_
 #define ART_RUNTIME_GC_COLLECTOR_GC_TYPE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index 9275e6d..95ba380 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_COLLECTOR_TYPE_H_
 #define ART_RUNTIME_GC_COLLECTOR_TYPE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index 1f2643a..0536f32d 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_GC_GC_CAUSE_H_
 #define ART_RUNTIME_GC_GC_CAUSE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 1b45ea1..26a45d3 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -37,13 +37,12 @@
 #include "gc/accounting/atomic_stack.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap-inl.h"
-#include "gc/accounting/mod_union_table.h"
 #include "gc/accounting/mod_union_table-inl.h"
 #include "gc/accounting/remembered_set.h"
 #include "gc/accounting/space_bitmap-inl.h"
 #include "gc/collector/concurrent_copying.h"
 #include "gc/collector/mark_compact.h"
-#include "gc/collector/mark_sweep-inl.h"
+#include "gc/collector/mark_sweep.h"
 #include "gc/collector/partial_mark_sweep.h"
 #include "gc/collector/semi_space.h"
 #include "gc/collector/sticky_mark_sweep.h"
@@ -62,7 +61,6 @@
 #include "image.h"
 #include "intern_table.h"
 #include "mirror/class-inl.h"
-#include "mirror/object.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/reference-inl.h"
@@ -467,6 +465,7 @@
   gc_complete_cond_.reset(new ConditionVariable("GC complete condition variable",
                                                 *gc_complete_lock_));
   task_processor_.reset(new TaskProcessor());
+  reference_processor_.reset(new ReferenceProcessor());
   pending_task_lock_ = new Mutex("Pending task lock");
   if (ignore_max_footprint_) {
     SetIdealFootprint(std::numeric_limits<size_t>::max());
@@ -1865,7 +1864,7 @@
              static_cast<double>(space_size_before_compaction);
   tl->ResumeAll();
   // Finish GC.
-  reference_processor_.EnqueueClearedReferences(self);
+  reference_processor_->EnqueueClearedReferences(self);
   GrowForUtilization(semi_space_collector_);
   LogGC(kGcCauseHomogeneousSpaceCompact, collector);
   FinishGC(self, collector::kGcTypeFull);
@@ -1998,7 +1997,7 @@
   ChangeCollector(collector_type);
   tl->ResumeAll();
   // Can't call into java code with all threads suspended.
-  reference_processor_.EnqueueClearedReferences(self);
+  reference_processor_->EnqueueClearedReferences(self);
   uint64_t duration = NanoTime() - start_time;
   GrowForUtilization(semi_space_collector_);
   DCHECK(collector != nullptr);
@@ -2472,7 +2471,7 @@
   total_bytes_freed_ever_ += GetCurrentGcIteration()->GetFreedBytes();
   RequestTrim(self);
   // Enqueue cleared references.
-  reference_processor_.EnqueueClearedReferences(self);
+  reference_processor_->EnqueueClearedReferences(self);
   // Grow the heap so that we know when to perform the next GC.
   GrowForUtilization(collector, bytes_allocated_before_gc);
   LogGC(gc_cause, collector);
@@ -3734,17 +3733,6 @@
   }
 }
 
-void Heap::EnsureNewAllocationRecordsDisallowed() const {
-  if (IsAllocTrackingEnabled()) {
-    // Lock and unlock once to ensure that no threads are still in the
-    // middle of adding new allocation records.
-    MutexLock mu(Thread::Current(), *Locks::alloc_tracker_lock_);
-    if (IsAllocTrackingEnabled()) {
-      GetAllocationRecords()->EnsureNewAllocationRecordsDisallowed();
-    }
-  }
-}
-
 // Based on debug malloc logic from libc/bionic/debug_stacktrace.cpp.
 class StackCrawlState {
  public:
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 1c75bd0..d0040f2 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -26,22 +26,17 @@
 #include "arch/instruction_set.h"
 #include "atomic.h"
 #include "base/time_utils.h"
-#include "base/timing_logger.h"
 #include "gc/accounting/atomic_stack.h"
 #include "gc/accounting/card_table.h"
 #include "gc/accounting/read_barrier_table.h"
 #include "gc/gc_cause.h"
-#include "gc/collector/garbage_collector.h"
 #include "gc/collector/gc_type.h"
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 #include "globals.h"
-#include "jni.h"
 #include "object_callbacks.h"
 #include "offsets.h"
-#include "reference_processor.h"
 #include "safe_map.h"
-#include "thread_pool.h"
 #include "verify_object.h"
 
 namespace art {
@@ -50,6 +45,7 @@
 class Mutex;
 class StackVisitor;
 class Thread;
+class ThreadPool;
 class TimingLogger;
 
 namespace mirror {
@@ -631,7 +627,7 @@
   bool HasImageSpace() const;
 
   ReferenceProcessor* GetReferenceProcessor() {
-    return &reference_processor_;
+    return reference_processor_.get();
   }
   TaskProcessor* GetTaskProcessor() {
     return task_processor_.get();
@@ -721,10 +717,6 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
 
-  void EnsureNewAllocationRecordsDisallowed() const
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      LOCKS_EXCLUDED(Locks::alloc_tracker_lock_);
-
  private:
   class ConcurrentGCTask;
   class CollectorTransitionTask;
@@ -1019,7 +1011,7 @@
   std::unique_ptr<ConditionVariable> gc_complete_cond_ GUARDED_BY(gc_complete_lock_);
 
   // Reference processor;
-  ReferenceProcessor reference_processor_;
+  std::unique_ptr<ReferenceProcessor> reference_processor_;
 
   // Task processor, proxies heap trim requests to the daemon threads.
   std::unique_ptr<TaskProcessor> task_processor_;
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 52192e2..2b567fe 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -16,7 +16,9 @@
 
 #include "large_object_space.h"
 
+#include <valgrind.h>
 #include <memory>
+#include <memcheck/memcheck.h>
 
 #include "gc/accounting/heap_bitmap-inl.h"
 #include "gc/accounting/space_bitmap-inl.h"
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 5f3a1db..9495864 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -20,8 +20,6 @@
 #include "space.h"
 
 #include <ostream>
-#include <valgrind.h>
-#include <memcheck/memcheck.h>
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/rosalloc_space-inl.h b/runtime/gc/space/rosalloc_space-inl.h
index 25d4445..f94ec23 100644
--- a/runtime/gc/space/rosalloc_space-inl.h
+++ b/runtime/gc/space/rosalloc_space-inl.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_GC_SPACE_ROSALLOC_SPACE_INL_H_
 #define ART_RUNTIME_GC_SPACE_ROSALLOC_SPACE_INL_H_
 
+#include <valgrind.h>
+
 #include "gc/allocator/rosalloc-inl.h"
 #include "gc/space/valgrind_settings.h"
 #include "rosalloc_space.h"
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index d37ddcb..abe9dc2 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -99,19 +99,6 @@
     }
   }
   method->SetEntryPointFromQuickCompiledCode(quick_code);
-  if (!method->IsResolutionMethod()) {
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    if (class_linker->IsQuickToInterpreterBridge(quick_code) ||
-        (class_linker->IsQuickResolutionStub(quick_code) &&
-         Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
-         !method->IsNative() && !method->IsProxyMethod())) {
-      DCHECK(!method->IsNative()) << PrettyMethod(method);
-      DCHECK(!method->IsProxyMethod()) << PrettyMethod(method);
-      method->SetEntryPointFromInterpreter(art::artInterpreterToInterpreterBridge);
-    } else {
-      method->SetEntryPointFromInterpreter(art::artInterpreterToCompiledCodeBridge);
-    }
-  }
 }
 
 void Instrumentation::InstallStubsForMethod(ArtMethod* method) {
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index fa103b1..0980ea1 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -19,6 +19,7 @@
 #include <cmath>
 
 #include "debugger.h"
+#include "entrypoints/runtime_asm_entrypoints.h"
 #include "mirror/array-inl.h"
 #include "unstarted_runtime.h"
 #include "verifier/method_verifier.h"
@@ -490,6 +491,23 @@
                                 uint32_t arg[Instruction::kMaxVarArgRegs],
                                 uint32_t vregC) ALWAYS_INLINE;
 
+SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+static inline bool NeedsInterpreter(Thread* self, ShadowFrame* new_shadow_frame) ALWAYS_INLINE;
+
+static inline bool NeedsInterpreter(Thread* self, ShadowFrame* new_shadow_frame) {
+  ArtMethod* target = new_shadow_frame->GetMethod();
+  if (UNLIKELY(target->IsNative() || target->IsProxyMethod())) {
+    return false;
+  }
+  Runtime* runtime = Runtime::Current();
+  ClassLinker* class_linker = runtime->GetClassLinker();
+  return runtime->GetInstrumentation()->IsForcedInterpretOnly() ||
+        // Doing this check avoids doing compiled/interpreter transitions.
+        class_linker->IsQuickToInterpreterBridge(target->GetEntryPointFromQuickCompiledCode()) ||
+        // Force the use of interpreter when it is required by the debugger.
+        Dbg::IsForcedInterpreterNeededForCalling(self, target);
+}
+
 template<bool is_range, bool do_assignability_check>
 static inline bool DoCallCommon(ArtMethod* called_method,
                                 Thread* self,
@@ -660,28 +678,11 @@
 
   // Do the call now.
   if (LIKELY(Runtime::Current()->IsStarted())) {
-    if (kIsDebugBuild && new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter() == nullptr) {
-      LOG(FATAL) << "Attempt to invoke non-executable method: "
-          << PrettyMethod(new_shadow_frame->GetMethod());
-      UNREACHABLE();
-    }
-    if (kIsDebugBuild && Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly() &&
-        !new_shadow_frame->GetMethod()->IsNative() &&
-        !new_shadow_frame->GetMethod()->IsProxyMethod() &&
-        new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter()
-            == artInterpreterToCompiledCodeBridge) {
-      LOG(FATAL) << "Attempt to call compiled code when -Xint: "
-          << PrettyMethod(new_shadow_frame->GetMethod());
-      UNREACHABLE();
-    }
-    // Force the use of interpreter when it is required by the debugger.
-    EntryPointFromInterpreter* entry;
-    if (UNLIKELY(Dbg::IsForcedInterpreterNeededForCalling(self, new_shadow_frame->GetMethod()))) {
-      entry = &art::artInterpreterToInterpreterBridge;
+    if (NeedsInterpreter(self, new_shadow_frame)) {
+      artInterpreterToInterpreterBridge(self, code_item, new_shadow_frame, result);
     } else {
-      entry = new_shadow_frame->GetMethod()->GetEntryPointFromInterpreter();
+      artInterpreterToCompiledCodeBridge(self, code_item, new_shadow_frame, result);
     }
-    entry(self, code_item, new_shadow_frame, result);
   } else {
     UnstartedRuntime::Invoke(self, code_item, new_shadow_frame, result, first_dest_reg);
   }
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index bc9545b..fda97db 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -132,11 +132,7 @@
     VLOG(jit) << "JIT not compiling " << PrettyMethod(method) << " due to breakpoint";
     return false;
   }
-  const bool result = jit_compile_method_(jit_compiler_handle_, method, self);
-  if (result) {
-    method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
-  }
-  return result;
+  return jit_compile_method_(jit_compiler_handle_, method, self);
 }
 
 void Jit::CreateThreadPool() {
diff --git a/runtime/oat.h b/runtime/oat.h
index 000ae8e..5706c4e 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '6', '4', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '6', '5', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index 8e99dbb..df34ce7 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -17,13 +17,6 @@
 #ifndef ART_RUNTIME_OBJECT_CALLBACKS_H_
 #define ART_RUNTIME_OBJECT_CALLBACKS_H_
 
-// For ostream.
-#include <ostream>
-// For uint32_t.
-#include <stdint.h>
-// For size_t.
-#include <stdlib.h>
-
 #include "base/macros.h"
 
 namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 20e4149..5067b0d 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1510,7 +1510,6 @@
   monitor_list_->EnsureNewMonitorsDisallowed();
   intern_table_->EnsureNewInternsDisallowed();
   java_vm_->EnsureNewWeakGlobalsDisallowed();
-  heap_->EnsureNewAllocationRecordsDisallowed();
 }
 
 void Runtime::SetInstructionSet(InstructionSet instruction_set) {
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 11c94db..6f3b0a3 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -857,7 +857,6 @@
               << " native=" << method->IsNative()
               << " entrypoints=" << method->GetEntryPointFromQuickCompiledCode()
               << "," << method->GetEntryPointFromJni()
-              << "," << method->GetEntryPointFromInterpreter()
               << " next=" << *cur_quick_frame_;
         }
 
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index f7ef894..5f965f1 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -25,6 +25,7 @@
 #include "base/mutex-inl.h"
 #include "gc/heap.h"
 #include "jni_env_ext.h"
+#include "thread_pool.h"
 
 namespace art {
 
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index b697b43..7e8128f 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -28,7 +28,6 @@
 #include <sstream>
 
 #include "base/histogram-inl.h"
-#include "base/mutex.h"
 #include "base/mutex-inl.h"
 #include "base/time_utils.h"
 #include "base/timing_logger.h"
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index 1e84c9d..d8f80fa 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -201,112 +201,4 @@
   return tasks_.size();
 }
 
-WorkStealingWorker::WorkStealingWorker(ThreadPool* thread_pool, const std::string& name,
-                                       size_t stack_size)
-    : ThreadPoolWorker(thread_pool, name, stack_size), task_(nullptr) {}
-
-void WorkStealingWorker::Run() {
-  Thread* self = Thread::Current();
-  Task* task = nullptr;
-  WorkStealingThreadPool* thread_pool = down_cast<WorkStealingThreadPool*>(thread_pool_);
-  while ((task = thread_pool_->GetTask(self)) != nullptr) {
-    WorkStealingTask* stealing_task = down_cast<WorkStealingTask*>(task);
-
-    {
-      CHECK(task_ == nullptr);
-      MutexLock mu(self, thread_pool->work_steal_lock_);
-      // Register that we are running the task
-      ++stealing_task->ref_count_;
-      task_ = stealing_task;
-    }
-    stealing_task->Run(self);
-    // Mark ourselves as not running a task so that nobody tries to steal from us.
-    // There is a race condition that someone starts stealing from us at this point. This is okay
-    // due to the reference counting.
-    task_ = nullptr;
-
-    bool finalize;
-
-    // Steal work from tasks until there is none left to steal. Note: There is a race, but
-    // all that happens when the race occurs is that we steal some work instead of processing a
-    // task from the queue.
-    while (thread_pool->GetTaskCount(self) == 0) {
-      WorkStealingTask* steal_from_task  = nullptr;
-
-      {
-        MutexLock mu(self, thread_pool->work_steal_lock_);
-        // Try finding a task to steal from.
-        steal_from_task = thread_pool->FindTaskToStealFrom();
-        if (steal_from_task != nullptr) {
-          CHECK_NE(stealing_task, steal_from_task)
-              << "Attempting to steal from completed self task";
-          steal_from_task->ref_count_++;
-        } else {
-          break;
-        }
-      }
-
-      if (steal_from_task != nullptr) {
-        // Task which completed earlier is going to steal some work.
-        stealing_task->StealFrom(self, steal_from_task);
-
-        {
-          // We are done stealing from the task, lets decrement its reference count.
-          MutexLock mu(self, thread_pool->work_steal_lock_);
-          finalize = !--steal_from_task->ref_count_;
-        }
-
-        if (finalize) {
-          steal_from_task->Finalize();
-        }
-      }
-    }
-
-    {
-      MutexLock mu(self, thread_pool->work_steal_lock_);
-      // If nobody is still referencing task_ we can finalize it.
-      finalize = !--stealing_task->ref_count_;
-    }
-
-    if (finalize) {
-      stealing_task->Finalize();
-    }
-  }
-}
-
-WorkStealingWorker::~WorkStealingWorker() {}
-
-WorkStealingThreadPool::WorkStealingThreadPool(const char* name, size_t num_threads)
-    : ThreadPool(name, 0),
-      work_steal_lock_("work stealing lock"),
-      steal_index_(0) {
-  while (GetThreadCount() < num_threads) {
-    const std::string worker_name = StringPrintf("Work stealing worker %zu", GetThreadCount());
-    threads_.push_back(new WorkStealingWorker(this, worker_name,
-                                              ThreadPoolWorker::kDefaultStackSize));
-  }
-}
-
-WorkStealingTask* WorkStealingThreadPool::FindTaskToStealFrom() {
-  const size_t thread_count = GetThreadCount();
-  for (size_t i = 0; i < thread_count; ++i) {
-    // TODO: Use CAS instead of lock.
-    ++steal_index_;
-    if (steal_index_ >= thread_count) {
-      steal_index_-= thread_count;
-    }
-
-    WorkStealingWorker* worker = down_cast<WorkStealingWorker*>(threads_[steal_index_]);
-    WorkStealingTask* task = worker->task_;
-    if (task) {
-      // Not null, we can probably steal from this worker.
-      return task;
-    }
-  }
-  // Couldn't find something to steal.
-  return nullptr;
-}
-
-WorkStealingThreadPool::~WorkStealingThreadPool() {}
-
 }  // namespace art
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index 0557708..88700e6 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -144,58 +144,6 @@
   DISALLOW_COPY_AND_ASSIGN(ThreadPool);
 };
 
-class WorkStealingTask : public Task {
- public:
-  WorkStealingTask() : ref_count_(0) {}
-
-  size_t GetRefCount() const {
-    return ref_count_;
-  }
-
-  virtual void StealFrom(Thread* self, WorkStealingTask* source) = 0;
-
- private:
-  // How many people are referencing this task.
-  size_t ref_count_;
-
-  friend class WorkStealingWorker;
-};
-
-class WorkStealingWorker : public ThreadPoolWorker {
- public:
-  virtual ~WorkStealingWorker();
-
-  bool IsRunningTask() const {
-    return task_ != nullptr;
-  }
-
- protected:
-  WorkStealingTask* task_;
-
-  WorkStealingWorker(ThreadPool* thread_pool, const std::string& name, size_t stack_size);
-  virtual void Run();
-
- private:
-  friend class WorkStealingThreadPool;
-  DISALLOW_COPY_AND_ASSIGN(WorkStealingWorker);
-};
-
-class WorkStealingThreadPool : public ThreadPool {
- public:
-  explicit WorkStealingThreadPool(const char* name, size_t num_threads);
-  virtual ~WorkStealingThreadPool();
-
- private:
-  Mutex work_steal_lock_;
-  // Which thread we are stealing from (round robin).
-  size_t steal_index_;
-
-  // Find a task to steal from
-  WorkStealingTask* FindTaskToStealFrom() EXCLUSIVE_LOCKS_REQUIRED(work_steal_lock_);
-
-  friend class WorkStealingWorker;
-};
-
 }  // namespace art
 
 #endif  // ART_RUNTIME_THREAD_POOL_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 92c9eb8..09db7cd 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4133,7 +4133,9 @@
                     << " to be compatible with type '" << insn_type
                     << "' but found type '" << *field_type
                     << "' in get-object";
-        work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        if (error != VERIFY_ERROR_BAD_CLASS_HARD) {
+          work_line_->SetRegisterType(this, vregA, reg_types_.Conflict());
+        }
         return;
       }
     }
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index c8aa4fd..1435607 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -585,7 +585,15 @@
   DCHECK(!Equals(incoming_type));  // Trivial equality handled by caller
   // Perform pointer equality tests for conflict to avoid virtual method dispatch.
   const ConflictType& conflict = reg_types->Conflict();
-  if (this == &conflict) {
+  if (IsUndefined() || incoming_type.IsUndefined()) {
+    // There is a difference between undefined and conflict. Conflicts may be copied around, but
+    // not used. Undefined registers must not be copied. So any merge with undefined should return
+    // undefined.
+    if (IsUndefined()) {
+      return *this;
+    }
+    return incoming_type;
+  } else if (this == &conflict) {
     DCHECK(IsConflict());
     return *this;  // Conflict MERGE * => Conflict
   } else if (&incoming_type == &conflict) {
diff --git a/runtime/verifier/register_line-inl.h b/runtime/verifier/register_line-inl.h
index 244deed..9cd2bdf 100644
--- a/runtime/verifier/register_line-inl.h
+++ b/runtime/verifier/register_line-inl.h
@@ -38,10 +38,9 @@
     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
         << new_type << "'";
     return false;
-  } else if (new_type.IsConflict()) {  // should only be set during a merge
-    verifier->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Set register to unknown type " << new_type;
-    return false;
   } else {
+    // Note: previously we failed when asked to set a conflict. However, conflicts are OK as long
+    //       as they are not accessed, and our backends can handle this nowadays.
     line_[vdst] = new_type.GetId();
   }
   // Clear the monitor entry bits for this register.
@@ -93,8 +92,9 @@
   if (!SetRegisterType(verifier, vdst, type)) {
     return;
   }
-  if ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
-      (cat == kTypeCategoryRef && !type.IsReferenceTypes())) {
+  if (!type.IsConflict() &&                                  // Allow conflicts to be copied around.
+      ((cat == kTypeCategory1nr && !type.IsCategory1Types()) ||
+       (cat == kTypeCategoryRef && !type.IsReferenceTypes()))) {
     verifier->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "copy1 v" << vdst << "<-v" << vsrc << " type=" << type
                                                  << " cat=" << static_cast<int>(cat);
   } else if (cat == kTypeCategoryRef) {
diff --git a/test/003-omnibus-opcodes/build b/test/003-omnibus-opcodes/build
index f909fb2..faa2983 100644
--- a/test/003-omnibus-opcodes/build
+++ b/test/003-omnibus-opcodes/build
@@ -22,5 +22,10 @@
 rm classes/UnresClass.class
 ${JAVAC} -d classes `find src2 -name '*.java'`
 
-${DX} -JXmx256m --debug --dex --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+  fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/004-ReferenceMap/build b/test/004-ReferenceMap/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/004-ReferenceMap/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/004-StackWalk/build b/test/004-StackWalk/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/004-StackWalk/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/005-annotations/build b/test/005-annotations/build
index 2474055..3f00a1a 100644
--- a/test/005-annotations/build
+++ b/test/005-annotations/build
@@ -25,4 +25,12 @@
 # ...but not at run time.
 rm 'classes/android/test/anno/MissingAnnotation.class'
 rm 'classes/android/test/anno/ClassWithInnerAnnotationClass$MissingInnerAnnotationClass.class'
-${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
+
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+fi
+
+zip $TEST_NAME.jar classes.dex
diff --git a/test/022-interface/build b/test/022-interface/build
index c86b1dc..3f8915c 100644
--- a/test/022-interface/build
+++ b/test/022-interface/build
@@ -19,5 +19,11 @@
 
 # Use classes that are compiled with ecj that exposes an invokeinterface
 # issue when interfaces override methods in Object
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/023-many-interfaces/build b/test/023-many-interfaces/build
index ad42a2d..3bb6747 100644
--- a/test/023-many-interfaces/build
+++ b/test/023-many-interfaces/build
@@ -21,8 +21,14 @@
 gcc -Wall -Werror -o iface-gen iface-gen.c
 ./iface-gen
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  # Use the default Jack commands
+  ./default-build
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
-zip $TEST_NAME.jar classes.dex
+  # dx needs more memory for that test so do not pass Xmx option here.
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+  zip $TEST_NAME.jar classes.dex
+fi
diff --git a/test/036-finalizer/src/Main.java b/test/036-finalizer/src/Main.java
index 8c7c27d..0de56f9 100644
--- a/test/036-finalizer/src/Main.java
+++ b/test/036-finalizer/src/Main.java
@@ -68,14 +68,17 @@
         return s[0];
     }
 
+    private static void printWeakReference(WeakReference<FinalizerTest> wimp) {
+        // Reference ft so we are sure the WeakReference cannot be cleared.
+        FinalizerTest keepLive = wimp.get();
+        System.out.println("wimp: " + wimpString(wimp));
+    }
+
     public static void main(String[] args) {
         WeakReference<FinalizerTest> wimp = makeRef();
-        FinalizerTest keepLive = wimp.get();
-
-        System.out.println("wimp: " + wimpString(wimp));
+        printWeakReference(wimp);
 
         /* this will try to collect and finalize ft */
-        keepLive = null;
         System.out.println("gc");
         Runtime.getRuntime().gc();
 
diff --git a/test/056-const-string-jumbo/build b/test/056-const-string-jumbo/build
index ef286d1..ae42519 100644
--- a/test/056-const-string-jumbo/build
+++ b/test/056-const-string-jumbo/build
@@ -39,8 +39,13 @@
     printf("}\n") > fileName;
 }'
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes
+  ${DX} -JXmx500m --debug --dex --no-optimize --positions=none --no-locals --output=classes.dex classes
+fi
+
 zip $TEST_NAME.jar classes.dex
diff --git a/test/074-gc-thrash/src/Main.java b/test/074-gc-thrash/src/Main.java
index 238e73a..f947d0b 100644
--- a/test/074-gc-thrash/src/Main.java
+++ b/test/074-gc-thrash/src/Main.java
@@ -218,17 +218,7 @@
             return;
         }
 
-        /*
-         * Check the results of the last trip through.  Everything in
-         * "weak" should be matched in "strong", and the two should be
-         * equivalent (object-wise, not just string-equality-wise).
-         */
-        for (int i = 0; i < MAX_DEPTH; i++) {
-            if (strong[i] != weak[i].get()) {
-                System.err.println("Deep: " + i + " strong=" + strong[i] +
-                    ", weak=" + weak[i].get());
-            }
-        }
+        checkStringReferences();
 
         /*
          * Wipe "strong", do a GC, see if "weak" got collected.
@@ -248,6 +238,26 @@
             System.out.println("Deep: iters=" + iter / MAX_DEPTH);
     }
 
+
+    /**
+     * Check the results of the last trip through.  Everything in
+     * "weak" should be matched in "strong", and the two should be
+     * equivalent (object-wise, not just string-equality-wise).
+     *
+     * We do that check in a separate method to avoid retaining these
+     * String references in local DEX registers. In interpreter mode,
+     * they would retain these references until the end of the method
+     * or until they are updated to another value.
+     */
+    private static void checkStringReferences() {
+      for (int i = 0; i < MAX_DEPTH; i++) {
+          if (strong[i] != weak[i].get()) {
+              System.err.println("Deep: " + i + " strong=" + strong[i] +
+                  ", weak=" + weak[i].get());
+          }
+      }
+    }
+
     /**
      * Recursively dive down, setting one or more local variables.
      *
diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java
index 4dfa73c..177c5a4 100644
--- a/test/082-inline-execute/src/Main.java
+++ b/test/082-inline-execute/src/Main.java
@@ -1000,6 +1000,45 @@
     Assert.assertEquals(Long.reverse(0x8765432187654321L), 0x84c2a6e184c2a6e1L);
     Assert.assertEquals(Long.reverse(Long.MAX_VALUE), 0xfffffffffffffffeL);
     Assert.assertEquals(Long.reverse(Long.MIN_VALUE), 1L);
+
+    Assert.assertEquals(test_Long_reverse_b22324327(0xaaaaaaaaaaaaaaaaL, 0x5555555555555555L),
+            157472205507277347L);
+  }
+
+  // A bit more complicated than the above. Use local variables to stress register allocation.
+  private static long test_Long_reverse_b22324327(long l1, long l2) {
+    // A couple of local integers. Use them in a loop, so they get promoted.
+    int i1 = 0, i2 = 1, i3 = 2, i4 = 3, i5 = 4, i6 = 5, i7 = 6, i8 = 7;
+    for (int k = 0; k < 10; k++) {
+      i1 += 1;
+      i2 += 2;
+      i3 += 3;
+      i4 += 4;
+      i5 += 5;
+      i6 += 6;
+      i7 += 7;
+      i8 += 8;
+    }
+
+    // Do the Long.reverse() calls, save the results.
+    long r1 = Long.reverse(l1);
+    long r2 = Long.reverse(l2);
+
+    // Some more looping with the ints.
+    for (int k = 0; k < 10; k++) {
+      i1 += 1;
+      i2 += 2;
+      i3 += 3;
+      i4 += 4;
+      i5 += 5;
+      i6 += 6;
+      i7 += 7;
+      i8 += 8;
+    }
+
+    // Include everything in the result, so things are kept live. Try to be a little bit clever to
+    // avoid things being folded somewhere.
+    return (r1 / i1) + (r2 / i2) + i3 + i4 + i5 + i6 + i7 + i8;
   }
 
   static Object runtime;
diff --git a/test/085-old-style-inner-class/build b/test/085-old-style-inner-class/build
index 963d6b3..6f50a76 100644
--- a/test/085-old-style-inner-class/build
+++ b/test/085-old-style-inner-class/build
@@ -22,7 +22,12 @@
 mkdir classes
 ${JAVAC} -source 1.4 -target 1.4 -d classes `find src -name '*.java'`
 
-# Suppress stderr to keep the inner class warnings out of the expected output.
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  # Suppress stderr to keep the inner class warnings out of the expected output.
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes 2>/dev/null
+fi
 
 zip $TEST_NAME.jar classes.dex
diff --git a/test/089-many-methods/build b/test/089-many-methods/build
index 7ede759..ff77c60 100644
--- a/test/089-many-methods/build
+++ b/test/089-many-methods/build
@@ -43,7 +43,8 @@
     printf("}\n") > fileName;
 }'
 
+# The test relies on the error message produced by dx, not jack, so keep building with dx for now
+# (b/19467889).
 mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
 ${DX} -JXmx1024m --dex --no-optimize classes
-
diff --git a/test/097-duplicate-method/build b/test/097-duplicate-method/build
index 6576779..a855873 100644
--- a/test/097-duplicate-method/build
+++ b/test/097-duplicate-method/build
@@ -18,8 +18,19 @@
 set -e
 
 mkdir classes
-${JAVAC} -d classes src/*.java
-${JASMIN} -d classes src/*.j
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-jack src.jack src
+
+  ${JASMIN} -d classes src/*.j
+  ${JILL} classes --output jasmin.jack
+
+  # We set jack.import.type.policy=keep-first to consider class definitions from jasmin first.
+  ${JACK} --import jasmin.jack --import src.jack -D jack.import.type.policy=keep-first --output-dex .
+else
+  ${JAVAC} -d classes src/*.java
+  ${JASMIN} -d classes src/*.j
+
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/111-unresolvable-exception/build b/test/111-unresolvable-exception/build
index c21a9ef..e772fb8 100644
--- a/test/111-unresolvable-exception/build
+++ b/test/111-unresolvable-exception/build
@@ -21,5 +21,10 @@
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/TestException.class
 
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/113-multidex/build b/test/113-multidex/build
index ec8706e..8ef5c0e 100644
--- a/test/113-multidex/build
+++ b/test/113-multidex/build
@@ -17,16 +17,32 @@
 # Stop if something fails.
 set -e
 
-mkdir classes
-
 # All except Main
+mkdir classes
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/Main.class
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 
 # Only Main
-${JAVAC} -d classes `find src -name '*.java'`
-rm classes/Second.class classes/FillerA.class classes/FillerB.class classes/Inf*.class
-${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+mkdir classes2
+${JAVAC} -d classes2 `find src -name '*.java'`
+rm classes2/Second.class classes2/FillerA.class classes2/FillerB.class classes2/Inf*.class
 
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes2 --output classes2.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
+  mv classes.dex classes-1.dex
+  ${JACK} --import classes2.jack --output-dex .
+  mv classes.dex classes2.dex
+  mv classes-1.dex classes.dex
+else
+  # All except Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+  # Only Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+fi
 zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/114-ParallelGC/src/Main.java b/test/114-ParallelGC/src/Main.java
index 46029cf..159dd5c 100644
--- a/test/114-ParallelGC/src/Main.java
+++ b/test/114-ParallelGC/src/Main.java
@@ -53,20 +53,21 @@
         }
 
         // Allocate objects to definitely run GC before quitting.
-        ArrayList<Object> l = new ArrayList<Object>();
-        try {
-            for (int i = 0; i < 100000; i++) {
-                l.add(new ArrayList<Object>(i));
-            }
-        } catch (OutOfMemoryError oom) {
-        }
-        // Make the (outer) ArrayList unreachable. Note it may still
-        // be reachable under an interpreter or a compiler without a
-        // liveness analysis.
-        l = null;
+        allocateObjectsToRunGc();
+
         new ArrayList<Object>(50);
     }
 
+    private static void allocateObjectsToRunGc() {
+      ArrayList<Object> l = new ArrayList<Object>();
+      try {
+          for (int i = 0; i < 100000; i++) {
+              l.add(new ArrayList<Object>(i));
+          }
+      } catch (OutOfMemoryError oom) {
+      }
+    }
+
     private Main(CyclicBarrier startBarrier) {
         this.startBarrier = startBarrier;
     }
diff --git a/test/121-modifiers/build b/test/121-modifiers/build
index d73be86..85b69e9 100644
--- a/test/121-modifiers/build
+++ b/test/121-modifiers/build
@@ -30,5 +30,11 @@
 # mv NonInf.out classes/NonInf.class
 # mv Main.class A.class A\$B.class A\$C.class classes/
 
-${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  # Workaround b/19561685: disable sanity checks to produce a DEX file with invalid modifiers.
+  ${JACK} --sanity-checks off --import classes.jack --output-dex .
+else
+  ${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+fi
 zip $TEST_NAME.jar classes.dex
diff --git a/test/124-missing-classes/build b/test/124-missing-classes/build
index 62e57c8..b92ecf9 100644
--- a/test/124-missing-classes/build
+++ b/test/124-missing-classes/build
@@ -25,4 +25,11 @@
 # ...but not at run time.
 rm 'classes/MissingClass.class'
 rm 'classes/Main$MissingInnerClass.class'
-${DX} -JXmx256m --debug --dex --output=$TEST_NAME.jar classes
+
+if [ ${USE_JACK} = "true" ]; then
+  ${JILL} classes --output classes.jack
+  ${JACK} --import classes.jack --output-dex .
+else
+  ${DX} -JXmx256m --debug --dex --output=classes.dex classes
+fi
+zip $TEST_NAME.jar classes.dex
diff --git a/test/126-miranda-multidex/build b/test/126-miranda-multidex/build
index 4c30f3f..b7f2118 100644
--- a/test/126-miranda-multidex/build
+++ b/test/126-miranda-multidex/build
@@ -17,16 +17,32 @@
 # Stop if something fails.
 set -e
 
+# All except MirandaInterface
 mkdir classes
-
-# All except Main
 ${JAVAC} -d classes `find src -name '*.java'`
 rm classes/MirandaInterface.class
-${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
 
-# Only Main
-${JAVAC} -d classes `find src -name '*.java'`
-rm classes/Main.class classes/MirandaAbstract.class classes/MirandaClass*.class classes/MirandaInterface2*.class
-${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes
+# Only MirandaInterface
+mkdir classes2
+${JAVAC} -d classes2 `find src -name '*.java'`
+rm classes2/Main.class classes2/MirandaAbstract.class classes2/MirandaClass*.class classes2/MirandaInterface2*.class
 
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes2 --output classes2.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
+  mv classes.dex classes-1.dex
+  ${JACK} --import classes2.jack --output-dex .
+  mv classes.dex classes2.dex
+  mv classes-1.dex classes.dex
+else
+  # All except Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex classes
+
+  # Only Main
+  ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex classes2
+fi
 zip $TEST_NAME.jar classes.dex classes2.dex
diff --git a/test/127-secondarydex/build b/test/127-secondarydex/build
index 712774f..0d9f4d6 100755
--- a/test/127-secondarydex/build
+++ b/test/127-secondarydex/build
@@ -23,9 +23,21 @@
 mkdir classes-ex
 mv classes/Super.class classes-ex
 
-if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+if [ ${USE_JACK} = "true" ]; then
+  # Create .jack files from classes generated with javac.
+  ${JILL} classes --output classes.jack
+  ${JILL} classes-ex --output classes-ex.jack
+
+  # Create DEX files from .jack files.
+  ${JACK} --import classes.jack --output-dex .
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+  ${JACK} --import classes-ex.jack --output-dex .
   zip ${TEST_NAME}-ex.jar classes.dex
+else
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+    zip $TEST_NAME.jar classes.dex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+    zip ${TEST_NAME}-ex.jar classes.dex
+  fi
 fi
diff --git a/test/131-structural-change/build b/test/131-structural-change/build
index 7ddc81d..ff0da20 100755
--- a/test/131-structural-change/build
+++ b/test/131-structural-change/build
@@ -17,15 +17,23 @@
 # Stop if something fails.
 set -e
 
-mkdir classes
-${JAVAC} -d classes `find src -name '*.java'`
-
-mkdir classes-ex
-${JAVAC} -d classes-ex `find src-ex -name '*.java'`
-
-if [ ${NEED_DEX} = "true" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+if [ ${USE_JACK} = "true" ]; then
+  ${JACK} --output-dex . src
   zip $TEST_NAME.jar classes.dex
-  ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+
+  ${JACK} --output-dex . src-ex
   zip ${TEST_NAME}-ex.jar classes.dex
+else
+  mkdir classes
+  ${JAVAC} -d classes `find src -name '*.java'`
+
+  mkdir classes-ex
+  ${JAVAC} -d classes-ex `find src-ex -name '*.java'`
+
+  if [ ${NEED_DEX} = "true" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex --dump-width=1000 classes
+    zip $TEST_NAME.jar classes.dex
+    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes.dex --dump-width=1000 classes-ex
+    zip ${TEST_NAME}-ex.jar classes.dex
+  fi
 fi
diff --git a/test/303-verification-stress/build b/test/303-verification-stress/build
index 789d38e..5ff73ec 100644
--- a/test/303-verification-stress/build
+++ b/test/303-verification-stress/build
@@ -21,8 +21,14 @@
 gcc -Wall -Werror -o classes-gen classes-gen.c
 ./classes-gen
 
-mkdir classes
-${JAVAC} -d classes src/*.java
+if [ ${USE_JACK} = "true" ]; then
+  # Use the default Jack commands
+  ./default-build
+else
+  mkdir classes
+  ${JAVAC} -d classes src/*.java
 
-${DX} --debug --dex --output=classes.dex classes
-zip $TEST_NAME.jar classes.dex
+  # dx needs more memory for that test so do not pass Xmx option here.
+  ${DX} --debug --dex --output=classes.dex classes
+  zip $TEST_NAME.jar classes.dex
+fi
diff --git a/test/454-get-vreg/build b/test/454-get-vreg/build
new file mode 100644
index 0000000..08987b5
--- /dev/null
+++ b/test/454-get-vreg/build
@@ -0,0 +1,26 @@
+#!/bin/bash
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# The test relies on DEX file produced by javac+dx so keep building with them for now
+# (see b/19467889)
+mkdir classes
+${JAVAC} -d classes `find src -name '*.java'`
+${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+  --dump-width=1000 ${DX_FLAGS} classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java
index a4280de..18125fa 100644
--- a/test/482-checker-loop-back-edge-use/src/Main.java
+++ b/test/482-checker-loop-back-edge-use/src/Main.java
@@ -36,11 +36,11 @@
   }
 
   /// CHECK-START: void Main.loop3(boolean) liveness (after)
-  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,64)} uses:[60,64]
-  /// CHECK:         Goto            liveness:62
+  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,60)} uses:[56,60]
+  /// CHECK:         Goto            liveness:58
 
-  /// CHECK-START: void Main.loop3(boolean) liveness (after)
-  /// CHECK-NOT:     Goto liveness:56
+  // CHECK-START: void Main.loop3(boolean) liveness (after)
+  // CHECK-NOT:     Goto liveness:50
   public static void loop3(boolean incoming) {
     // 'incoming' only needs a use at the outer loop's back edge.
     while (System.currentTimeMillis() != 42) {
@@ -49,11 +49,11 @@
     }
   }
 
-  /// CHECK-START: void Main.loop4(boolean) liveness (after)
-  /// CHECK:         ParameterValue  liveness:4  ranges:{[4,24)} uses:[24]
+  // CHECK-START: void Main.loop4(boolean) liveness (after)
+  // CHECK:         ParameterValue  liveness:4  ranges:{[4,22)} uses:[22]
 
-  /// CHECK-START: void Main.loop4(boolean) liveness (after)
-  /// CHECK-NOT:     Goto            liveness:22
+  // CHECK-START: void Main.loop4(boolean) liveness (after)
+  // CHECK-NOT:     Goto            liveness:18
   public static void loop4(boolean incoming) {
     // 'incoming' has no loop use, so should not have back edge uses.
     System.out.println(incoming);
diff --git a/test/510-checker-try-catch/smali/Builder.smali b/test/510-checker-try-catch/smali/Builder.smali
index 4ea7b61..2274ba4 100644
--- a/test/510-checker-try-catch/smali/Builder.smali
+++ b/test/510-checker-try-catch/smali/Builder.smali
@@ -713,20 +713,20 @@
 ## CHECK-START: int Builder.testSwitchTryExit(int, int, int, int) builder (after)
 
 ## CHECK:  name             "B0"
-## CHECK:  successors       "<<BEnterTry:B\d+>>"
+## CHECK:  successors       "<<BEnterTry1:B\d+>>"
 
 ## CHECK:  name             "<<BPSwitch0:B\d+>>"
-## CHECK:  predecessors     "<<BEnterTry>>"
-## CHECK:  successors       "<<BTry2:B\d+>>" "<<BPSwitch1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BTry2:B\d+>>" "<<BExitTry1:B\d+>>"
 ## CHECK:  If
 
-## CHECK:  name             "<<BPSwitch1>>"
-## CHECK:  predecessors     "<<BPSwitch0>>"
-## CHECK:  successors       "<<BExitTry1:B\d+>>" "<<BTry1:B\d+>>"
+## CHECK:  name             "<<BPSwitch1:B\d+>>"
+## CHECK:  predecessors     "<<BExitTry1>>"
+## CHECK:  successors       "<<BOutside:B\d+>>" "<<BEnterTry2:B\d+>>"
 ## CHECK:  If
 
-## CHECK:  name             "<<BTry1>>"
-## CHECK:  predecessors     "<<BPSwitch1>>"
+## CHECK:  name             "<<BTry1:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2>>"
 ## CHECK:  successors       "<<BTry2>>"
 ## CHECK:  Div
 
@@ -735,28 +735,34 @@
 ## CHECK:  successors       "<<BExitTry2:B\d+>>"
 ## CHECK:  Div
 
-## CHECK:  name             "<<BOutside:B\d+>>"
-## CHECK:  predecessors     "<<BExitTry1>>" "<<BExitTry2>>"
+## CHECK:  name             "<<BOutside>>"
+## CHECK:  predecessors     "<<BPSwitch1>>" "<<BExitTry2>>"
 ## CHECK:  successors       "<<BCatchReturn:B\d+>>"
 ## CHECK:  Div
 
 ## CHECK:  name             "<<BCatchReturn>>"
-## CHECK:  predecessors     "<<BOutside>>" "<<BEnterTry>>" "<<BExitTry1>>" "<<BExitTry2>>"
+## CHECK:  predecessors     "<<BOutside>>" "<<BEnterTry1>>" "<<BExitTry1>>" "<<BEnterTry2>>" "<<BExitTry2>>"
 ## CHECK:  flags            "catch_block"
 ## CHECK:  Return
 
-## CHECK:  name             "<<BEnterTry>>"
+## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "B0"
 ## CHECK:  successors       "<<BPSwitch0>>"
 ## CHECK:  xhandlers        "<<BCatchReturn>>"
 ## CHECK:  TryBoundary      kind:entry
 
 ## CHECK:  name             "<<BExitTry1>>"
-## CHECK:  predecessors     "<<BPSwitch1>>"
-## CHECK:  successors       "<<BOutside>>"
+## CHECK:  predecessors     "<<BPSwitch0>>"
+## CHECK:  successors       "<<BPSwitch1>>"
 ## CHECK:  xhandlers        "<<BCatchReturn>>"
 ## CHECK:  TryBoundary      kind:exit
 
+## CHECK:  name             "<<BEnterTry2>>"
+## CHECK:  predecessors     "<<BPSwitch1>>"
+## CHECK:  successors       "<<BTry1>>"
+## CHECK:  xhandlers        "<<BCatchReturn>>"
+## CHECK:  TryBoundary      kind:entry
+
 ## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
 ## CHECK:  successors       "<<BOutside>>"
@@ -767,6 +773,7 @@
     .registers 4
 
     :try_start
+    div-int/2addr p0, p1
     packed-switch p0, :pswitch_data
 
     div-int/2addr p0, p1
@@ -809,6 +816,10 @@
 ## CHECK:  flags            "catch_block"
 ## CHECK:  StoreLocal       [v0,<<Minus1>>]
 
+## CHECK:  name             "<<BExit>>"
+## CHECK:  predecessors     "<<BExitTry>>" "<<BCatch>>"
+## CHECK:  Exit
+
 ## CHECK:  name             "<<BEnterTry>>"
 ## CHECK:  predecessors     "B0"
 ## CHECK:  successors       "<<BTry>>"
@@ -821,10 +832,6 @@
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
-## CHECK:  name             "<<BExit>>"
-## CHECK:  predecessors     "<<BExitTry>>" "<<BCatch>>"
-## CHECK:  Exit
-
 .method public static testThrow(Ljava/lang/Exception;)I
     .registers 2
 
@@ -852,6 +859,9 @@
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
+
+## CHECK:  name             "<<BExit>>"
 
 ## CHECK:  name             "<<BTry:B\d+>>"
 ## CHECK:  predecessors     "<<BEnterTry>>"
@@ -904,6 +914,14 @@
 ## CHECK:  name             "<<BReturn:B\d+>>"
 ## CHECK:  predecessors     "<<BExitTry2>>"
 
+## CHECK:  name             "{{B\d+}}"
+## CHECK:  Exit
+
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  successors       "<<BExitTry2>>"
+## CHECK:  Div
+
 ## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "B0"
 ## CHECK:  successors       "<<BTry1>>"
@@ -916,11 +934,6 @@
 ## CHECK:  xhandlers        "<<BCatch>>"
 ## CHECK:  TryBoundary      kind:exit
 
-## CHECK:  name             "<<BTry2:B\d+>>"
-## CHECK:  predecessors     "<<BEnterTry2>>"
-## CHECK:  successors       "<<BExitTry2>>"
-## CHECK:  Div
-
 ## CHECK:  name             "<<BEnterTry2>>"
 ## CHECK:  predecessors     "<<BCatch>>"
 ## CHECK:  successors       "<<BTry2>>"
@@ -956,48 +969,51 @@
 ## CHECK:  successors       "<<BCatch1:B\d+>>"
 
 ## CHECK:  name             "<<BCatch1>>"
-## CHECK:  predecessors     "B0" "<<BEnter2:B\d+>>" "<<BExit2:B\d+>>"
-## CHECK:  successors       "<<BEnter1:B\d+>>"
+## CHECK:  predecessors     "B0" "<<BEnterTry2:B\d+>>" "<<BExitTry2:B\d+>>"
+## CHECK:  successors       "<<BEnterTry1:B\d+>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BCatch2:B\d+>>"
-## CHECK:  predecessors     "<<BExit1:B\d+>>" "<<BEnter1>>" "<<BExit1>>"
-## CHECK:  successors       "<<BEnter2>>"
+## CHECK:  predecessors     "<<BExitTry1:B\d+>>" "<<BEnterTry1>>" "<<BExitTry1>>"
+## CHECK:  successors       "<<BEnterTry2>>"
 ## CHECK:  flags            "catch_block"
 
 ## CHECK:  name             "<<BReturn:B\d+>>"
-## CHECK:  predecessors     "<<BExit2>>"
+## CHECK:  predecessors     "<<BExitTry2>>"
+## CHECK:  successors       "<<BExit:B\d+>>"
 ## CHECK:  Return
 
+## CHECK:  name             "<<BExit>>"
+
 ## CHECK:  name             "<<BTry1:B\d+>>"
-## CHECK:  predecessors     "<<BEnter1>>"
-## CHECK:  successors       "<<BExit1>>"
+## CHECK:  predecessors     "<<BEnterTry1>>"
+## CHECK:  successors       "<<BExitTry1>>"
 ## CHECK:  Div
 
-## CHECK:  name             "<<BEnter1>>"
+## CHECK:  name             "<<BTry2:B\d+>>"
+## CHECK:  predecessors     "<<BEnterTry2>>"
+## CHECK:  successors       "<<BExitTry2>>"
+## CHECK:  Div
+
+## CHECK:  name             "<<BEnterTry1>>"
 ## CHECK:  predecessors     "<<BCatch1>>"
 ## CHECK:  successors       "<<BTry1>>"
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:entry
 
-## CHECK:  name             "<<BExit1>>"
+## CHECK:  name             "<<BExitTry1>>"
 ## CHECK:  predecessors     "<<BTry1>>"
 ## CHECK:  successors       "<<BCatch2>>"
 ## CHECK:  xhandlers        "<<BCatch2>>"
 ## CHECK:  TryBoundary      kind:exit
 
-## CHECK:  name             "<<BTry2:B\d+>>"
-## CHECK:  predecessors     "<<BEnter2>>"
-## CHECK:  successors       "<<BExit2>>"
-## CHECK:  Div
-
-## CHECK:  name             "<<BEnter2>>"
+## CHECK:  name             "<<BEnterTry2>>"
 ## CHECK:  predecessors     "<<BCatch2>>"
 ## CHECK:  successors       "<<BTry2>>"
 ## CHECK:  xhandlers        "<<BCatch1>>"
 ## CHECK:  TryBoundary      kind:entry
 
-## CHECK:  name             "<<BExit2>>"
+## CHECK:  name             "<<BExitTry2>>"
 ## CHECK:  predecessors     "<<BTry2>>"
 ## CHECK:  successors       "<<BReturn>>"
 ## CHECK:  xhandlers        "<<BCatch1>>"
@@ -1131,3 +1147,29 @@
     :try_end
     .catchall {:try_start .. :try_end} :catch_all
 .end method
+
+## CHECK-START: int Builder.testSynchronized(java.lang.Object) builder (after)
+## CHECK:      flags "catch_block"
+## CHECK-NOT:  end_block
+## CHECK:      MonitorOperation kind:exit
+
+.method public static testSynchronized(Ljava/lang/Object;)I
+  .registers 2
+
+  monitor-enter p0
+
+  :try_start_9
+  invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I
+  move-result v0
+
+  monitor-exit p0
+  return v0
+
+  :catchall_11
+  move-exception v0
+  monitor-exit p0
+  :try_end_15
+  .catchall {:try_start_9 .. :try_end_15} :catchall_11
+
+  throw v0
+.end method
diff --git a/test/522-checker-regression-monitor-exit/expected.txt b/test/522-checker-regression-monitor-exit/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/expected.txt
diff --git a/test/522-checker-regression-monitor-exit/info.txt b/test/522-checker-regression-monitor-exit/info.txt
new file mode 100644
index 0000000..7cfc963
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/info.txt
@@ -0,0 +1,3 @@
+Regression test for removal of monitor-exit due to lack of specified side-effects.
+The test invokes a synchronized version of Object.hashCode in multiple threads.
+If monitor-exit is removed, the following threads will get stuck and timeout.
\ No newline at end of file
diff --git a/test/522-checker-regression-monitor-exit/smali/Test.smali b/test/522-checker-regression-monitor-exit/smali/Test.smali
new file mode 100644
index 0000000..c8e9198
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/smali/Test.smali
@@ -0,0 +1,40 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LTest;
+
+.super Ljava/lang/Object;
+
+## CHECK-START: int Test.synchronizedHashCode(java.lang.Object) dead_code_elimination (before)
+## CHECK:         MonitorOperation [<<Param:l\d+>>] kind:enter
+## CHECK:         MonitorOperation [<<Param>>]      kind:exit
+
+## CHECK-START: int Test.synchronizedHashCode(java.lang.Object) dead_code_elimination (after)
+## CHECK:         MonitorOperation [<<Param:l\d+>>] kind:enter
+## CHECK:         MonitorOperation [<<Param>>]      kind:exit
+
+.method public static synchronizedHashCode(Ljava/lang/Object;)I
+  .registers 2
+
+  monitor-enter p0
+  invoke-virtual {p0}, Ljava/lang/Object;->hashCode()I
+  move-result v0
+
+  # Must not get removed by DCE.
+  monitor-exit p0
+
+  return v0
+
+.end method
diff --git a/test/522-checker-regression-monitor-exit/src/Main.java b/test/522-checker-regression-monitor-exit/src/Main.java
new file mode 100644
index 0000000..c85ac96
--- /dev/null
+++ b/test/522-checker-regression-monitor-exit/src/Main.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeoutException;
+
+public class Main {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  private static class HashCodeQuery implements Callable<Integer> {
+    public HashCodeQuery(Object obj) {
+      m_obj = obj;
+    }
+
+    public Integer call() {
+      Integer result;
+      try {
+        Class<?> c = Class.forName("Test");
+        Method m = c.getMethod("synchronizedHashCode", new Class[] { Object.class });
+        result = (Integer) m.invoke(null, m_obj);
+      } catch (Exception e) {
+        System.err.println("Hash code query exception");
+        e.printStackTrace();
+        result = -1;
+      }
+      return result;
+    }
+
+    private Object m_obj;
+    private int m_index;
+  }
+
+  public static void main(String args[]) throws Exception {
+    Object obj = new Object();
+    int numThreads = 10;
+
+    ExecutorService pool = Executors.newFixedThreadPool(numThreads);
+
+    List<HashCodeQuery> queries = new ArrayList<HashCodeQuery>(numThreads);
+    for (int i = 0; i < numThreads; ++i) {
+      queries.add(new HashCodeQuery(obj));
+    }
+
+    try {
+      List<Future<Integer>> results = pool.invokeAll(queries, 5, TimeUnit.SECONDS);
+
+      int hash = obj.hashCode();
+      for (int i = 0; i < numThreads; ++i) {
+        int result = results.get(i).get();
+        if (hash != result) {
+          throw new Error("Query #" + i + " wrong. Expected " + hash + ", got " + result);
+        }
+      }
+      pool.shutdown();
+    } catch (CancellationException ex) {
+      System.err.println("Job timeout");
+      System.exit(1);
+    }
+  }
+}
diff --git a/test/523-checker-can-throw-regression/expected.txt b/test/523-checker-can-throw-regression/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/523-checker-can-throw-regression/expected.txt
diff --git a/test/523-checker-can-throw-regression/info.txt b/test/523-checker-can-throw-regression/info.txt
new file mode 100644
index 0000000..720dc85
--- /dev/null
+++ b/test/523-checker-can-throw-regression/info.txt
@@ -0,0 +1,2 @@
+Regression test for the HGraphBuilder which would split a throwing catch block
+but would not update information about which blocks throw.
\ No newline at end of file
diff --git a/test/523-checker-can-throw-regression/smali/Test.smali b/test/523-checker-can-throw-regression/smali/Test.smali
new file mode 100644
index 0000000..87192ea
--- /dev/null
+++ b/test/523-checker-can-throw-regression/smali/Test.smali
@@ -0,0 +1,53 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+.class public LTest;
+
+.super Ljava/lang/Object;
+
+## CHECK-START: int Test.testCase(int, int, int) builder (after)
+## CHECK:         TryBoundary kind:entry
+## CHECK:         TryBoundary kind:entry
+## CHECK-NOT:     TryBoundary kind:entry
+
+## CHECK-START: int Test.testCase(int, int, int) builder (after)
+## CHECK:         TryBoundary kind:exit
+## CHECK:         TryBoundary kind:exit
+## CHECK-NOT:     TryBoundary kind:exit
+
+.method public static testCase(III)I
+  .registers 4
+
+  :try_start_1
+  div-int/2addr p0, p1
+  return p0
+  :try_end_1
+  .catchall {:try_start_1 .. :try_end_1} :catchall
+
+  :catchall
+  :try_start_2
+  move-exception v0
+  # Block would be split here but second part not marked as throwing.
+  div-int/2addr p0, p1
+  if-eqz p2, :else
+
+  div-int/2addr p0, p1
+  :else
+  div-int/2addr p0, p2
+  return p0
+  :try_end_2
+  .catchall {:try_start_2 .. :try_end_2} :catchall
+
+.end method
diff --git a/test/523-checker-can-throw-regression/src/Main.java b/test/523-checker-can-throw-regression/src/Main.java
new file mode 100644
index 0000000..3ff48f3
--- /dev/null
+++ b/test/523-checker-can-throw-regression/src/Main.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.TimeoutException;
+
+public class Main {
+
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String args[]) {}
+}
diff --git a/test/701-easy-div-rem/build b/test/701-easy-div-rem/build
index 1dc8452..666fe89 100644
--- a/test/701-easy-div-rem/build
+++ b/test/701-easy-div-rem/build
@@ -23,6 +23,10 @@
 
 # Increase the file size limitation for classes.lst as the machine generated
 # source file contains a lot of methods and is quite large.
-ulimit -S 4096
+
+# Jack generates big temp files so only apply ulimit for dx.
+if [ ${USE_JACK} = "false" ]; then
+  ulimit -S 4096
+fi
 
 ./default-build
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index fe68c5b..4c17240 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -28,4 +28,7 @@
 b/22080519
 b/21645819
 b/22244733
+b/22331663
+b/22331663 (pass)
+b/22331663 (fail)
 Done!
diff --git a/test/800-smali/smali/b_22331663.smali b/test/800-smali/smali/b_22331663.smali
new file mode 100644
index 0000000..057fc7f
--- /dev/null
+++ b/test/800-smali/smali/b_22331663.smali
@@ -0,0 +1,38 @@
+.class public LB22331663;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       # Make v4 defined, just use null.
+       const v4, 0
+
+       if-eqz v5, :Label2
+
+:Label1
+       # Construct a java.lang.Object completely, and throw a new exception.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+       new-instance v3, Ljava/lang/RuntimeException;
+       invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+       throw v3
+
+:Label2
+       # Allocate a java.lang.Object (do not initialize), and throw a new exception.
+       new-instance v4, Ljava/lang/Object;
+
+       new-instance v3, Ljava/lang/RuntimeException;
+       invoke-direct {v3}, Ljava/lang/RuntimeException;-><init>()V
+       throw v3
+
+:Label3
+       # Catch handler. Here we had to merge the uninitialized with the initialized reference,
+       # which creates a conflict. Copy the conflict, and then return. This should not make the
+       # verifier fail the method.
+       move-object v0, v4
+
+       return-void
+
+.catchall {:Label1 .. :Label3} :Label3
+.end method
diff --git a/test/800-smali/smali/b_22331663_fail.smali b/test/800-smali/smali/b_22331663_fail.smali
new file mode 100644
index 0000000..0c25e30
--- /dev/null
+++ b/test/800-smali/smali/b_22331663_fail.smali
@@ -0,0 +1,20 @@
+.class public LB22331663Fail;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       if-eqz v5, :Label1
+
+       # Construct a java.lang.Object completely. This makes v4 of reference type.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+:Label1
+       # At this point, v4 is the merge of Undefined and ReferenceType. The verifier should
+       # reject any use of this, even a copy. Previously this was a conflict. Conflicts must
+       # be movable now, so ensure that we do not get a conflict (and then allow the move).
+       move-object v0, v4
+
+       return-void
+.end method
diff --git a/test/800-smali/smali/b_22331663_pass.smali b/test/800-smali/smali/b_22331663_pass.smali
new file mode 100644
index 0000000..1b54180
--- /dev/null
+++ b/test/800-smali/smali/b_22331663_pass.smali
@@ -0,0 +1,22 @@
+.class public LB22331663Pass;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       if-eqz v5, :Label1
+
+       # Construct a java.lang.Object completely. This makes v4 of reference type.
+       new-instance v4, Ljava/lang/Object;
+       invoke-direct {v4}, Ljava/lang/Object;-><init>()V
+
+:Label1
+       # At this point, v4 is the merge of Undefined and ReferenceType. The verifier should not
+       # reject this if it is unused.
+
+       # Do an allocation here. This will force heap checking in gcstress mode.
+       new-instance v0, Ljava/lang/Object;
+       invoke-direct {v0}, Ljava/lang/Object;-><init>()V
+
+       return-void
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 61f0d7b..8be6418 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -103,6 +103,12 @@
                 null, null));
         testCases.add(new TestCase("b/22244733", "B22244733", "run", new Object[] { "abc" },
                 null, "abc"));
+        testCases.add(new TestCase("b/22331663", "B22331663", "run", new Object[] { false },
+                null, null));
+        testCases.add(new TestCase("b/22331663 (pass)", "B22331663Pass", "run",
+                new Object[] { false }, null, null));
+        testCases.add(new TestCase("b/22331663 (fail)", "B22331663Fail", "run",
+                new Object[] { false }, new VerifyError(), null));
     }
 
     public void runTests() {
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index c4111f6..c18bb5c 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -33,22 +33,46 @@
 TEST_ART_RUN_TEST_BUILD_RULES :=
 
 # Dependencies for actually running a run-test.
-TEST_ART_RUN_TEST_DEPENDENCIES := $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger
+TEST_ART_RUN_TEST_DEPENDENCIES := \
+  $(DX) \
+  $(HOST_OUT_EXECUTABLES)/jasmin \
+  $(HOST_OUT_EXECUTABLES)/smali \
+  $(HOST_OUT_EXECUTABLES)/dexmerger
+
+ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+  TEST_ART_RUN_TEST_DEPENDENCIES += \
+    $(JACK_JAR) \
+    $(JACK_LAUNCHER_JAR) \
+    $(JILL_JAR)
+endif
 
 # Helper to create individual build targets for tests. Must be called with $(eval).
 # $(1): the test number
 define define-build-art-run-test
   dmart_target := $(art_run_tests_dir)/art-run-tests/$(1)/touch
+  run_test_options = --build-only
+  ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+    run_test_options += --build-with-jack
+  else
+    run_test_options += --build-with-javac-dx
+  endif
+$$(dmart_target): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
 $$(dmart_target): $(TEST_ART_RUN_TEST_DEPENDENCIES)
 	$(hide) rm -rf $$(dir $$@) && mkdir -p $$(dir $$@)
 	$(hide) DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
 	  SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
 	  DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
-	  $(LOCAL_PATH)/run-test --build-only --output-path $$(abspath $$(dir $$@)) $(1)
+	  JACK=$(abspath $(JACK)) \
+	  JACK_VM_COMMAND="$(JACK_VM) $(DEFAULT_JACK_VM_ARGS) $(JAVA_TMPDIR_ARG) -jar $(abspath $(JACK_LAUNCHER_JAR)) " \
+	  JACK_CLASSPATH=$(TARGET_JACK_CLASSPATH) \
+	  JACK_JAR=$(abspath $(JACK_JAR)) \
+	  JILL_JAR=$(abspath $(JILL_JAR)) \
+	  $(LOCAL_PATH)/run-test $$(PRIVATE_RUN_TEST_OPTIONS) --output-path $$(abspath $$(dir $$@)) $(1)
 	$(hide) touch $$@
 
   TEST_ART_RUN_TEST_BUILD_RULES += $$(dmart_target)
   dmart_target :=
+  run_test_options :=
 endef
 $(foreach test, $(TEST_ART_RUN_TESTS), $(eval $(call define-build-art-run-test,$(test))))
 
@@ -599,6 +623,12 @@
   prereq_rule :=
   test_groups :=
   uc_host_or_target :=
+  jack_classpath :=
+  ifeq ($(ANDROID_COMPILE_WITH_JACK),true)
+    run_test_options += --build-with-jack
+  else
+    run_test_options += --build-with-javac-dx
+  endif
   ifeq ($(ART_TEST_RUN_TEST_ALWAYS_CLEAN),true)
     run_test_options += --always-clean
   endif
@@ -607,11 +637,13 @@
     test_groups := ART_RUN_TEST_HOST_RULES
     run_test_options += --host
     prereq_rule := $(ART_TEST_HOST_RUN_TEST_DEPENDENCIES)
+    jack_classpath := $(HOST_JACK_CLASSPATH)
   else
     ifeq ($(1),target)
       uc_host_or_target := TARGET
       test_groups := ART_RUN_TEST_TARGET_RULES
       prereq_rule := test-art-target-sync
+      jack_classpath := $(TARGET_JACK_CLASSPATH)
     else
       $$(error found $(1) expected $(TARGET_TYPES))
     endif
@@ -806,12 +838,19 @@
     run_test_options := --android-root $(ART_TEST_ANDROID_ROOT) $$(run_test_options)
   endif
 $$(run_test_rule_name): PRIVATE_RUN_TEST_OPTIONS := $$(run_test_options)
+$$(run_test_rule_name): PRIVATE_JACK_CLASSPATH := $$(jack_classpath)
 .PHONY: $$(run_test_rule_name)
-$$(run_test_rule_name): $(DX) $(HOST_OUT_EXECUTABLES)/jasmin $(HOST_OUT_EXECUTABLES)/smali $(HOST_OUT_EXECUTABLES)/dexmerger $(HOST_OUT_EXECUTABLES)/hprof-conv $$(prereq_rule)
+$$(run_test_rule_name): $(TEST_ART_RUN_TEST_DEPENDENCIES) $(HOST_OUT_EXECUTABLES)/hprof-conv $$(prereq_rule)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  DX=$(abspath $(DX)) JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
+	  DX=$(abspath $(DX)) \
+	    JASMIN=$(abspath $(HOST_OUT_EXECUTABLES)/jasmin) \
 	    SMALI=$(abspath $(HOST_OUT_EXECUTABLES)/smali) \
 	    DXMERGER=$(abspath $(HOST_OUT_EXECUTABLES)/dexmerger) \
+	    JACK=$(abspath $(JACK)) \
+	    JACK_VM_COMMAND="$(JACK_VM) $(DEFAULT_JACK_VM_ARGS) $(JAVA_TMPDIR_ARG) -jar $(abspath $(JACK_LAUNCHER_JAR)) " \
+	    JACK_CLASSPATH=$$(PRIVATE_JACK_CLASSPATH) \
+	    JACK_JAR=$(abspath $(JACK_JAR)) \
+	    JILL_JAR=$(abspath $(JILL_JAR)) \
 	    art/test/run-test $$(PRIVATE_RUN_TEST_OPTIONS) $(12) \
 	      && $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
 	$$(hide) (echo $(MAKECMDGOALS) | grep -q $$@ && \
@@ -826,6 +865,7 @@
   run_test_options :=
   run_test_rule_name :=
   prereq_rule :=
+  jack_classpath :=
 endef  # define-test-art-run-test
 
 $(foreach target, $(TARGET_TYPES), \
diff --git a/test/dexdump/bytecodes.lst b/test/dexdump/bytecodes.lst
new file mode 100644
index 0000000..aeda7b4
--- /dev/null
+++ b/test/dexdump/bytecodes.lst
@@ -0,0 +1,20 @@
+#bytecodes.dex
+0x000009a0 8 com.google.android.test.BuildConfig <init> ()V BuildConfig.java 4
+0x000009b8 8 com.google.android.test.R$attr <init> ()V R.java 11
+0x000009d0 8 com.google.android.test.R$drawable <init> ()V R.java 13
+0x000009e8 8 com.google.android.test.R <init> ()V R.java 10
+0x00000a00 148 com.google.android.test.Test <clinit> ()V Test.java 7
+0x00000aa4 468 com.google.android.test.Test <init> ()V Test.java 43
+0x00000ca4 478 com.google.android.test.Test add (Ljava/lang/Object;)Ljava/lang/Object; Test.java 179
+0x00000ea0 236 com.google.android.test.Test adds (Ljava/lang/Object;)Ljava/lang/Object; Test.java 201
+0x00000f9c 342 com.google.android.test.Test copies ()V Test.java 216
+0x00001104 156 com.google.android.test.Test doit (I)V Test.java 98
+0x000011b0 146 com.google.android.test.Test geta ()Z Test.java 72
+0x00001254 38 com.google.android.test.Test p (I)V Test.java 120
+0x0000128c 636 com.google.android.test.Test params (BCSIJFDLjava/lang/Object;[I)J Test.java 232
+0x00001518 170 com.google.android.test.Test q (II)V Test.java 127
+0x000015d4 186 com.google.android.test.Test r (II)I Test.java 139
+0x000016a0 388 com.google.android.test.Test s (JJ)J Test.java 159
+0x00001834 96 com.google.android.test.Test seta ()V Test.java 60
+0x000018a4 14 com.google.android.test.Test onStart ()V Test.java 86
+0x000018c4 18 com.google.android.test.Test run ()V Test.java 92
diff --git a/test/dexdump/checkers.lst b/test/dexdump/checkers.lst
new file mode 100644
index 0000000..daef138
--- /dev/null
+++ b/test/dexdump/checkers.lst
@@ -0,0 +1,82 @@
+#checkers.dex
+0x0000149c 8 com.google.android.checkers.Checkers <init> ()V (none) -1
+0x000014b4 66 com.google.android.checkers.Checkers a (Z)V (none) -1
+0x00001508 8 com.google.android.checkers.Checkers onConfigurationChanged (Landroid/content/res/Configuration;)V (none) -1
+0x00001520 118 com.google.android.checkers.Checkers onCreate (Landroid/os/Bundle;)V (none) -1
+0x000015a8 432 com.google.android.checkers.Checkers onCreateOptionsMenu (Landroid/view/Menu;)Z (none) -1
+0x00001768 116 com.google.android.checkers.Checkers onKeyDown (ILandroid/view/KeyEvent;)Z (none) -1
+0x000017ec 316 com.google.android.checkers.Checkers onOptionsItemSelected (Landroid/view/MenuItem;)Z (none) -1
+0x00001938 42 com.google.android.checkers.Checkers onPause ()V (none) -1
+0x00001974 16 com.google.android.checkers.Checkers onStop ()V (none) -1
+0x00001994 88 com.google.android.checkers.Checkers onTrackballEvent (Landroid/view/MotionEvent;)Z (none) -1
+0x000019fc 1324 com.google.android.checkers.CheckersView <init> (Landroid/content/Context;Landroid/content/SharedPreferences;)V (none) -1
+0x00001f48 62 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences$Editor;Ljava/lang/String;[I)V (none) -1
+0x00001f98 66 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences;Ljava/lang/String;[I)V (none) -1
+0x00001fec 126 com.google.android.checkers.CheckersView a (Landroid/graphics/Canvas;IIII)V (none) -1
+0x0000207c 162 com.google.android.checkers.CheckersView a (Landroid/graphics/Canvas;IIIILandroid/graphics/Paint;Landroid/graphics/Paint;Z)V (none) -1
+0x00002130 8 com.google.android.checkers.CheckersView a (Lcom/google/android/checkers/CheckersView;I)V (none) -1
+0x00002148 588 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences;)Z (none) -1
+0x000023d0 22 com.google.android.checkers.CheckersView a (Lcom/google/android/checkers/CheckersView;)Z (none) -1
+0x000023f8 1290 com.google.android.checkers.CheckersView a (ZIIII)Z (none) -1
+0x00002930 204 com.google.android.checkers.CheckersView b (FF)I (none) -1
+0x00002a20 36 com.google.android.checkers.CheckersView b (I)V (none) -1
+0x00002a60 198 com.google.android.checkers.CheckersView b (Landroid/graphics/Canvas;IIII)V (none) -1
+0x00002b38 524 com.google.android.checkers.CheckersView c (I)V (none) -1
+0x00002d54 176 com.google.android.checkers.CheckersView d ()V (none) -1
+0x00002e14 20 com.google.android.checkers.CheckersView e ()Z (none) -1
+0x00002e38 128 com.google.android.checkers.CheckersView a ()V (none) -1
+0x00002ec8 226 com.google.android.checkers.CheckersView a (FF)V (none) -1
+0x00002fd8 32 com.google.android.checkers.CheckersView a (IIII)V (none) -1
+0x00003008 340 com.google.android.checkers.CheckersView a (Landroid/content/SharedPreferences$Editor;)V (none) -1
+0x00003178 34 com.google.android.checkers.CheckersView a (I)Z (none) -1
+0x000031ac 44 com.google.android.checkers.CheckersView a (Z)Z (none) -1
+0x000031f4 60 com.google.android.checkers.CheckersView b ()V (none) -1
+0x0000324c 138 com.google.android.checkers.CheckersView b (Z)Z (none) -1
+0x000032f4 16 com.google.android.checkers.CheckersView c ()I (none) -1
+0x00003320 68 com.google.android.checkers.CheckersView c (Z)Z (none) -1
+0x00003380 38 com.google.android.checkers.CheckersView d (Z)Z (none) -1
+0x000033c4 2528 com.google.android.checkers.CheckersView draw (Landroid/graphics/Canvas;)V (none) -1
+0x00003dd0 38 com.google.android.checkers.CheckersView e (Z)Z (none) -1
+0x00003e14 104 com.google.android.checkers.CheckersView onSizeChanged (IIII)V (none) -1
+0x00003e98 82 com.google.android.checkers.CheckersView onTouchEvent (Landroid/view/MotionEvent;)Z (none) -1
+0x00003efc 128 com.google.android.checkers.CheckersView setLevel (I)V (none) -1
+0x00003f98 2780 com.google.android.checkers.a <clinit> ()V (none) -1
+0x00004a84 188 com.google.android.checkers.a <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x00004b5c 28 com.google.android.checkers.a a (II)I (none) -1
+0x00004b88 2592 com.google.android.checkers.a a (IIIIIZ)I (none) -1
+0x000055b8 110 com.google.android.checkers.a a (IZ)I (none) -1
+0x00005638 196 com.google.android.checkers.a a (Z)I (none) -1
+0x0000570c 112 com.google.android.checkers.a a (ZII)I (none) -1
+0x0000578c 88 com.google.android.checkers.a a (ZIIIZ)I (none) -1
+0x000057f4 68 com.google.android.checkers.a a (ZIIZ)I (none) -1
+0x00005848 152 com.google.android.checkers.a a (IIII)V (none) -1
+0x000058f0 78 com.google.android.checkers.a a (IIIII)V (none) -1
+0x00005950 198 com.google.android.checkers.a a (IIIIIIII)V (none) -1
+0x00005a28 1750 com.google.android.checkers.a a (IZI)Z (none) -1
+0x00006110 92 com.google.android.checkers.a b (ZIIIZ)I (none) -1
+0x0000617c 112 com.google.android.checkers.a b (ZIIZ)I (none) -1
+0x000061fc 38 com.google.android.checkers.a b ()V (none) -1
+0x0000624c 736 com.google.android.checkers.a b (I)V (none) -1
+0x0000653c 198 com.google.android.checkers.a b (IIIIIIII)V (none) -1
+0x00006614 922 com.google.android.checkers.a b (IZI)Z (none) -1
+0x000069c0 108 com.google.android.checkers.a c (ZIIZ)I (none) -1
+0x00006a3c 16 com.google.android.checkers.a c ()V (none) -1
+0x00006a68 406 com.google.android.checkers.a c (IIIIIIII)V (none) -1
+0x00006c10 112 com.google.android.checkers.a d (ZIIZ)I (none) -1
+0x00006c90 16 com.google.android.checkers.a a (ZZ)I (none) -1
+0x00006cb0 90 com.google.android.checkers.a a ()V (none) -1
+0x00006d1c 8 com.google.android.checkers.a a (I)V (none) -1
+0x00006d34 74 com.google.android.checkers.a a (IIIIZ)V (none) -1
+0x00006d90 32 com.google.android.checkers.a b (ZZ)V (none) -1
+0x00006dcc 1052 com.google.android.checkers.a run ()V (none) -1
+0x000071f8 12 com.google.android.checkers.b <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x00007214 28 com.google.android.checkers.b onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x00007240 12 com.google.android.checkers.c <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x0000725c 2 com.google.android.checkers.c onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x00007270 12 com.google.android.checkers.d <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x0000728c 2 com.google.android.checkers.d onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x000072a0 12 com.google.android.checkers.e <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x000072bc 14 com.google.android.checkers.e onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x000072dc 12 com.google.android.checkers.f <init> (Lcom/google/android/checkers/CheckersView;)V (none) -1
+0x000072f8 12 com.google.android.checkers.f onClick (Landroid/content/DialogInterface;I)V (none) -1
+0x00007314 58 com.google.android.checkers.g a ([B)Z (none) -1
diff --git a/test/dexdump/run-all-tests b/test/dexdump/run-all-tests
index f5d8cd6..d9f1e96 100755
--- a/test/dexdump/run-all-tests
+++ b/test/dexdump/run-all-tests
@@ -37,10 +37,14 @@
 tmpdir=/tmp/test-$$
 mkdir ${tmpdir}
 
-# Set up binary and flags to test.
+# Set up dexdump binary and flags to test.
 DEXD="${ANDROID_HOST_OUT}/bin/dexdump2"
-FLAGS1="-dfh"
-FLAGS2="-l xml"
+DEXDFLAGS1="-dfh"
+DEXDFLAGS2="-l xml"
+
+# Set up dexlist binary and flags to test.
+DEXL="${ANDROID_HOST_OUT}/bin/dexlist2"
+DEXLFLAGS=""
 
 # Run the tests.
 passed=0
@@ -50,18 +54,28 @@
     basenm=`basename "${i}" .dex`
     txtfile=${basenm}.txt
     xmlfile=${basenm}.xml
-    genfile1=${tmpdir}/${txtfile}
-    genfile2=${tmpdir}/${xmlfile}
-    ${DEXD} ${FLAGS1} ${i} > ${genfile1}
-    cmp ${txtfile} ${genfile1}
+    lstfile=${basenm}.lst
+    gentxtfile=${tmpdir}/${txtfile}
+    genxmlfile=${tmpdir}/${xmlfile}
+    genlstfile=${tmpdir}/${lstfile}
+    ${DEXD} ${DEXDFLAGS1} ${i} > ${gentxtfile}
+    cmp ${txtfile} ${gentxtfile}
     if [ "$?" = "0" ]; then
         ((passed += 1))
     else
         ((failed += 1))
         echo failed: ${i}
     fi
-    ${DEXD} ${FLAGS2} ${i} > ${genfile2}
-    cmp ${xmlfile} ${genfile2}
+    ${DEXD} ${DEXDFLAGS2} ${i} > ${genxmlfile}
+    cmp ${xmlfile} ${genxmlfile}
+    if [ "$?" = "0" ]; then
+        ((passed += 1))
+    else
+        ((failed += 1))
+        echo failed: ${i}
+    fi
+    ${DEXL} ${DEXLFLAGS} ${i} > ${genlstfile}
+    cmp ${lstfile} ${genlstfile}
     if [ "$?" = "0" ]; then
         ((passed += 1))
     else
@@ -77,7 +91,7 @@
 echo
 
 # Clean up, cd back to original dir.
-#rm -rf ${tmpdir}
+rm -rf ${tmpdir}
 cd ${oldwd}
 
 # Return status.
diff --git a/test/etc/default-build b/test/etc/default-build
index 92954a9..c281bca 100755
--- a/test/etc/default-build
+++ b/test/etc/default-build
@@ -39,24 +39,57 @@
   exit 0
 fi
 
-if [ -d src ]; then
-  mkdir classes
-  ${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
-fi
-
-if [ -d src2 ]; then
-  mkdir -p classes
-  ${JAVAC} -d classes `find src2 -name '*.java'`
-fi
-
 if ! [ -d src ] && ! [ -d src2 ]; then
   # No src directory? Then forget about trying to run dx.
   SKIP_DX_MERGER="true"
 fi
 
-if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
-  ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
-    --dump-width=1000 ${DX_FLAGS} classes
+if [ -d src-multidex ]; then
+  # Jack does not support this configuration unless we specify how to partition the DEX file
+  # with a .jpp file.
+  USE_JACK="false"
+fi
+
+if [ ${USE_JACK} = "true" ]; then
+  # Jack toolchain
+  if [ -d src ]; then
+    ${JACK} --output-jack src.jack src
+    imported_jack_files="--import src.jack"
+  fi
+
+  if [ -d src2 ]; then
+    ${JACK} --output-jack src2.jack src2
+    imported_jack_files="--import src2.jack ${imported_jack_files}"
+  fi
+
+  # Compile jack files into a DEX file. We set jack.import.type.policy=keep-first to consider
+  # class definitions from src2 first.
+  ${JACK} ${imported_jack_files} -D jack.import.type.policy=keep-first --output-dex .
+else
+  # Legacy toolchain with javac+dx
+  if [ -d src ]; then
+    mkdir classes
+    ${JAVAC} -implicit:none -classpath src-multidex -d classes `find src -name '*.java'`
+  fi
+
+  if [ -d src-multidex ]; then
+    mkdir classes2
+    ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
+    if [ ${NEED_DEX} = "true" ]; then
+      ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
+        --dump-width=1000 ${DX_FLAGS} classes2
+    fi
+  fi
+
+  if [ -d src2 ]; then
+    mkdir -p classes
+    ${JAVAC} -d classes `find src2 -name '*.java'`
+  fi
+
+  if [ ${NEED_DEX} = "true" -a ${SKIP_DX_MERGER} = "false" ]; then
+    ${DX} -JXmx256m --debug --dex --dump-to=classes.lst --output=classes.dex \
+      --dump-width=1000 ${DX_FLAGS} classes
+  fi
 fi
 
 if [ -d smali ]; then
@@ -72,30 +105,34 @@
 fi
 
 if [ -d src-ex ]; then
-  mkdir classes-ex
-  ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
-      --dump-width=1000 ${DX_FLAGS} classes-ex
+  if [ ${USE_JACK} = "true" ]; then
+      # Rename previous "classes.dex" so it is not overwritten.
+      mv classes.dex classes-1.dex
+      #TODO find another way to append src.jack to the jack classpath
+      ${JACK}:src.jack --output-dex . src-ex
+      zip $TEST_NAME-ex.jar classes.dex
+      # Restore previous "classes.dex" so it can be zipped.
+      mv classes-1.dex classes.dex
+  else
+    mkdir classes-ex
+    ${JAVAC} -d classes-ex -cp classes `find src-ex -name '*.java'`
+    if [ ${NEED_DEX} = "true" ]; then
+      ${DX} -JXmx256m --debug --dex --dump-to=classes-ex.lst --output=classes-ex.dex \
+        --dump-width=1000 ${DX_FLAGS} classes-ex
 
-    # quick shuffle so that the stored name is "classes.dex"
-    mv classes.dex classes-1.dex
-    mv classes-ex.dex classes.dex
-    zip $TEST_NAME-ex.jar classes.dex
-    mv classes.dex classes-ex.dex
-    mv classes-1.dex classes.dex
+      # quick shuffle so that the stored name is "classes.dex"
+      mv classes.dex classes-1.dex
+      mv classes-ex.dex classes.dex
+      zip $TEST_NAME-ex.jar classes.dex
+      mv classes.dex classes-ex.dex
+      mv classes-1.dex classes.dex
+    fi
   fi
 fi
 
 # Create a single jar with two dex files for multidex.
 if [ -d src-multidex ]; then
-  mkdir classes2
-  ${JAVAC} -implicit:none -classpath src -d classes2 `find src-multidex -name '*.java'`
-  if [ ${NEED_DEX} = "true" ]; then
-    ${DX} -JXmx256m --debug --dex --dump-to=classes2.lst --output=classes2.dex \
-      --dump-width=1000 ${DX_FLAGS} classes2
-    zip $TEST_NAME.jar classes.dex classes2.dex
-  fi
+  zip $TEST_NAME.jar classes.dex classes2.dex
 elif [ ${NEED_DEX} = "true" ]; then
   zip $TEST_NAME.jar classes.dex
 fi
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index cf6be83..842d87e 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -458,7 +458,9 @@
       # When running under gdb, we cannot do piping and grepping...
       $cmdline "$@"
     else
-      $cmdline "$@" 2>&1
+      trap 'kill -INT -$pid' INT
+      $cmdline "$@" 2>&1 & pid=$!
+      wait $pid
       # Add extra detail if time out is enabled.
       if [ ${PIPESTATUS[0]} = 124 ] && [ "$TIME_OUT" = "y" ]; then
         echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2
diff --git a/test/run-test b/test/run-test
index ffa25eb..f5fff09a 100755
--- a/test/run-test
+++ b/test/run-test
@@ -46,6 +46,7 @@
 export RUN="${progdir}/etc/run-test-jar"
 export DEX_LOCATION=/data/run-test/${test_dir}
 export NEED_DEX="true"
+export USE_JACK="false"
 
 # If dx was not set by the environment variable, assume it is in the path.
 if [ -z "$DX" ]; then
@@ -67,6 +68,46 @@
   export DXMERGER="dexmerger"
 fi
 
+# If jack was not set by the environment variable, assume it is in the path.
+if [ -z "$JACK" ]; then
+  export JACK="jack"
+fi
+
+# If the tree is compiled with Jack, build test with Jack by default.
+if [ "$ANDROID_COMPILE_WITH_JACK" = "true" ]; then
+  USE_JACK="true"
+fi
+
+# ANDROID_BUILD_TOP is not set in a build environment.
+if [ -z "$ANDROID_BUILD_TOP" ]; then
+    export ANDROID_BUILD_TOP=$oldwd
+fi
+
+# If JACK_VM_COMMAND is not set, assume it launches the prebuilt jack-launcher.
+if [ -z "$JACK_VM_COMMAND" ]; then
+  if [ ! -z "$TMPDIR" ]; then
+    jack_temp_dir="-Djava.io.tmpdir=$TMPDIR"
+  fi
+  export JACK_VM_COMMAND="java -Dfile.encoding=UTF-8 -Xms2560m -XX:+TieredCompilation $jack_temp_dir -jar $ANDROID_BUILD_TOP/prebuilts/sdk/tools/jack-launcher.jar"
+fi
+
+# If JACK_CLASSPATH is not set, assume it only contains core-libart.
+if [ -z "$JACK_CLASSPATH" ]; then
+  export JACK_CLASSPATH="$ANDROID_BUILD_TOP/out/host/common/obj/JAVA_LIBRARIES/core-libart-hostdex_intermediates/classes.jack"
+fi
+
+# If JACK_JAR is not set, assume it is located in the prebuilts directory.
+if [ -z "$JACK_JAR" ]; then
+  export JACK_JAR="$ANDROID_BUILD_TOP/prebuilts/sdk/tools/jack.jar"
+fi
+
+# If JILL_JAR is not set, assume it is located in the prebuilts directory.
+if [ -z "$JILL_JAR" ]; then
+  export JILL_JAR="$ANDROID_BUILD_TOP/prebuilts/sdk/tools/jill.jar"
+fi
+
+export JACK="$JACK -g -cp $JACK_CLASSPATH"
+export JILL="java -jar $JILL_JAR"
 
 info="info.txt"
 build="build"
@@ -116,6 +157,7 @@
         runtime="jvm"
         prebuild_mode="no"
         NEED_DEX="false"
+        USE_JACK="false"
         run_args="${run_args} --jvm"
         shift
     elif [ "x$1" = "x-O" ]; then
@@ -237,6 +279,12 @@
     elif [ "x$1" = "x--build-only" ]; then
         build_only="yes"
         shift
+    elif [ "x$1" = "x--build-with-javac-dx" ]; then
+        USE_JACK="false"
+        shift
+    elif [ "x$1" = "x--build-with-jack" ]; then
+        USE_JACK="true"
+        shift
     elif [ "x$1" = "x--output-path" ]; then
         shift
         tmp_dir=$1
@@ -369,10 +417,7 @@
     fi
 elif [ "$runtime" = "art" ]; then
     if [ "$target_mode" = "no" ]; then
-        # ANDROID_BUILD_TOP and ANDROID_HOST_OUT are not set in a build environment.
-        if [ -z "$ANDROID_BUILD_TOP" ]; then
-            export ANDROID_BUILD_TOP=$oldwd
-        fi
+        # ANDROID_HOST_OUT is not set in a build environment.
         if [ -z "$ANDROID_HOST_OUT" ]; then
             export ANDROID_HOST_OUT=$ANDROID_BUILD_TOP/out/host/linux-x86
         fi
@@ -462,6 +507,8 @@
         echo "    --debuggable          Whether to compile Java code for a debugger."
         echo "    --gdb                 Run under gdb; incompatible with some tests."
         echo "    --build-only          Build test files only (off by default)."
+        echo "    --build-with-javac-dx Build test files with javac and dx (on by default)."
+        echo "    --build-with-jack     Build test files with jack and jill (off by default)."
         echo "    --interpreter         Enable interpreter only mode (off by default)."
         echo "    --jit                 Enable jit (off by default)."
         echo "    --optimizing          Enable optimizing compiler (default)."
@@ -556,6 +603,10 @@
   # if Checker is not invoked and the test only runs the program.
   build_args="${build_args} --dx-option --no-optimize"
 
+  # Jack does not necessarily generate the same DEX output than dx. Because these tests depend
+  # on a particular DEX output, keep building them with dx for now (b/19467889).
+  USE_JACK="false"
+
   if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$target_mode" = "no" -a "$debuggable" = "no" ]; then
     run_checker="yes"
     run_args="${run_args} -Xcompiler-option --dump-cfg=$tmp_dir/$cfg_output \
@@ -564,14 +615,20 @@
 fi
 
 # To cause tests to fail fast, limit the file sizes created by dx, dex2oat and ART output to 2MB.
-file_size_limit=2048
+build_file_size_limit=2048
+run_file_size_limit=2048
 if echo "$test_dir" | grep 089; then
-  file_size_limit=5120
+  build_file_size_limit=5120
+  run_file_size_limit=5120
 elif echo "$test_dir" | grep 083; then
-  file_size_limit=5120
+  build_file_size_limit=5120
+  run_file_size_limit=5120
 fi
-if ! ulimit -S "$file_size_limit"; then
-   echo "ulimit file size setting failed"
+if [ ${USE_JACK} = "false" ]; then
+  # Set ulimit if we build with dx only, Jack can generate big temp files.
+  if ! ulimit -S "$build_file_size_limit"; then
+    echo "ulimit file size setting failed"
+  fi
 fi
 
 good="no"
@@ -582,6 +639,9 @@
     build_exit="$?"
     echo "build exit status: $build_exit" 1>&2
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" 2>&1
         run_exit="$?"
@@ -604,6 +664,9 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         if [ "$run_checker" = "yes" ]; then
@@ -635,6 +698,9 @@
     "./${build}" $build_args >"$build_output" 2>&1
     build_exit="$?"
     if [ "$build_exit" = '0' ]; then
+        if ! ulimit -S "$run_file_size_limit"; then
+          echo "ulimit file size setting failed"
+        fi
         echo "${test_dir}: running..." 1>&2
         "./${run}" $run_args "$@" >"$output" 2>&1
         run_exit="$?"
diff --git a/tools/symbolize.sh b/tools/symbolize.sh
index 7365a9b..f5686e6 100755
--- a/tools/symbolize.sh
+++ b/tools/symbolize.sh
@@ -22,6 +22,7 @@
 INTERACTIVE="no"
 if [ "x$1" = "x--interactive" ] ; then
   INTERACTIVE="yes"
+  shift
 fi
 
 # Pull the file from the device and symbolize it.
@@ -57,4 +58,15 @@
   done
 }
 
-all
+if [ "x$1" = "x" ] ; then
+  # No further arguments, iterate over all oat files on device.
+  all
+else
+  # Take the parameters as a list of paths on device.
+  while (($#)); do
+    DIR=$(dirname $1)
+    NAME=$(basename $1)
+    one $DIR $NAME
+    shift
+  done
+fi