Merge "Support compiling run-tests with jack"
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.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/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 8551382..bb1b40a 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,30 +333,37 @@
     return;
   }
 
+  const size_t num_blocks = graph_->GetBlocks().Size();
+  ArenaBitVector can_block_throw(arena_, num_blocks, false);
+
+  // Scan blocks and mark those which contain throwing instructions.
+  for (size_t block_id = 0; block_id < num_blocks; ++block_id) {
+    HBasicBlock* block = graph_->GetBlocks().Get(block_id);
+    for (HInstructionIterator insn(block->GetInstructions()); !insn.Done(); insn.Advance()) {
+      if (insn.Current()->CanThrow()) {
+        can_block_throw.SetBit(block_id);
+        break;
+      }
+    }
+  }
+
   // 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; block_id < num_blocks; ++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
@@ -373,7 +386,7 @@
       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);
+      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
@@ -385,12 +398,14 @@
           // 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(!IsBlockInPcRange(predecessor->GetSinglePredecessor(), try_start, try_end));
+            DCHECK_NE(try_item, predecessor_try_item);
           }
-        } else if (!IsBlockInPcRange(predecessor, try_start, try_end)) {
+        } 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
@@ -399,7 +414,7 @@
           // Not an edge on the boundary of the try block.
           continue;
         }
-        SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, try_item);
+        SplitTryBoundaryEdge(predecessor, try_block, HTryBoundary::kEntry, code_item, *try_item);
       }
     }
 
@@ -416,11 +431,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 +454,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 +513,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;
 }
 
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index e487255..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);
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/nodes.h b/compiler/optimizing/nodes.h
index e4a7aa6..59255d1 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -4131,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/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/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/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/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/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index c7d2e9f..5e69b79 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -334,6 +334,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 +353,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/heap.cc b/runtime/gc/heap.cc
index 1b45ea1..a782fc8 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -3734,17 +3734,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..cfb6e06 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -721,10 +721,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;
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/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/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/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/510-checker-try-catch/smali/Builder.smali b/test/510-checker-try-catch/smali/Builder.smali
index 4ea7b61..87e4064 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>>"
@@ -956,48 +966,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             "<<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:  predecessors     "<<BEnterTry2>>"
+## CHECK:  successors       "<<BExitTry2>>"
 ## 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 +1144,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/800-smali/expected.txt b/test/800-smali/expected.txt
index fe68c5b..6ee7a5b 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -28,4 +28,5 @@
 b/22080519
 b/21645819
 b/22244733
+b/22331663
 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..af99152
--- /dev/null
+++ b/test/800-smali/smali/b_22331663.smali
@@ -0,0 +1,35 @@
+.class public LB22331663;
+.super Ljava/lang/Object;
+
+
+.method public static run(Z)V
+.registers 6
+       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/src/Main.java b/test/800-smali/src/Main.java
index 61f0d7b..3dbba8d 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -103,6 +103,8 @@
                 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));
     }
 
     public void runTests() {
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/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