Merge "Use ObjPtr for reflection.cc/h/inl"
diff --git a/Android.mk b/Android.mk
index cc18660..2647268 100644
--- a/Android.mk
+++ b/Android.mk
@@ -434,12 +434,25 @@
 ########################################################################
 # Phony target for only building what go/lem requires on target.
 .PHONY: build-art-target-golem
+# Also include libartbenchmark, we always include it when running golem.
+ART_TARGET_SHARED_LIBRARY_BENCHMARK := $(TARGET_OUT_SHARED_LIBRARIES)/libartbenchmark.so
 build-art-target-golem: dex2oat dalvikvm patchoat linker \
                         $(TARGET_OUT)/etc/public.libraries.txt \
                         $(ART_TARGET_DEX_DEPENDENCIES) \
                         $(ART_TARGET_SHARED_LIBRARY_DEPENDENCIES) \
+                        $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \
                         $(TARGET_CORE_IMG_OUT_BASE).art \
                         $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art
+	sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
+	# remove libartd.so from public.libraries.txt because golem builds won't have it.
+
+########################################################################
+# Phony target for building what go/lem requires on host.
+.PHONY: build-art-host-golem
+# Also include libartbenchmark, we always include it when running golem.
+ART_HOST_SHARED_LIBRARY_BENCHMARK := $(ART_HOST_OUT_SHARED_LIBRARIES)/libartbenchmark.so
+build-art-host-golem: build-art-host \
+                      $(ART_HOST_SHARED_LIBRARY_BENCHMARK)
 
 ########################################################################
 # Rules for building all dependencies for tests.
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
index a7ca279..dd19888 100644
--- a/benchmark/Android.bp
+++ b/benchmark/Android.bp
@@ -19,8 +19,10 @@
     host_supported: true,
     defaults: ["art_defaults", "art_debug_defaults"],
     srcs: [
+        "jni_loader.cc",
         "jobject-benchmark/jobject_benchmark.cc",
         "jni-perf/perf_jni.cc",
+        "micro-native/micro_native.cc",
         "scoped-primitive-array/scoped_primitive_array.cc",
     ],
     shared_libs: [
diff --git a/benchmark/jni_loader.cc b/benchmark/jni_loader.cc
new file mode 100644
index 0000000..2c9f86e
--- /dev/null
+++ b/benchmark/jni_loader.cc
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 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 <jni.h>
+
+extern void register_micro_native_methods(JNIEnv* env);
+
+jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/) {
+  JNIEnv* env;
+  if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+    return -1;
+  }
+
+  // List of functions to call to register methods explicitly.
+  // Otherwise we use the regular JNI naming conventions to register implicitly.
+  register_micro_native_methods(env);
+
+  return JNI_VERSION_1_6;
+}
diff --git a/benchmark/micro-native/micro_native.cc b/benchmark/micro-native/micro_native.cc
new file mode 100644
index 0000000..43c29e2
--- /dev/null
+++ b/benchmark/micro-native/micro_native.cc
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#define LOG_TAG "NativeMethods"
+
+#define CLASS_NAME "benchmarks/MicroNative/java/NativeMethods"
+
+#include "JNIHelp.h"
+#include "JniConstants.h"
+
+static void NativeMethods_emptyJniStaticSynchronizedMethod0(JNIEnv*, jclass) { }
+static void NativeMethods_emptyJniSynchronizedMethod0(JNIEnv*, jclass) { }
+
+static JNINativeMethod gMethods_NormalOnly[] = {
+  NATIVE_METHOD(NativeMethods, emptyJniStaticSynchronizedMethod0, "()V"),
+  NATIVE_METHOD(NativeMethods, emptyJniSynchronizedMethod0, "()V"),
+};
+
+static void NativeMethods_emptyJniMethod0(JNIEnv*, jobject) { }
+static void NativeMethods_emptyJniMethod6(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeMethods_emptyJniMethod6L(JNIEnv*, jobject, jobject, jarray, jarray, jobject,
+                                           jarray, jarray) { }
+static void NativeMethods_emptyJniStaticMethod6L(JNIEnv*, jclass, jobject, jarray, jarray, jobject,
+                                                 jarray, jarray) { }
+
+static void NativeMethods_emptyJniStaticMethod0(JNIEnv*, jclass) { }
+static void NativeMethods_emptyJniStaticMethod6(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(NativeMethods, emptyJniMethod0, "()V"),
+  NATIVE_METHOD(NativeMethods, emptyJniMethod6, "(IIIIII)V"),
+  NATIVE_METHOD(NativeMethods, emptyJniMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6L, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod0, "()V"),
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6, "(IIIIII)V"),
+};
+
+static void NativeMethods_emptyJniMethod0_Fast(JNIEnv*, jobject) { }
+static void NativeMethods_emptyJniMethod6_Fast(JNIEnv*, jobject, int, int, int, int, int, int) { }
+static void NativeMethods_emptyJniMethod6L_Fast(JNIEnv*, jobject, jobject, jarray, jarray, jobject,
+                                                jarray, jarray) { }
+static void NativeMethods_emptyJniStaticMethod6L_Fast(JNIEnv*, jclass, jobject, jarray, jarray,
+                                                      jobject, jarray, jarray) { }
+
+static void NativeMethods_emptyJniStaticMethod0_Fast(JNIEnv*, jclass) { }
+static void NativeMethods_emptyJniStaticMethod6_Fast(JNIEnv*, jclass, int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Fast[] = {
+  NATIVE_METHOD(NativeMethods, emptyJniMethod0_Fast, "()V"),
+  NATIVE_METHOD(NativeMethods, emptyJniMethod6_Fast, "(IIIIII)V"),
+  NATIVE_METHOD(NativeMethods, emptyJniMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6L_Fast, "(Ljava/lang/String;[Ljava/lang/String;[[ILjava/lang/Object;[Ljava/lang/Object;[[[[Ljava/lang/Object;)V"),
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod0_Fast, "()V"),
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6_Fast, "(IIIIII)V"),
+};
+
+static void NativeMethods_emptyJniStaticMethod0_Critical() { }
+static void NativeMethods_emptyJniStaticMethod6_Critical(int, int, int, int, int, int) { }
+
+static JNINativeMethod gMethods_Critical[] = {
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod0_Critical, "()V"),
+  NATIVE_METHOD(NativeMethods, emptyJniStaticMethod6_Critical, "(IIIIII)V"),
+};
+
+void register_micro_native_methods(JNIEnv* env) {
+  jniRegisterNativeMethods(env, CLASS_NAME, gMethods_NormalOnly, NELEM(gMethods_NormalOnly));
+  jniRegisterNativeMethods(env, CLASS_NAME, gMethods, NELEM(gMethods));
+  jniRegisterNativeMethods(env, CLASS_NAME, gMethods_Fast, NELEM(gMethods_Fast));
+  jniRegisterNativeMethods(env, CLASS_NAME, gMethods_Critical, NELEM(gMethods_Critical));
+}
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index ad881b7..6b5758b 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -45,6 +45,7 @@
 #include "gc/space/space-inl.h"
 #include "globals.h"
 #include "image.h"
+#include "imt_conflict_table.h"
 #include "intern_table.h"
 #include "linear_alloc.h"
 #include "lock_word.h"
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 139daa7..3b08d9f 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -21,6 +21,7 @@
 #include "class_linker.h"
 #include "dex_instruction-inl.h"
 #include "driver/compiler_options.h"
+#include "imtable-inl.h"
 #include "scoped_thread_state_change.h"
 
 namespace art {
@@ -895,7 +896,7 @@
                                            dex_pc,
                                            method_idx,
                                            resolved_method,
-                                           resolved_method->GetImtIndex());
+                                           ImTable::GetImtIndex(resolved_method));
   }
 
   return HandleInvoke(invoke,
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
index 507dbf0..3424e3c 100644
--- a/runtime/arch/stub_test.cc
+++ b/runtime/arch/stub_test.cc
@@ -22,6 +22,7 @@
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
+#include "imt_conflict_table.h"
 #include "linear_alloc.h"
 #include "mirror/class-inl.h"
 #include "mirror/string-inl.h"
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 9b4b38a..73cce5e 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -123,10 +123,6 @@
   return dex_method_index_;
 }
 
-inline uint32_t ArtMethod::GetImtIndex() {
-  return GetDexMethodIndex() % ImTable::kSize;
-}
-
 inline ArtMethod** ArtMethod::GetDexCacheResolvedMethods(PointerSize pointer_size) {
   return GetNativePointer<ArtMethod**>(DexCacheResolvedMethodsOffset(pointer_size),
                                        pointer_size);
diff --git a/runtime/art_method.h b/runtime/art_method.h
index b1baccd..3d2db69 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -34,6 +34,7 @@
 namespace art {
 
 template<class T> class Handle;
+class ImtConflictTable;
 union JValue;
 class OatQuickMethodHeader;
 class ProfilingInfo;
@@ -48,175 +49,6 @@
 class PointerArray;
 }  // namespace mirror
 
-// Table to resolve IMT conflicts at runtime. The table is attached to
-// the jni entrypoint of IMT conflict ArtMethods.
-// The table contains a list of pairs of { interface_method, implementation_method }
-// with the last entry being null to make an assembly implementation of a lookup
-// faster.
-class ImtConflictTable {
-  enum MethodIndex {
-    kMethodInterface,
-    kMethodImplementation,
-    kMethodCount,  // Number of elements in enum.
-  };
-
- public:
-  // Build a new table copying `other` and adding the new entry formed of
-  // the pair { `interface_method`, `implementation_method` }
-  ImtConflictTable(ImtConflictTable* other,
-                   ArtMethod* interface_method,
-                   ArtMethod* implementation_method,
-                   PointerSize pointer_size) {
-    const size_t count = other->NumEntries(pointer_size);
-    for (size_t i = 0; i < count; ++i) {
-      SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size));
-      SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size));
-    }
-    SetInterfaceMethod(count, pointer_size, interface_method);
-    SetImplementationMethod(count, pointer_size, implementation_method);
-    // Add the null marker.
-    SetInterfaceMethod(count + 1, pointer_size, nullptr);
-    SetImplementationMethod(count + 1, pointer_size, nullptr);
-  }
-
-  // num_entries excludes the header.
-  ImtConflictTable(size_t num_entries, PointerSize pointer_size) {
-    SetInterfaceMethod(num_entries, pointer_size, nullptr);
-    SetImplementationMethod(num_entries, pointer_size, nullptr);
-  }
-
-  // Set an entry at an index.
-  void SetInterfaceMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
-    SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method);
-  }
-
-  void SetImplementationMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
-    SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method);
-  }
-
-  ArtMethod* GetInterfaceMethod(size_t index, PointerSize pointer_size) const {
-    return GetMethod(index * kMethodCount + kMethodInterface, pointer_size);
-  }
-
-  ArtMethod* GetImplementationMethod(size_t index, PointerSize pointer_size) const {
-    return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size);
-  }
-
-  // Return true if two conflict tables are the same.
-  bool Equals(ImtConflictTable* other, PointerSize pointer_size) const {
-    size_t num = NumEntries(pointer_size);
-    if (num != other->NumEntries(pointer_size)) {
-      return false;
-    }
-    for (size_t i = 0; i < num; ++i) {
-      if (GetInterfaceMethod(i, pointer_size) != other->GetInterfaceMethod(i, pointer_size) ||
-          GetImplementationMethod(i, pointer_size) !=
-              other->GetImplementationMethod(i, pointer_size)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  // Visit all of the entries.
-  // NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod*
-  // and also returns one. The order is <interface, implementation>.
-  template<typename Visitor>
-  void Visit(const Visitor& visitor, PointerSize pointer_size) NO_THREAD_SAFETY_ANALYSIS {
-    uint32_t table_index = 0;
-    for (;;) {
-      ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size);
-      if (interface_method == nullptr) {
-        break;
-      }
-      ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size);
-      auto input = std::make_pair(interface_method, implementation_method);
-      std::pair<ArtMethod*, ArtMethod*> updated = visitor(input);
-      if (input.first != updated.first) {
-        SetInterfaceMethod(table_index, pointer_size, updated.first);
-      }
-      if (input.second != updated.second) {
-        SetImplementationMethod(table_index, pointer_size, updated.second);
-      }
-      ++table_index;
-    }
-  }
-
-  // Lookup the implementation ArtMethod associated to `interface_method`. Return null
-  // if not found.
-  ArtMethod* Lookup(ArtMethod* interface_method, PointerSize pointer_size) const {
-    uint32_t table_index = 0;
-    for (;;) {
-      ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size);
-      if (current_interface_method == nullptr) {
-        break;
-      }
-      if (current_interface_method == interface_method) {
-        return GetImplementationMethod(table_index, pointer_size);
-      }
-      ++table_index;
-    }
-    return nullptr;
-  }
-
-  // Compute the number of entries in this table.
-  size_t NumEntries(PointerSize pointer_size) const {
-    uint32_t table_index = 0;
-    while (GetInterfaceMethod(table_index, pointer_size) != nullptr) {
-      ++table_index;
-    }
-    return table_index;
-  }
-
-  // Compute the size in bytes taken by this table.
-  size_t ComputeSize(PointerSize pointer_size) const {
-    // Add the end marker.
-    return ComputeSize(NumEntries(pointer_size), pointer_size);
-  }
-
-  // Compute the size in bytes needed for copying the given `table` and add
-  // one more entry.
-  static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, PointerSize pointer_size) {
-    return table->ComputeSize(pointer_size) + EntrySize(pointer_size);
-  }
-
-  // Compute size with a fixed number of entries.
-  static size_t ComputeSize(size_t num_entries, PointerSize pointer_size) {
-    return (num_entries + 1) * EntrySize(pointer_size);  // Add one for null terminator.
-  }
-
-  static size_t EntrySize(PointerSize pointer_size) {
-    return static_cast<size_t>(pointer_size) * static_cast<size_t>(kMethodCount);
-  }
-
- private:
-  ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
-    if (pointer_size == PointerSize::k64) {
-      return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data64_[index]));
-    } else {
-      return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data32_[index]));
-    }
-  }
-
-  void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
-    if (pointer_size == PointerSize::k64) {
-      data64_[index] = dchecked_integral_cast<uint64_t>(reinterpret_cast<uintptr_t>(method));
-    } else {
-      data32_[index] = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(method));
-    }
-  }
-
-  // Array of entries that the assembly stubs will iterate over. Note that this is
-  // not fixed size, and we allocate data prior to calling the constructor
-  // of ImtConflictTable.
-  union {
-    uint32_t data32_[0];
-    uint64_t data64_[0];
-  };
-
-  DISALLOW_COPY_AND_ASSIGN(ImtConflictTable);
-};
-
 class ArtMethod FINAL {
  public:
   ArtMethod() : access_flags_(0), dex_code_item_offset_(0), dex_method_index_(0),
@@ -428,8 +260,6 @@
 
   ALWAYS_INLINE uint32_t GetDexMethodIndex() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ALWAYS_INLINE uint32_t GetImtIndex() REQUIRES_SHARED(Locks::mutator_lock_);
-
   void SetDexMethodIndex(uint32_t new_idx) {
     // Not called within a transaction.
     dex_method_index_ = new_idx;
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index eb38a8c..48550f3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -56,6 +56,8 @@
 #include "gc/space/image_space.h"
 #include "handle_scope-inl.h"
 #include "image-inl.h"
+#include "imt_conflict_table.h"
+#include "imtable-inl.h"
 #include "intern_table.h"
 #include "interpreter/interpreter.h"
 #include "jit/jit.h"
@@ -6269,7 +6271,7 @@
       // or interface methods in the IMT here they will not create extra conflicts since we compare
       // names and signatures in SetIMTRef.
       ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
-      const uint32_t imt_index = interface_method->GetImtIndex();
+      const uint32_t imt_index = ImTable::GetImtIndex(interface_method);
 
       // There is only any conflicts if all of the interface methods for an IMT slot don't have
       // the same implementation method, keep track of this to avoid creating a conflict table in
@@ -6323,7 +6325,7 @@
         }
         DCHECK(implementation_method != nullptr);
         ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size_);
-        const uint32_t imt_index = interface_method->GetImtIndex();
+        const uint32_t imt_index = ImTable::GetImtIndex(interface_method);
         if (!imt[imt_index]->IsRuntimeMethod() ||
             imt[imt_index] == unimplemented_method ||
             imt[imt_index] == imt_conflict_method) {
@@ -6782,7 +6784,7 @@
         auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size_);
         MethodNameAndSignatureComparator interface_name_comparator(
             interface_method->GetInterfaceMethodIfProxy(image_pointer_size_));
-        uint32_t imt_index = interface_method->GetImtIndex();
+        uint32_t imt_index = ImTable::GetImtIndex(interface_method);
         ArtMethod** imt_ptr = &out_imt[imt_index];
         // For each method listed in the interface's method list, find the
         // matching method in our class's method list.  We want to favor the
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
index c3cf53b..789a5bd 100644
--- a/runtime/dex_file_annotations.cc
+++ b/runtime/dex_file_annotations.cc
@@ -1027,6 +1027,66 @@
                                               annotation_class);
 }
 
+bool GetParametersMetadataForMethod(ArtMethod* method,
+                                    MutableHandle<mirror::ObjectArray<mirror::String>>* names,
+                                    MutableHandle<mirror::IntArray>* access_flags) {
+  const DexFile::AnnotationSetItem::AnnotationSetItem* annotation_set =
+      FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+
+  const DexFile* dex_file = method->GetDexFile();
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(*dex_file,
+                          annotation_set,
+                          "Ldalvik/annotation/MethodParameters;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return false;
+  }
+
+  StackHandleScope<5> hs(Thread::Current());
+
+  // Extract the parameters' names String[].
+  mirror::Class* string_class = mirror::String::GetJavaLangString();
+  Handle<mirror::Class> string_array_class(hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
+  if (UNLIKELY(string_array_class.Get() == nullptr)) {
+    return false;
+  }
+
+  Handle<mirror::Class> klass = hs.NewHandle(method->GetDeclaringClass());
+  Handle<mirror::Object> names_obj =
+      hs.NewHandle(GetAnnotationValue(klass,
+                                      annotation_item,
+                                      "names",
+                                      string_array_class,
+                                      DexFile::kDexAnnotationArray));
+  if (names_obj.Get() == nullptr) {
+    return false;
+  }
+
+  // Extract the parameters' access flags int[].
+  Handle<mirror::Class> int_array_class(hs.NewHandle(mirror::IntArray::GetArrayClass()));
+  if (UNLIKELY(int_array_class.Get() == nullptr)) {
+    return false;
+  }
+  Handle<mirror::Object> access_flags_obj =
+      hs.NewHandle(GetAnnotationValue(klass,
+                                      annotation_item,
+                                      "accessFlags",
+                                      int_array_class,
+                                      DexFile::kDexAnnotationArray));
+  if (access_flags_obj.Get() == nullptr) {
+    return false;
+  }
+
+  names->Assign(names_obj.Get()->AsObjectArray<mirror::String>());
+  access_flags->Assign(access_flags_obj.Get()->AsIntArray());
+  return true;
+}
+
 mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) {
   const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
   if (annotation_set == nullptr) {
diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h
index 7b4e856..c66c5bd 100644
--- a/runtime/dex_file_annotations.h
+++ b/runtime/dex_file_annotations.h
@@ -30,6 +30,7 @@
 class ArtField;
 class ArtMethod;
 class ClassLinker;
+template<class T> class MutableHandle;
 
 namespace annotations {
 
@@ -58,6 +59,10 @@
                                                 uint32_t parameter_idx,
                                                 Handle<mirror::Class> annotation_class)
     REQUIRES_SHARED(Locks::mutator_lock_);
+bool GetParametersMetadataForMethod(ArtMethod* method,
+                                    MutableHandle<mirror::ObjectArray<mirror::String>>* names,
+                                    MutableHandle<mirror::IntArray>* access_flags)
+    REQUIRES_SHARED(Locks::mutator_lock_);
 mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method)
     REQUIRES_SHARED(Locks::mutator_lock_);
 bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 14110c2..99b8805 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -26,6 +26,8 @@
 #include "dex_file.h"
 #include "entrypoints/quick/callee_save_frame.h"
 #include "handle_scope-inl.h"
+#include "imt_conflict_table.h"
+#include "imtable-inl.h"
 #include "indirect_reference_table.h"
 #include "invoke_type.h"
 #include "jni_internal.h"
@@ -612,7 +614,7 @@
       UNREACHABLE();
     }
     case kInterface: {
-      uint32_t imt_index = resolved_method->GetImtIndex();
+      uint32_t imt_index = ImTable::GetImtIndex(resolved_method);
       PointerSize pointer_size = class_linker->GetImagePointerSize();
       ArtMethod* imt_method = (*this_object)->GetClass()->GetImt(pointer_size)->
           Get(imt_index, pointer_size);
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index fcbd834..cfd948e 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -23,6 +23,8 @@
 #include "entrypoints/entrypoint_utils-inl.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
+#include "imt_conflict_table.h"
+#include "imtable-inl.h"
 #include "interpreter/interpreter.h"
 #include "linear_alloc.h"
 #include "method_reference.h"
@@ -2239,7 +2241,8 @@
   if (LIKELY(interface_method->GetDexMethodIndex() != DexFile::kDexNoIndex)) {
     // If the dex cache already resolved the interface method, look whether we have
     // a match in the ImtConflictTable.
-    ArtMethod* conflict_method = imt->Get(interface_method->GetImtIndex(), kRuntimePointerSize);
+    ArtMethod* conflict_method = imt->Get(ImTable::GetImtIndex(interface_method),
+                                          kRuntimePointerSize);
     if (LIKELY(conflict_method->IsRuntimeMethod())) {
       ImtConflictTable* current_table = conflict_method->GetImtConflictTable(kRuntimePointerSize);
       DCHECK(current_table != nullptr);
@@ -2291,7 +2294,7 @@
 
   // We arrive here if we have found an implementation, and it is not in the ImtConflictTable.
   // We create a new table with the new pair { interface_method, method }.
-  uint32_t imt_index = interface_method->GetImtIndex();
+  uint32_t imt_index = ImTable::GetImtIndex(interface_method);
   ArtMethod* conflict_method = imt->Get(imt_index, kRuntimePointerSize);
   if (conflict_method->IsRuntimeMethod()) {
     ArtMethod* new_conflict_method = Runtime::Current()->GetClassLinker()->AddMethodToConflictTable(
diff --git a/runtime/image-inl.h b/runtime/image-inl.h
index 669649e..da18ae5 100644
--- a/runtime/image-inl.h
+++ b/runtime/image-inl.h
@@ -20,6 +20,7 @@
 #include "image.h"
 
 #include "art_method.h"
+#include "imt_conflict_table.h"
 #include "imtable.h"
 #include "read_barrier-inl.h"
 
diff --git a/runtime/imt_conflict_table.h b/runtime/imt_conflict_table.h
new file mode 100644
index 0000000..fdd10fe
--- /dev/null
+++ b/runtime/imt_conflict_table.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_IMT_CONFLICT_TABLE_H_
+#define ART_RUNTIME_IMT_CONFLICT_TABLE_H_
+
+#include <cstddef>
+
+#include "base/casts.h"
+#include "base/enums.h"
+#include "base/macros.h"
+
+namespace art {
+
+class ArtMethod;
+
+// Table to resolve IMT conflicts at runtime. The table is attached to
+// the jni entrypoint of IMT conflict ArtMethods.
+// The table contains a list of pairs of { interface_method, implementation_method }
+// with the last entry being null to make an assembly implementation of a lookup
+// faster.
+class ImtConflictTable {
+  enum MethodIndex {
+    kMethodInterface,
+    kMethodImplementation,
+    kMethodCount,  // Number of elements in enum.
+  };
+
+ public:
+  // Build a new table copying `other` and adding the new entry formed of
+  // the pair { `interface_method`, `implementation_method` }
+  ImtConflictTable(ImtConflictTable* other,
+                   ArtMethod* interface_method,
+                   ArtMethod* implementation_method,
+                   PointerSize pointer_size) {
+    const size_t count = other->NumEntries(pointer_size);
+    for (size_t i = 0; i < count; ++i) {
+      SetInterfaceMethod(i, pointer_size, other->GetInterfaceMethod(i, pointer_size));
+      SetImplementationMethod(i, pointer_size, other->GetImplementationMethod(i, pointer_size));
+    }
+    SetInterfaceMethod(count, pointer_size, interface_method);
+    SetImplementationMethod(count, pointer_size, implementation_method);
+    // Add the null marker.
+    SetInterfaceMethod(count + 1, pointer_size, nullptr);
+    SetImplementationMethod(count + 1, pointer_size, nullptr);
+  }
+
+  // num_entries excludes the header.
+  ImtConflictTable(size_t num_entries, PointerSize pointer_size) {
+    SetInterfaceMethod(num_entries, pointer_size, nullptr);
+    SetImplementationMethod(num_entries, pointer_size, nullptr);
+  }
+
+  // Set an entry at an index.
+  void SetInterfaceMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
+    SetMethod(index * kMethodCount + kMethodInterface, pointer_size, method);
+  }
+
+  void SetImplementationMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
+    SetMethod(index * kMethodCount + kMethodImplementation, pointer_size, method);
+  }
+
+  ArtMethod* GetInterfaceMethod(size_t index, PointerSize pointer_size) const {
+    return GetMethod(index * kMethodCount + kMethodInterface, pointer_size);
+  }
+
+  ArtMethod* GetImplementationMethod(size_t index, PointerSize pointer_size) const {
+    return GetMethod(index * kMethodCount + kMethodImplementation, pointer_size);
+  }
+
+  // Return true if two conflict tables are the same.
+  bool Equals(ImtConflictTable* other, PointerSize pointer_size) const {
+    size_t num = NumEntries(pointer_size);
+    if (num != other->NumEntries(pointer_size)) {
+      return false;
+    }
+    for (size_t i = 0; i < num; ++i) {
+      if (GetInterfaceMethod(i, pointer_size) != other->GetInterfaceMethod(i, pointer_size) ||
+          GetImplementationMethod(i, pointer_size) !=
+              other->GetImplementationMethod(i, pointer_size)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  // Visit all of the entries.
+  // NO_THREAD_SAFETY_ANALYSIS for calling with held locks. Visitor is passed a pair of ArtMethod*
+  // and also returns one. The order is <interface, implementation>.
+  template<typename Visitor>
+  void Visit(const Visitor& visitor, PointerSize pointer_size) NO_THREAD_SAFETY_ANALYSIS {
+    uint32_t table_index = 0;
+    for (;;) {
+      ArtMethod* interface_method = GetInterfaceMethod(table_index, pointer_size);
+      if (interface_method == nullptr) {
+        break;
+      }
+      ArtMethod* implementation_method = GetImplementationMethod(table_index, pointer_size);
+      auto input = std::make_pair(interface_method, implementation_method);
+      std::pair<ArtMethod*, ArtMethod*> updated = visitor(input);
+      if (input.first != updated.first) {
+        SetInterfaceMethod(table_index, pointer_size, updated.first);
+      }
+      if (input.second != updated.second) {
+        SetImplementationMethod(table_index, pointer_size, updated.second);
+      }
+      ++table_index;
+    }
+  }
+
+  // Lookup the implementation ArtMethod associated to `interface_method`. Return null
+  // if not found.
+  ArtMethod* Lookup(ArtMethod* interface_method, PointerSize pointer_size) const {
+    uint32_t table_index = 0;
+    for (;;) {
+      ArtMethod* current_interface_method = GetInterfaceMethod(table_index, pointer_size);
+      if (current_interface_method == nullptr) {
+        break;
+      }
+      if (current_interface_method == interface_method) {
+        return GetImplementationMethod(table_index, pointer_size);
+      }
+      ++table_index;
+    }
+    return nullptr;
+  }
+
+  // Compute the number of entries in this table.
+  size_t NumEntries(PointerSize pointer_size) const {
+    uint32_t table_index = 0;
+    while (GetInterfaceMethod(table_index, pointer_size) != nullptr) {
+      ++table_index;
+    }
+    return table_index;
+  }
+
+  // Compute the size in bytes taken by this table.
+  size_t ComputeSize(PointerSize pointer_size) const {
+    // Add the end marker.
+    return ComputeSize(NumEntries(pointer_size), pointer_size);
+  }
+
+  // Compute the size in bytes needed for copying the given `table` and add
+  // one more entry.
+  static size_t ComputeSizeWithOneMoreEntry(ImtConflictTable* table, PointerSize pointer_size) {
+    return table->ComputeSize(pointer_size) + EntrySize(pointer_size);
+  }
+
+  // Compute size with a fixed number of entries.
+  static size_t ComputeSize(size_t num_entries, PointerSize pointer_size) {
+    return (num_entries + 1) * EntrySize(pointer_size);  // Add one for null terminator.
+  }
+
+  static size_t EntrySize(PointerSize pointer_size) {
+    return static_cast<size_t>(pointer_size) * static_cast<size_t>(kMethodCount);
+  }
+
+ private:
+  ArtMethod* GetMethod(size_t index, PointerSize pointer_size) const {
+    if (pointer_size == PointerSize::k64) {
+      return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data64_[index]));
+    } else {
+      return reinterpret_cast<ArtMethod*>(static_cast<uintptr_t>(data32_[index]));
+    }
+  }
+
+  void SetMethod(size_t index, PointerSize pointer_size, ArtMethod* method) {
+    if (pointer_size == PointerSize::k64) {
+      data64_[index] = dchecked_integral_cast<uint64_t>(reinterpret_cast<uintptr_t>(method));
+    } else {
+      data32_[index] = dchecked_integral_cast<uint32_t>(reinterpret_cast<uintptr_t>(method));
+    }
+  }
+
+  // Array of entries that the assembly stubs will iterate over. Note that this is
+  // not fixed size, and we allocate data prior to calling the constructor
+  // of ImtConflictTable.
+  union {
+    uint32_t data32_[0];
+    uint64_t data64_[0];
+  };
+
+  DISALLOW_COPY_AND_ASSIGN(ImtConflictTable);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_IMT_CONFLICT_TABLE_H_
diff --git a/runtime/imtable-inl.h b/runtime/imtable-inl.h
new file mode 100644
index 0000000..0cb9b5e
--- /dev/null
+++ b/runtime/imtable-inl.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_IMTABLE_INL_H_
+#define ART_RUNTIME_IMTABLE_INL_H_
+
+#include "imtable.h"
+
+#include "art_method-inl.h"
+
+namespace art {
+
+inline uint32_t ImTable::GetBaseImtHash(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
+  return method->GetDexMethodIndex();
+}
+
+inline uint32_t ImTable::GetImtIndex(ArtMethod* method) {
+  return GetBaseImtHash(method) % ImTable::kSize;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_IMTABLE_INL_H_
+
diff --git a/runtime/imtable.h b/runtime/imtable.h
index 2416621..6df890d 100644
--- a/runtime/imtable.h
+++ b/runtime/imtable.h
@@ -21,9 +21,13 @@
 #error IMT_SIZE not defined
 #endif
 
+#include "base/enums.h"
+#include "base/macros.h"
+
 namespace art {
 
 class ArtMethod;
+class DexFile;
 
 class ImTable {
  public:
@@ -69,6 +73,19 @@
   constexpr static size_t SizeInBytes(PointerSize pointer_size) {
     return kSize * static_cast<size_t>(pointer_size);
   }
+
+  // Converts a method to the base hash used in GetImtIndex.
+  ALWAYS_INLINE static inline uint32_t GetBaseImtHash(ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  ALWAYS_INLINE static inline uint32_t GetBaseImtHash(const DexFile* dex_file, uint32_t method_idx)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // The (complete) hashing scheme to map an ArtMethod to a slot in the Interface Method Table
+  // (IMT).
+  ALWAYS_INLINE static inline uint32_t GetImtIndex(ArtMethod* method)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  ALWAYS_INLINE static inline uint32_t GetImtIndex(const DexFile* dex_file, uint32_t method_idx)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 };
 
 }  // namespace art
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index 8fcf6ac..f345c09 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -18,8 +18,10 @@
 
 #include "art_method-inl.h"
 #include "dex_file_annotations.h"
+#include "handle.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
+#include "mirror/method.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
 #include "reflection.h"
@@ -43,8 +45,8 @@
 }
 
 static jobject Executable_getAnnotationNative(JNIEnv* env,
-                                                  jobject javaMethod,
-                                                  jclass annotationType) {
+                                              jobject javaMethod,
+                                              jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
@@ -77,9 +79,107 @@
   }
 }
 
+static jobjectArray Executable_getParameters0(JNIEnv* env, jobject javaMethod) {
+  ScopedFastNativeObjectAccess soa(env);
+  Thread* self = soa.Self();
+  StackHandleScope<8> hs(self);
+
+  Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method*>(javaMethod));
+  ArtMethod* art_method = executable.Get()->GetArtMethod();
+  if (art_method->GetDeclaringClass()->IsProxyClass()) {
+    return nullptr;
+  }
+
+  // Find the MethodParameters system annotation.
+  MutableHandle<mirror::ObjectArray<mirror::String>> names =
+      hs.NewHandle<mirror::ObjectArray<mirror::String>>(nullptr);
+  MutableHandle<mirror::IntArray> access_flags = hs.NewHandle<mirror::IntArray>(nullptr);
+  if (!annotations::GetParametersMetadataForMethod(art_method, &names, &access_flags)) {
+    return nullptr;
+  }
+
+  // Validate the MethodParameters system annotation data.
+  if (UNLIKELY(names.Get() == nullptr || access_flags.Get() == nullptr)) {
+    ThrowIllegalArgumentException(
+        StringPrintf("Missing parameter metadata for names or access flags for %s",
+                     PrettyMethod(art_method).c_str()).c_str());
+    return nullptr;
+  }
+
+  // Check array sizes match each other
+  int32_t names_count = names.Get()->GetLength();
+  int32_t access_flags_count = access_flags.Get()->GetLength();
+  if (names_count != access_flags_count) {
+    ThrowIllegalArgumentException(
+        StringPrintf(
+            "Inconsistent parameter metadata for %s. names length: %d, access flags length: %d",
+            PrettyMethod(art_method).c_str(),
+            names_count,
+            access_flags_count).c_str());
+    return nullptr;
+  }
+
+  // Instantiate a Parameter[] to hold the result.
+  Handle<mirror::Class> parameter_array_class =
+      hs.NewHandle(
+          soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter__array));
+  Handle<mirror::ObjectArray<mirror::Object>> parameter_array =
+      hs.NewHandle(
+          mirror::ObjectArray<mirror::Object>::Alloc(self,
+                                                     parameter_array_class.Get(),
+                                                     names_count));
+  if (UNLIKELY(parameter_array.Get() == nullptr)) {
+    self->AssertPendingException();
+    return nullptr;
+  }
+
+  Handle<mirror::Class> parameter_class =
+      hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter));
+  ArtMethod* parameter_init =
+      soa.DecodeMethod(WellKnownClasses::java_lang_reflect_Parameter_init);
+
+  // Mutable handles used in the loop below to ensure cleanup without scaling the number of
+  // handles by the number of parameters.
+  MutableHandle<mirror::String> name = hs.NewHandle<mirror::String>(nullptr);
+  MutableHandle<mirror::Object> parameter = hs.NewHandle<mirror::Object>(nullptr);
+
+  // Populate the Parameter[] to return.
+  for (int32_t parameter_index = 0; parameter_index < names_count; parameter_index++) {
+    name.Assign(names.Get()->Get(parameter_index));
+    int32_t modifiers = access_flags.Get()->Get(parameter_index);
+
+    // Allocate / initialize the Parameter to add to parameter_array.
+    parameter.Assign(parameter_class->AllocObject(self));
+    if (UNLIKELY(parameter.Get() == nullptr)) {
+      self->AssertPendingOOMException();
+      return nullptr;
+    }
+
+    uint32_t args[5] = { PointerToLowMemUInt32(parameter.Get()),
+                         PointerToLowMemUInt32(name.Get()),
+                         static_cast<uint32_t>(modifiers),
+                         PointerToLowMemUInt32(executable.Get()),
+                         static_cast<uint32_t>(parameter_index)
+    };
+    JValue result;
+    static const char* method_signature = "VLILI";  // return + parameter types
+    parameter_init->Invoke(self, args, sizeof(args), &result, method_signature);
+    if (UNLIKELY(self->IsExceptionPending())) {
+      return nullptr;
+    }
+
+    // Store the Parameter in the Parameter[].
+    parameter_array.Get()->Set(parameter_index, parameter.Get());
+    if (UNLIKELY(self->IsExceptionPending())) {
+      return nullptr;
+    }
+  }
+  return soa.AddLocalReference<jobjectArray>(parameter_array.Get());
+}
+
 static jboolean Executable_isAnnotationPresentNative(JNIEnv* env,
-                                                         jobject javaMethod,
-                                                         jclass annotationType) {
+                                                     jobject javaMethod,
+                                                     jclass annotationType) {
   ScopedFastNativeObjectAccess soa(env);
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
   if (method->GetDeclaringClass()->IsProxyClass()) {
@@ -96,6 +196,7 @@
   NATIVE_METHOD(Executable, getDeclaredAnnotationsNative, "!()[Ljava/lang/annotation/Annotation;"),
   NATIVE_METHOD(Executable, getParameterAnnotationsNative,
                 "!()[[Ljava/lang/annotation/Annotation;"),
+  NATIVE_METHOD(Executable, getParameters0, "!()[Ljava/lang/reflect/Parameter;"),
   NATIVE_METHOD(Executable, getSignatureAnnotation, "!()[Ljava/lang/String;"),
   NATIVE_METHOD(Executable, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"),
 };
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index f04d41d..0be79ef 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -192,6 +192,13 @@
       } else {
         StringAppendF(&extras, " \"%.16s... (%d chars)", utf8.c_str(), s->GetLength());
       }
+    } else if (ref->IsReferenceInstance()) {
+      mirror::Object* referent = ref->AsReference()->GetReferent();
+      if (referent == nullptr) {
+        extras = " (referent is null)";
+      } else {
+        extras = StringPrintf(" (referent is a %s)", PrettyTypeOf(referent).c_str());
+      }
     }
     os << StringPrintf("    %5d: ", idx) << ref << " " << className << extras << "\n";
   }
diff --git a/runtime/reference_table_test.cc b/runtime/reference_table_test.cc
index fae8e72..819e17a 100644
--- a/runtime/reference_table_test.cc
+++ b/runtime/reference_table_test.cc
@@ -16,11 +16,15 @@
 
 #include "reference_table.h"
 
+#include "class_linker.h"
 #include "common_runtime_test.h"
+#include "handle_scope-inl.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
+#include "mirror/class_loader.h"
 #include "mirror/string.h"
 #include "primitive.h"
+#include "runtime.h"
 #include "scoped_thread_state_change.h"
 #include "thread-inl.h"
 
@@ -28,6 +32,39 @@
 
 class ReferenceTableTest : public CommonRuntimeTest {};
 
+static mirror::Object* CreateWeakReference(mirror::Object* referent)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  Thread* self = Thread::Current();
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+  StackHandleScope<3> scope(self);
+  Handle<mirror::Object> h_referent(scope.NewHandle<mirror::Object>(referent));
+
+  Handle<mirror::Class> h_ref_class(scope.NewHandle<mirror::Class>(
+      class_linker->FindClass(self,
+                              "Ljava/lang/ref/WeakReference;",
+                              ScopedNullHandle<mirror::ClassLoader>())));
+  CHECK(h_ref_class.Get() != nullptr);
+  CHECK(class_linker->EnsureInitialized(self, h_ref_class, true, true));
+
+  Handle<mirror::Object> h_ref_instance(scope.NewHandle<mirror::Object>(
+      h_ref_class->AllocObject(self)));
+  CHECK(h_ref_instance.Get() != nullptr);
+
+  ArtMethod* constructor = h_ref_class->FindDeclaredDirectMethod(
+      "<init>", "(Ljava/lang/Object;)V", class_linker->GetImagePointerSize());
+  CHECK(constructor != nullptr);
+
+  uint32_t args[2];
+  args[0] = PointerToLowMemUInt32(h_ref_instance.Get());
+  args[1] = PointerToLowMemUInt32(h_referent.Get());
+  JValue result;
+  constructor->Invoke(self, args, sizeof(uint32_t), &result, constructor->GetShorty());
+  CHECK(!self->IsExceptionPending());
+
+  return h_ref_instance.Get();
+}
+
 TEST_F(ReferenceTableTest, Basics) {
   ScopedObjectAccess soa(Thread::Current());
   mirror::Object* o1 = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello");
@@ -104,6 +141,29 @@
                 std::string::npos) << oss.str();
     }
   }
+
+  // Add a reference and check that the type of the referent is dumped.
+  {
+    mirror::Object* empty_reference = CreateWeakReference(nullptr);
+    ASSERT_TRUE(empty_reference->IsReferenceInstance());
+    rt.Add(empty_reference);
+    std::ostringstream oss;
+    rt.Dump(oss);
+    EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is null)"), std::string::npos)
+        << oss.str();
+  }
+
+  {
+    mirror::Object* string_referent = mirror::String::AllocFromModifiedUtf8(Thread::Current(), "A");
+    mirror::Object* non_empty_reference = CreateWeakReference(string_referent);
+    ASSERT_TRUE(non_empty_reference->IsReferenceInstance());
+    rt.Add(non_empty_reference);
+    std::ostringstream oss;
+    rt.Dump(oss);
+    EXPECT_NE(oss.str().find("java.lang.ref.WeakReference (referent is a java.lang.String)"),
+              std::string::npos)
+        << oss.str();
+  }
 }
 
 }  // namespace art
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 03b03de..17c6c2e 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -441,8 +441,8 @@
       // runnable (both cases waiting inside Thread::TransitionFromSuspendedToRunnable), or waiting
       // for the thread flip to end at the JNI critical section entry (kWaitingForGcThreadFlip),
       ThreadState state = thread->GetState();
-      if (state == kWaitingForGcThreadFlip ||
-          thread->IsTransitioningToRunnable()) {
+      if ((state == kWaitingForGcThreadFlip || thread->IsTransitioningToRunnable()) &&
+          thread->GetSuspendCount() == 1) {
         // The thread will resume right after the broadcast.
         thread->ModifySuspendCount(self, -1, nullptr, false);
         ++runnable_thread_count;
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 6b569f4..e5216fb 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -53,6 +53,8 @@
 jclass WellKnownClasses::java_lang_reflect_Executable;
 jclass WellKnownClasses::java_lang_reflect_Field;
 jclass WellKnownClasses::java_lang_reflect_Method;
+jclass WellKnownClasses::java_lang_reflect_Parameter;
+jclass WellKnownClasses::java_lang_reflect_Parameter__array;
 jclass WellKnownClasses::java_lang_reflect_Proxy;
 jclass WellKnownClasses::java_lang_RuntimeException;
 jclass WellKnownClasses::java_lang_StackOverflowError;
@@ -87,6 +89,7 @@
 jmethodID WellKnownClasses::java_lang_Long_valueOf;
 jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add;
 jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add;
+jmethodID WellKnownClasses::java_lang_reflect_Parameter_init;
 jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke;
 jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad;
 jmethodID WellKnownClasses::java_lang_Short_valueOf;
@@ -280,6 +283,8 @@
   java_lang_reflect_Executable = CacheClass(env, "java/lang/reflect/Executable");
   java_lang_reflect_Field = CacheClass(env, "java/lang/reflect/Field");
   java_lang_reflect_Method = CacheClass(env, "java/lang/reflect/Method");
+  java_lang_reflect_Parameter = CacheClass(env, "java/lang/reflect/Parameter");
+  java_lang_reflect_Parameter__array = CacheClass(env, "[Ljava/lang/reflect/Parameter;");
   java_lang_reflect_Proxy = CacheClass(env, "java/lang/reflect/Proxy");
   java_lang_RuntimeException = CacheClass(env, "java/lang/RuntimeException");
   java_lang_StackOverflowError = CacheClass(env, "java/lang/StackOverflowError");
@@ -312,6 +317,7 @@
   ScopedLocalRef<jclass> java_lang_ref_ReferenceQueue(env, env->FindClass("java/lang/ref/ReferenceQueue"));
   java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
 
+  java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V");
   java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;");
   java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V");
   java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index c9110e6..ddfc5b8 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -67,6 +67,8 @@
   static jclass java_lang_reflect_Executable;
   static jclass java_lang_reflect_Field;
   static jclass java_lang_reflect_Method;
+  static jclass java_lang_reflect_Parameter;
+  static jclass java_lang_reflect_Parameter__array;
   static jclass java_lang_reflect_Proxy;
   static jclass java_lang_RuntimeException;
   static jclass java_lang_StackOverflowError;
@@ -101,6 +103,7 @@
   static jmethodID java_lang_Long_valueOf;
   static jmethodID java_lang_ref_FinalizerReference_add;
   static jmethodID java_lang_ref_ReferenceQueue_add;
+  static jmethodID java_lang_reflect_Parameter_init;
   static jmethodID java_lang_reflect_Proxy_invoke;
   static jmethodID java_lang_Runtime_nativeLoad;
   static jmethodID java_lang_Short_valueOf;
diff --git a/test/run-test b/test/run-test
index c50a9ca..7a4afaf 100755
--- a/test/run-test
+++ b/test/run-test
@@ -937,6 +937,7 @@
         --raw-cmd="$raw_cmd" \
         --check-script="$cwd/check" \
         --expected-output="$cwd/expected.txt" \
+        --logfile="$cwd/bisection_log.txt" \
         --timeout=300
     fi
 fi
diff --git a/tools/bisection_search/bisection_search.py b/tools/bisection_search/bisection_search.py
index c5971e6..27bd599 100755
--- a/tools/bisection_search/bisection_search.py
+++ b/tools/bisection_search/bisection_search.py
@@ -294,8 +294,7 @@
   if faulty_method_idx == len(all_methods) + 1:
     return (None, None)
   if faulty_method_idx == 0:
-    raise FatalError('Testable fails with no methods compiled. '
-                     'Perhaps issue lies outside of compiler.')
+    raise FatalError('Testable fails with no methods compiled.')
   faulty_method = all_methods[faulty_method_idx - 1]
   all_passes = testable.GetAllPassesForMethod(faulty_method)
   faulty_pass_idx = BinarySearch(
@@ -415,7 +414,11 @@
   try:
     testable = Dex2OatWrapperTestable(base_cmd, test_env, args.expected_retcode,
                                       output_checker, args.verbose)
-    (method, opt_pass) = BugSearch(testable)
+    if testable.Test(compiled_methods=[]):
+      (method, opt_pass) = BugSearch(testable)
+    else:
+      print('Testable fails with no methods compiled.')
+      sys.exit(1)
   except Exception as e:
     print('Error occurred.\nLogfile: {0}'.format(test_env.logfile.name))
     test_env.logfile.write('Exception: {0}\n'.format(e))
diff --git a/tools/jfuzz/run_jfuzz_test_nightly.py b/tools/jfuzz/run_jfuzz_test_nightly.py
index cd338fb..29595f2 100755
--- a/tools/jfuzz/run_jfuzz_test_nightly.py
+++ b/tools/jfuzz/run_jfuzz_test_nightly.py
@@ -16,9 +16,14 @@
 
 import argparse
 import os
+import re
+import shutil
 import subprocess
 import sys
 
+from glob import glob
+
+from tempfile import mkdtemp
 from tempfile import TemporaryFile
 
 # Default arguments for run_jfuzz_test.py.
@@ -51,15 +56,29 @@
     for proc in processes:
       proc.kill()
   # Output results.
+  output_dirs = []
   for i, output_file in enumerate(output_files):
     output_file.seek(0)
     output_str = output_file.read().decode('ascii')
     output_file.close()
+    # Extract output directory. Example match: 'Directory : /tmp/tmp8ltpfjng'.
+    directory_match = re.search(r'Directory[^:]*: ([^\n]+)\n', output_str)
+    if directory_match:
+      output_dirs.append(directory_match.group(1))
     print('Tester', i)
     if output_str.find(SUCCESS_STRING) == NOT_FOUND:
       print(output_str)
     else:
       print(SUCCESS_STRING)
+  # Gather divergences.
+  global_out_dir = mkdtemp('jfuzz_nightly')
+  divergence_nr = 1
+  for out_dir in output_dirs:
+    for divergence_dir in glob(out_dir + '/divergence*/'):
+      shutil.copytree(divergence_dir,
+                      global_out_dir + '/divergence' + str(divergence_nr))
+      divergence_nr += 1
+  print('Global output directory:', global_out_dir)
 
 if __name__ == '__main__':
   main(sys.argv)