Merge "Revert "Revert "Revert "(dl)Close native libraries on unload""""
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 6703695..eb9c381 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -206,6 +206,22 @@
   return instruction;
 }
 
+static bool UpdateDominatorOfSuccessor(HBasicBlock* block, HBasicBlock* successor) {
+  DCHECK(ContainsElement(block->GetSuccessors(), successor));
+
+  HBasicBlock* old_dominator = successor->GetDominator();
+  HBasicBlock* new_dominator =
+      (old_dominator == nullptr) ? block
+                                 : CommonDominator::ForPair(old_dominator, block);
+
+  if (old_dominator == new_dominator) {
+    return false;
+  } else {
+    successor->SetDominator(new_dominator);
+    return true;
+  }
+}
+
 void HGraph::ComputeDominanceInformation() {
   DCHECK(reverse_post_order_.empty());
   reverse_post_order_.reserve(blocks_.size());
@@ -228,15 +244,7 @@
       worklist.pop_back();
     } else {
       HBasicBlock* successor = current->GetSuccessors()[successors_visited[current_id]++];
-
-      if (successor->GetDominator() == nullptr) {
-        successor->SetDominator(current);
-      } else {
-        // The CommonDominator can work for multiple blocks as long as the
-        // domination information doesn't change. However, since we're changing
-        // that information here, we can use the finder only for pairs of blocks.
-        successor->SetDominator(CommonDominator::ForPair(successor->GetDominator(), current));
-      }
+      UpdateDominatorOfSuccessor(current, successor);
 
       // Once all the forward edges have been visited, we know the immediate
       // dominator of the block. We can then start visiting its successors.
@@ -248,6 +256,44 @@
     }
   }
 
+  // Check if the graph has back edges not dominated by their respective headers.
+  // If so, we need to update the dominators of those headers and recursively of
+  // their successors. We do that with a fix-point iteration over all blocks.
+  // The algorithm is guaranteed to terminate because it loops only if the sum
+  // of all dominator chains has decreased in the current iteration.
+  bool must_run_fix_point = false;
+  for (HBasicBlock* block : blocks_) {
+    if (block != nullptr &&
+        block->IsLoopHeader() &&
+        block->GetLoopInformation()->HasBackEdgeNotDominatedByHeader()) {
+      must_run_fix_point = true;
+      break;
+    }
+  }
+  if (must_run_fix_point) {
+    bool update_occurred = true;
+    while (update_occurred) {
+      update_occurred = false;
+      for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
+        HBasicBlock* block = it.Current();
+        for (HBasicBlock* successor : block->GetSuccessors()) {
+          update_occurred |= UpdateDominatorOfSuccessor(block, successor);
+        }
+      }
+    }
+  }
+
+  // Make sure that there are no remaining blocks whose dominator information
+  // needs to be updated.
+  if (kIsDebugBuild) {
+    for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
+      HBasicBlock* block = it.Current();
+      for (HBasicBlock* successor : block->GetSuccessors()) {
+        DCHECK(!UpdateDominatorOfSuccessor(block, successor));
+      }
+    }
+  }
+
   // Populate `dominated_blocks_` information after computing all dominators.
   // The potential presence of irreducible loops requires to do it after.
   for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
@@ -595,20 +641,16 @@
   blocks_.SetBit(header_->GetBlockId());
   header_->SetInLoop(this);
 
-  bool is_irreducible_loop = false;
-  for (HBasicBlock* back_edge : GetBackEdges()) {
-    DCHECK(back_edge->GetDominator() != nullptr);
-    if (!header_->Dominates(back_edge)) {
-      is_irreducible_loop = true;
-      break;
-    }
-  }
+  bool is_irreducible_loop = HasBackEdgeNotDominatedByHeader();
 
   if (is_irreducible_loop) {
     ArenaBitVector visited(graph->GetArena(),
                            graph->GetBlocks().size(),
                            /* expandable */ false,
                            kArenaAllocGraphBuilder);
+    // Stop marking blocks at the loop header.
+    visited.SetBit(header_->GetBlockId());
+
     for (HBasicBlock* back_edge : GetBackEdges()) {
       PopulateIrreducibleRecursive(back_edge, &visited);
     }
@@ -667,6 +709,16 @@
   return last_position;
 }
 
+bool HLoopInformation::HasBackEdgeNotDominatedByHeader() const {
+  for (HBasicBlock* back_edge : GetBackEdges()) {
+    DCHECK(back_edge->GetDominator() != nullptr);
+    if (!header_->Dominates(back_edge)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 bool HBasicBlock::Dominates(HBasicBlock* other) const {
   // Walk up the dominator tree from `other`, to find out if `this`
   // is an ancestor.
@@ -2396,6 +2448,7 @@
   }
   if (!NeedsEnvironment()) {
     RemoveEnvironment();
+    SetSideEffects(SideEffects::None());
   }
 }
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index afb995d..829fe71 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -725,6 +725,8 @@
     blocks_.ClearAllBits();
   }
 
+  bool HasBackEdgeNotDominatedByHeader() const;
+
  private:
   // Internal recursive implementation of `Populate`.
   void PopulateRecursive(HBasicBlock* block);
@@ -5530,6 +5532,7 @@
     SetPackedFlag<kFlagIsInDexCache>(true);
     DCHECK(!NeedsEnvironment());
     RemoveEnvironment();
+    SetSideEffects(SideEffects::None());
   }
 
   size_t InputCount() const OVERRIDE {
diff --git a/profman/profman.cc b/profman/profman.cc
index 3e632bc..b3454fa 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -216,7 +216,11 @@
   }
 
   void LogCompletionTime() {
-    LOG(INFO) << "profman took " << PrettyDuration(NanoTime() - start_ns_);
+    static constexpr uint64_t kLogThresholdTime = MsToNs(100);  // 100ms
+    uint64_t time_taken = NanoTime() - start_ns_;
+    if (time_taken > kLogThresholdTime) {
+      LOG(WARNING) << "profman took " << PrettyDuration(NanoTime() - start_ns_);
+    }
   }
 
   std::vector<std::string> profile_files_;
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index f58af5a..5bdb36c 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -418,26 +418,6 @@
   (*icu_cleanup_fn)();
 
   Runtime::Current()->GetHeap()->VerifyHeap();  // Check for heap corruption after the test
-
-  // Manually closing the JNI libraries.
-  // Runtime does not support repeatedly doing JNI->CreateVM, thus we need to manually clean up the
-  // dynamic linking loader so that gtests would not fail.
-  // Bug: 25785594
-  if (runtime_->IsStarted()) {
-    {
-      // We retrieve the handle by calling dlopen on the library. To close it, we need to call
-      // dlclose twice, the first time to undo our dlopen and the second time to actually unload it.
-      // See man dlopen.
-      void* handle = dlopen("libjavacore.so", RTLD_LAZY);
-      dlclose(handle);
-      CHECK_EQ(0, dlclose(handle));
-    }
-    {
-      void* handle = dlopen("libopenjdkd.so", RTLD_LAZY);
-      dlclose(handle);
-      CHECK_EQ(0, dlclose(handle));
-    }
-  }
 }
 
 static std::string GetDexFileName(const std::string& jar_prefix, bool host) {
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 3df4e98..c504074 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -2358,7 +2358,8 @@
 static std::string GetStringOrError(const uint8_t* const begin,
                                     const DexFile::Header* const header,
                                     uint32_t string_idx) {
-  if (header->string_ids_size_ < string_idx) {
+  // The `string_idx` is not guaranteed to be valid yet.
+  if (header->string_ids_size_ <= string_idx) {
     return "(error)";
   }
 
@@ -2375,9 +2376,11 @@
 static std::string GetClassOrError(const uint8_t* const begin,
                                    const DexFile::Header* const header,
                                    uint32_t class_idx) {
-  if (header->type_ids_size_ < class_idx) {
-    return "(error)";
-  }
+  // The `class_idx` is either `FieldId::class_idx_` or `MethodId::class_idx_` and
+  // it has already been checked in `DexFileVerifier::CheckClassDataItemField()`
+  // or `DexFileVerifier::CheckClassDataItemMethod()`, respectively, to match
+  // a valid defining class.
+  CHECK_LT(class_idx, header->type_ids_size_);
 
   const DexFile::TypeId* type_id =
       reinterpret_cast<const DexFile::TypeId*>(begin + header->type_ids_off_) + class_idx;
@@ -2390,9 +2393,8 @@
 static std::string GetFieldDescriptionOrError(const uint8_t* const begin,
                                               const DexFile::Header* const header,
                                               uint32_t idx) {
-  if (header->field_ids_size_ < idx) {
-    return "(error)";
-  }
+  // The `idx` has already been checked in `DexFileVerifier::CheckClassDataItemField()`.
+  CHECK_LT(idx, header->field_ids_size_);
 
   const DexFile::FieldId* field_id =
       reinterpret_cast<const DexFile::FieldId*>(begin + header->field_ids_off_) + idx;
@@ -2408,9 +2410,8 @@
 static std::string GetMethodDescriptionOrError(const uint8_t* const begin,
                                                const DexFile::Header* const header,
                                                uint32_t idx) {
-  if (header->method_ids_size_ < idx) {
-    return "(error)";
-  }
+  // The `idx` has already been checked in `DexFileVerifier::CheckClassDataItemMethod()`.
+  CHECK_LT(idx, header->method_ids_size_);
 
   const DexFile::MethodId* method_id =
       reinterpret_cast<const DexFile::MethodId*>(begin + header->method_ids_off_) + idx;
@@ -2608,7 +2609,13 @@
       *error_msg = StringPrintf("Constructor %" PRIu32 "(%s) is not flagged correctly wrt/ static.",
                                 method_index,
                                 GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
-      return false;
+      if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+        return false;
+      } else {
+        // Allow in older versions, but warn.
+        LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
+                     << *error_msg;
+      }
     }
   }
   // Check that static and private methods, as well as constructors, are in the direct methods list,
@@ -2662,7 +2669,13 @@
       *error_msg = StringPrintf("Constructor %u(%s) must not be abstract or native",
                                 method_index,
                                 GetMethodDescriptionOrError(begin_, header_, method_index).c_str());
-      return false;
+      if (header_->GetVersion() >= DexFile::kDefaultMethodsVersion) {
+        return false;
+      } else {
+        // Allow in older versions, but warn.
+        LOG(WARNING) << "This dex file is invalid and will be rejected in the future. Error is: "
+                      << *error_msg;
+      }
     }
     if ((method_access_flags & kAccAbstract) != 0) {
       // Abstract methods are not allowed to have the following flags.
diff --git a/runtime/dex_file_verifier_test.cc b/runtime/dex_file_verifier_test.cc
index 344d186..177a373 100644
--- a/runtime/dex_file_verifier_test.cc
+++ b/runtime/dex_file_verifier_test.cc
@@ -57,7 +57,14 @@
   255, 255, 255, 255
 };
 
-static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
+// Make the Dex file version 37.
+static void MakeDexVersion37(DexFile* dex_file) {
+  size_t offset = OFFSETOF_MEMBER(DexFile::Header, magic_) + 6;
+  CHECK_EQ(*(dex_file->Begin() + offset), '5');
+  *(const_cast<uint8_t*>(dex_file->Begin()) + offset) = '7';
+}
+
+static inline std::unique_ptr<uint8_t[]> DecodeBase64(const char* src, size_t* dst_size) {
   std::vector<uint8_t> tmp;
   uint32_t t = 0, y = 0;
   int g = 3;
@@ -100,7 +107,7 @@
     *dst_size = 0;
   }
   std::copy(tmp.begin(), tmp.end(), dst.get());
-  return dst.release();
+  return dst;
 }
 
 static void FixUpChecksum(uint8_t* dex_file) {
@@ -113,25 +120,18 @@
   header->checksum_ = adler_checksum;
 }
 
-// Custom deleter. Necessary to clean up the memory we use (to be able to mutate).
-struct DexFileDeleter {
-  void operator()(DexFile* in) {
-    if (in != nullptr) {
-      delete[] in->Begin();
-      delete in;
-    }
-  }
-};
-
-using DexFileUniquePtr = std::unique_ptr<DexFile, DexFileDeleter>;
-
 class DexFileVerifierTest : public CommonRuntimeTest {
  protected:
   void VerifyModification(const char* dex_file_base64_content,
                           const char* location,
                           std::function<void(DexFile*)> f,
                           const char* expected_error) {
-    DexFileUniquePtr dex_file(WrapAsDexFile(dex_file_base64_content));
+    size_t length;
+    std::unique_ptr<uint8_t[]> dex_bytes = DecodeBase64(dex_file_base64_content, &length);
+    CHECK(dex_bytes != nullptr);
+    // Note: `dex_file` will be destroyed before `dex_bytes`.
+    std::unique_ptr<DexFile> dex_file(
+        new DexFile(dex_bytes.get(), length, "tmp", 0, nullptr, nullptr));
     f(dex_file.get());
     FixUpChecksum(const_cast<uint8_t*>(dex_file->Begin()));
 
@@ -150,15 +150,6 @@
       }
     }
   }
-
- private:
-  static DexFile* WrapAsDexFile(const char* dex_file_content_in_base_64) {
-    // Decode base64.
-    size_t length;
-    uint8_t* dex_bytes = DecodeBase64(dex_file_content_in_base_64, &length);
-    CHECK(dex_bytes != nullptr);
-    return new DexFile(dex_bytes, length, "tmp", 0, nullptr, nullptr);
-  }
 };
 
 static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
@@ -290,7 +281,9 @@
 // Find the method data for the first method with the given name (from class 0). Note: the pointer
 // is to the access flags, so that the caller doesn't have to handle the leb128-encoded method-index
 // delta.
-static const uint8_t* FindMethodData(const DexFile* dex_file, const char* name) {
+static const uint8_t* FindMethodData(const DexFile* dex_file,
+                                     const char* name,
+                                     /*out*/ uint32_t* method_idx = nullptr) {
   const DexFile::ClassDef& class_def = dex_file->GetClassDef(0);
   const uint8_t* class_data = dex_file->GetClassData(class_def);
 
@@ -316,6 +309,9 @@
     const DexFile::StringId& string_id = dex_file->GetStringId(name_index);
     const char* str = dex_file->GetStringData(string_id);
     if (strcmp(name, str) == 0) {
+      if (method_idx != nullptr) {
+        *method_idx = method_index;
+      }
       DecodeUnsignedLeb128(&trailing);
       return trailing;
     }
@@ -449,6 +445,7 @@
         kMethodFlagsTestDex,
         "method_flags_constructor_native_nocode",
         [&](DexFile* dex_file) {
+          MakeDexVersion37(dex_file);
           ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
           ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
 
@@ -461,6 +458,7 @@
         kMethodFlagsTestDex,
         "method_flags_constructor_abstract_nocode",
         [&](DexFile* dex_file) {
+          MakeDexVersion37(dex_file);
           ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
           ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
 
@@ -521,6 +519,7 @@
       kMethodFlagsTestDex,
       "init_not_allowed_flags",
       [&](DexFile* dex_file) {
+        MakeDexVersion37(dex_file);
         ApplyMaskToMethodFlags(dex_file, "foo", ~kAccDeclaredSynchronized);
         ApplyMaskToMethodFlags(dex_file, "bar", ~kAccDeclaredSynchronized);
 
@@ -683,6 +682,22 @@
   }
 }
 
+TEST_F(DexFileVerifierTest, B28552165) {
+  // Regression test for bad error string retrieval in different situations.
+  // Using invalid access flags to trigger the error.
+  VerifyModification(
+      kMethodFlagsTestDex,
+      "b28552165",
+      [](DexFile* dex_file) {
+        OrMaskToMethodFlags(dex_file, "foo", kAccPublic | kAccProtected);
+        uint32_t method_idx;
+        FindMethodData(dex_file, "foo", &method_idx);
+        auto* method_id = const_cast<DexFile::MethodId*>(&dex_file->GetMethodId(method_idx));
+        method_id->name_idx_ = dex_file->NumStringIds();
+      },
+      "Method may have only one of public/protected/private, LMethodFlags;.(error)");
+}
+
 // Set of dex files for interface method tests. As it's not as easy to mutate method names, it's
 // just easier to break up bad cases.
 
@@ -725,13 +740,6 @@
   return result;
 }
 
-// Make the Dex file version 37.
-static void MakeDexVersion37(DexFile* dex_file) {
-  size_t offset = OFFSETOF_MEMBER(DexFile::Header, magic_) + 6;
-  CHECK_EQ(*(dex_file->Begin() + offset), '5');
-  *(const_cast<uint8_t*>(dex_file->Begin()) + offset) = '7';
-}
-
 TEST_F(DexFileVerifierTest, MethodAccessFlagsInterfaces) {
   VerifyModification(
       kMethodFlagsInterface,
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 81a396a..6c630cc 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -515,8 +515,24 @@
       // instruction, as it already executed.
       // TODO: should be tested more once b/17586779 is fixed.
       const Instruction* instr = Instruction::At(&code_item->insns_[dex_pc]);
-      DCHECK(instr->IsInvoke());
-      new_dex_pc = dex_pc + instr->SizeInCodeUnits();
+      if (instr->IsInvoke()) {
+        new_dex_pc = dex_pc + instr->SizeInCodeUnits();
+      } else if (instr->Opcode() == Instruction::NEW_INSTANCE) {
+        // It's possible to deoptimize at a NEW_INSTANCE dex instruciton that's for a
+        // java string, which is turned into a call into StringFactory.newEmptyString();
+        if (kIsDebugBuild) {
+          ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+          mirror::Class* klass = class_linker->ResolveType(
+              instr->VRegB_21c(), shadow_frame->GetMethod());
+          DCHECK(klass->IsStringClass());
+        }
+        // Skip the dex instruction since we essentially come back from an invocation.
+        new_dex_pc = dex_pc + instr->SizeInCodeUnits();
+      } else {
+        DCHECK(false) << "Unexpected instruction opcode " << instr->Opcode()
+                      << " at dex_pc " << dex_pc
+                      << " of method: " << PrettyMethod(shadow_frame->GetMethod(), false);
+      }
     } else {
       // Nothing to do, the dex_pc is the one at which the code requested
       // the deoptimization.
diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc
index 2bdf8d1..8619ff7 100644
--- a/test/004-JniTest/jni_test.cc
+++ b/test/004-JniTest/jni_test.cc
@@ -14,23 +14,22 @@
  * limitations under the License.
  */
 
-#include <assert.h>
 #include <iostream>
 #include <pthread.h>
 #include <stdio.h>
 #include <vector>
 
+#include "art_method-inl.h"
+#include "base/logging.h"
 #include "jni.h"
 
-#if defined(NDEBUG)
-#error test code compiled without NDEBUG
-#endif
+namespace art {
 
 static JavaVM* jvm = nullptr;
 
 extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void*) {
-  assert(vm != nullptr);
-  assert(jvm == nullptr);
+  CHECK(vm != nullptr);
+  CHECK(jvm == nullptr);
   jvm = vm;
   std::cout << "JNI_OnLoad called" << std::endl;
   return JNI_VERSION_1_6;
@@ -39,24 +38,24 @@
 extern "C" JNIEXPORT void JNI_OnUnload(JavaVM*, void*) {
   // std::cout since LOG(INFO) adds extra stuff like pid.
   std::cout << "JNI_OnUnload called" << std::endl;
-  // Clear jvm for assert in test 004-JniTest.
+  // Clear jvm for CHECK in test 004-JniTest.
   jvm = nullptr;
 }
 
 static void* AttachHelper(void* arg) {
-  assert(jvm != nullptr);
+  CHECK(jvm != nullptr);
 
   JNIEnv* env = nullptr;
   JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, nullptr };
   int attach_result = jvm->AttachCurrentThread(&env, &args);
-  assert(attach_result == 0);
+  CHECK_EQ(attach_result, 0);
 
   typedef void (*Fn)(JNIEnv*);
   Fn fn = reinterpret_cast<Fn>(arg);
   fn(env);
 
   int detach_result = jvm->DetachCurrentThread();
-  assert(detach_result == 0);
+  CHECK_EQ(detach_result, 0);
   return nullptr;
 }
 
@@ -64,19 +63,19 @@
   pthread_t pthread;
   int pthread_create_result = pthread_create(&pthread, nullptr, AttachHelper,
                                              reinterpret_cast<void*>(fn));
-  assert(pthread_create_result == 0);
+  CHECK_EQ(pthread_create_result, 0);
   int pthread_join_result = pthread_join(pthread, nullptr);
-  assert(pthread_join_result == 0);
+  CHECK_EQ(pthread_join_result, 0);
 }
 
 static void testFindClassOnAttachedNativeThread(JNIEnv* env) {
   jclass clazz = env->FindClass("Main");
-  assert(clazz != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(clazz != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jobjectArray array = env->NewObjectArray(0, clazz, nullptr);
-  assert(array != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(array != nullptr);
+  CHECK(!env->ExceptionCheck());
 }
 
 // http://b/10994325
@@ -86,12 +85,12 @@
 
 static void testFindFieldOnAttachedNativeThread(JNIEnv* env) {
   jclass clazz = env->FindClass("Main");
-  assert(clazz != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(clazz != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z");
-  assert(field != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(field != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   env->SetStaticBooleanField(clazz, field, JNI_TRUE);
 }
@@ -103,38 +102,38 @@
 
 static void testReflectFieldGetFromAttachedNativeThread(JNIEnv* env) {
   jclass clazz = env->FindClass("Main");
-  assert(clazz != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(clazz != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jclass class_clazz = env->FindClass("java/lang/Class");
-  assert(class_clazz != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(class_clazz != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jmethodID getFieldMetodId = env->GetMethodID(class_clazz, "getField",
                                                "(Ljava/lang/String;)Ljava/lang/reflect/Field;");
-  assert(getFieldMetodId != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(getFieldMetodId != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jstring field_name = env->NewStringUTF("testReflectFieldGetFromAttachedNativeThreadField");
-  assert(field_name != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(field_name != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jobject field = env->CallObjectMethod(clazz, getFieldMetodId, field_name);
-  assert(field != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(field != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jclass field_clazz = env->FindClass("java/lang/reflect/Field");
-  assert(field_clazz != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(field_clazz != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jmethodID getBooleanMetodId = env->GetMethodID(field_clazz, "getBoolean",
                                                  "(Ljava/lang/Object;)Z");
-  assert(getBooleanMetodId != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(getBooleanMetodId != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   jboolean value = env->CallBooleanMethod(field, getBooleanMetodId, /* ignored */ clazz);
-  assert(value == false);
-  assert(!env->ExceptionCheck());
+  CHECK(value == false);
+  CHECK(!env->ExceptionCheck());
 }
 
 // http://b/15539150
@@ -148,22 +147,22 @@
 extern "C" JNIEXPORT void JNICALL Java_Main_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
                                                                                      jclass) {
   jclass super_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SuperClass");
-  assert(super_class != nullptr);
+  CHECK(super_class != nullptr);
 
   jmethodID execute = env->GetStaticMethodID(super_class, "execute", "()V");
-  assert(execute != nullptr);
+  CHECK(execute != nullptr);
 
   jclass sub_class = env->FindClass("Main$testCallStaticVoidMethodOnSubClass_SubClass");
-  assert(sub_class != nullptr);
+  CHECK(sub_class != nullptr);
 
   env->CallStaticVoidMethod(sub_class, execute);
 }
 
 extern "C" JNIEXPORT jobject JNICALL Java_Main_testGetMirandaMethodNative(JNIEnv* env, jclass) {
   jclass abstract_class = env->FindClass("Main$testGetMirandaMethod_MirandaAbstract");
-  assert(abstract_class != nullptr);
+  CHECK(abstract_class != nullptr);
   jmethodID miranda_method = env->GetMethodID(abstract_class, "inInterface", "()Z");
-  assert(miranda_method != nullptr);
+  CHECK(miranda_method != nullptr);
   return env->ToReflectedMethod(abstract_class, miranda_method, JNI_FALSE);
 }
 
@@ -171,11 +170,11 @@
 extern "C" void JNICALL Java_Main_testZeroLengthByteBuffers(JNIEnv* env, jclass) {
   std::vector<uint8_t> buffer(1);
   jobject byte_buffer = env->NewDirectByteBuffer(&buffer[0], 0);
-  assert(byte_buffer != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(byte_buffer != nullptr);
+  CHECK(!env->ExceptionCheck());
 
-  assert(env->GetDirectBufferAddress(byte_buffer) == &buffer[0]);
-  assert(env->GetDirectBufferCapacity(byte_buffer) == 0);
+  CHECK_EQ(env->GetDirectBufferAddress(byte_buffer), &buffer[0]);
+  CHECK_EQ(env->GetDirectBufferCapacity(byte_buffer), 0);
 }
 
 constexpr size_t kByteReturnSize = 7;
@@ -185,18 +184,18 @@
                                               jbyte b3, jbyte b4, jbyte b5, jbyte b6,
                                               jbyte b7, jbyte b8, jbyte b9, jbyte b10) {
   // We use b1 to drive the output.
-  assert(b2 == 2);
-  assert(b3 == -3);
-  assert(b4 == 4);
-  assert(b5 == -5);
-  assert(b6 == 6);
-  assert(b7 == -7);
-  assert(b8 == 8);
-  assert(b9 == -9);
-  assert(b10 == 10);
+  CHECK_EQ(b2, 2);
+  CHECK_EQ(b3, -3);
+  CHECK_EQ(b4, 4);
+  CHECK_EQ(b5, -5);
+  CHECK_EQ(b6, 6);
+  CHECK_EQ(b7, -7);
+  CHECK_EQ(b8, 8);
+  CHECK_EQ(b9, -9);
+  CHECK_EQ(b10, 10);
 
-  assert(0 <= b1);
-  assert(b1 < static_cast<jbyte>(kByteReturnSize));
+  CHECK_LE(0, b1);
+  CHECK_LT(b1, static_cast<jbyte>(kByteReturnSize));
 
   return byte_returns[b1];
 }
@@ -210,18 +209,18 @@
                                                 jshort s3, jshort s4, jshort s5, jshort s6,
                                                 jshort s7, jshort s8, jshort s9, jshort s10) {
   // We use s1 to drive the output.
-  assert(s2 == 2);
-  assert(s3 == -3);
-  assert(s4 == 4);
-  assert(s5 == -5);
-  assert(s6 == 6);
-  assert(s7 == -7);
-  assert(s8 == 8);
-  assert(s9 == -9);
-  assert(s10 == 10);
+  CHECK_EQ(s2, 2);
+  CHECK_EQ(s3, -3);
+  CHECK_EQ(s4, 4);
+  CHECK_EQ(s5, -5);
+  CHECK_EQ(s6, 6);
+  CHECK_EQ(s7, -7);
+  CHECK_EQ(s8, 8);
+  CHECK_EQ(s9, -9);
+  CHECK_EQ(s10, 10);
 
-  assert(0 <= s1);
-  assert(s1 < static_cast<jshort>(kShortReturnSize));
+  CHECK_LE(0, s1);
+  CHECK_LT(s1, static_cast<jshort>(kShortReturnSize));
 
   return short_returns[s1];
 }
@@ -231,17 +230,17 @@
                                                     jboolean b5, jboolean b6, jboolean b7,
                                                     jboolean b8, jboolean b9, jboolean b10) {
   // We use b1 to drive the output.
-  assert(b2 == JNI_TRUE);
-  assert(b3 == JNI_FALSE);
-  assert(b4 == JNI_TRUE);
-  assert(b5 == JNI_FALSE);
-  assert(b6 == JNI_TRUE);
-  assert(b7 == JNI_FALSE);
-  assert(b8 == JNI_TRUE);
-  assert(b9 == JNI_FALSE);
-  assert(b10 == JNI_TRUE);
+  CHECK_EQ(b2, JNI_TRUE);
+  CHECK_EQ(b3, JNI_FALSE);
+  CHECK_EQ(b4, JNI_TRUE);
+  CHECK_EQ(b5, JNI_FALSE);
+  CHECK_EQ(b6, JNI_TRUE);
+  CHECK_EQ(b7, JNI_FALSE);
+  CHECK_EQ(b8, JNI_TRUE);
+  CHECK_EQ(b9, JNI_FALSE);
+  CHECK_EQ(b10, JNI_TRUE);
 
-  assert(b1 == JNI_TRUE || b1 == JNI_FALSE);
+  CHECK(b1 == JNI_TRUE || b1 == JNI_FALSE);
   return b1;
 }
 
@@ -252,17 +251,17 @@
                                               jchar c3, jchar c4, jchar c5, jchar c6, jchar c7,
                                               jchar c8, jchar c9, jchar c10) {
   // We use c1 to drive the output.
-  assert(c2 == 'a');
-  assert(c3 == 'b');
-  assert(c4 == 'c');
-  assert(c5 == '0');
-  assert(c6 == '1');
-  assert(c7 == '2');
-  assert(c8 == 1234);
-  assert(c9 == 2345);
-  assert(c10 == 3456);
+  CHECK_EQ(c2, 'a');
+  CHECK_EQ(c3, 'b');
+  CHECK_EQ(c4, 'c');
+  CHECK_EQ(c5, '0');
+  CHECK_EQ(c6, '1');
+  CHECK_EQ(c7, '2');
+  CHECK_EQ(c8, 1234);
+  CHECK_EQ(c9, 2345);
+  CHECK_EQ(c10, 3456);
 
-  assert(c1 < static_cast<jchar>(kCharReturnSize));
+  CHECK_LT(c1, static_cast<jchar>(kCharReturnSize));
 
   return char_returns[c1];
 }
@@ -281,39 +280,39 @@
   // Test direct call.
   {
     jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack");
-    assert(vmstack_clazz != nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(vmstack_clazz != nullptr);
+    CHECK(!env->ExceptionCheck());
 
     jmethodID getCallingClassLoaderMethodId = env->GetStaticMethodID(vmstack_clazz,
                                                                      "getCallingClassLoader",
                                                                      "()Ljava/lang/ClassLoader;");
-    assert(getCallingClassLoaderMethodId != nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(getCallingClassLoaderMethodId != nullptr);
+    CHECK(!env->ExceptionCheck());
 
     jobject class_loader = env->CallStaticObjectMethod(vmstack_clazz,
                                                        getCallingClassLoaderMethodId);
-    assert(class_loader == nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(class_loader == nullptr);
+    CHECK(!env->ExceptionCheck());
   }
 
   // Test one-level call. Use System.loadLibrary().
   {
     jclass system_clazz = env->FindClass("java/lang/System");
-    assert(system_clazz != nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(system_clazz != nullptr);
+    CHECK(!env->ExceptionCheck());
 
     jmethodID loadLibraryMethodId = env->GetStaticMethodID(system_clazz, "loadLibrary",
                                                            "(Ljava/lang/String;)V");
-    assert(loadLibraryMethodId != nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(loadLibraryMethodId != nullptr);
+    CHECK(!env->ExceptionCheck());
 
     // Create a string object.
     jobject library_string = env->NewStringUTF("non_existing_library");
-    assert(library_string != nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(library_string != nullptr);
+    CHECK(!env->ExceptionCheck());
 
     env->CallStaticVoidMethod(system_clazz, loadLibraryMethodId, library_string);
-    assert(env->ExceptionCheck());
+    CHECK(env->ExceptionCheck());
 
     // We expect UnsatisfiedLinkError.
     jthrowable thrown = env->ExceptionOccurred();
@@ -321,7 +320,7 @@
 
     jclass unsatisfied_link_error_clazz = env->FindClass("java/lang/UnsatisfiedLinkError");
     jclass thrown_class = env->GetObjectClass(thrown);
-    assert(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
+    CHECK(env->IsSameObject(unsatisfied_link_error_clazz, thrown_class));
   }
 }
 
@@ -333,31 +332,31 @@
 
 static void testShallowGetStackClass2(JNIEnv* env) {
   jclass vmstack_clazz = env->FindClass("dalvik/system/VMStack");
-  assert(vmstack_clazz != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(vmstack_clazz != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   // Test direct call.
   {
     jmethodID getStackClass2MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass2",
                                                               "()Ljava/lang/Class;");
-    assert(getStackClass2MethodId != nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(getStackClass2MethodId != nullptr);
+    CHECK(!env->ExceptionCheck());
 
     jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass2MethodId);
-    assert(caller_class == nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(caller_class == nullptr);
+    CHECK(!env->ExceptionCheck());
   }
 
   // Test one-level call. Use VMStack.getStackClass1().
   {
     jmethodID getStackClass1MethodId = env->GetStaticMethodID(vmstack_clazz, "getStackClass1",
                                                               "()Ljava/lang/Class;");
-    assert(getStackClass1MethodId != nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(getStackClass1MethodId != nullptr);
+    CHECK(!env->ExceptionCheck());
 
     jobject caller_class = env->CallStaticObjectMethod(vmstack_clazz, getStackClass1MethodId);
-    assert(caller_class == nullptr);
-    assert(!env->ExceptionCheck());
+    CHECK(caller_class == nullptr);
+    CHECK(!env->ExceptionCheck());
   }
 
   // For better testing we would need to compile against libcore and have a two-deep stack
@@ -416,8 +415,8 @@
       env_->ExceptionDescribe();
       env_->FatalError(__FUNCTION__);
     }
-    assert(!env_->ExceptionCheck());
-    assert(c != nullptr);
+    CHECK(!env_->ExceptionCheck());
+    CHECK(c != nullptr);
     return c;
   }
 
@@ -429,7 +428,7 @@
       env_->ExceptionDescribe();
       env_->FatalError(__FUNCTION__);
     }
-    assert(m != nullptr);
+    CHECK(m != nullptr);
     return m;
   }
 
@@ -439,7 +438,7 @@
       env_->ExceptionDescribe();
       env_->FatalError(__FUNCTION__);
     }
-    assert(o != nullptr);
+    CHECK(o != nullptr);
     return o;
   }
 
@@ -467,7 +466,7 @@
       env_->ExceptionDescribe();
       env_->FatalError(__FUNCTION__);
     }
-    assert(m != nullptr);
+    CHECK(m != nullptr);
     return m;
   }
 
@@ -508,21 +507,21 @@
     jobject sub_super = CallConstructor(sub_, super_constructor_);
     jobject sub_sub = CallConstructor(sub_, sub_constructor_);
 
-    assert(env_->IsInstanceOf(super_super, super_));
-    assert(!env_->IsInstanceOf(super_super, sub_));
+    CHECK(env_->IsInstanceOf(super_super, super_));
+    CHECK(!env_->IsInstanceOf(super_super, sub_));
 
     // Note that even though we called (and ran) the subclass
     // constructor, we are not the subclass.
-    assert(env_->IsInstanceOf(super_sub, super_));
-    assert(!env_->IsInstanceOf(super_sub, sub_));
+    CHECK(env_->IsInstanceOf(super_sub, super_));
+    CHECK(!env_->IsInstanceOf(super_sub, sub_));
 
     // Note that even though we called the superclass constructor, we
     // are still the subclass.
-    assert(env_->IsInstanceOf(sub_super, super_));
-    assert(env_->IsInstanceOf(sub_super, sub_));
+    CHECK(env_->IsInstanceOf(sub_super, super_));
+    CHECK(env_->IsInstanceOf(sub_super, sub_));
 
-    assert(env_->IsInstanceOf(sub_sub, super_));
-    assert(env_->IsInstanceOf(sub_sub, sub_));
+    CHECK(env_->IsInstanceOf(sub_sub, super_));
+    CHECK(env_->IsInstanceOf(sub_sub, sub_));
   }
 
   void TestnonstaticCallNonvirtualMethod(bool super_object, bool super_class, bool super_method, const char* test_case) {
@@ -542,8 +541,8 @@
     CallMethod(o, c, m, true, test_case);
     jboolean super_field = GetBooleanField(o, super_field_);
     jboolean sub_field = GetBooleanField(o, sub_field_);
-    assert(super_field == super_method);
-    assert(sub_field != super_method);
+    CHECK_EQ(super_field, super_method);
+    CHECK_NE(sub_field, super_method);
   }
 
   void TestnonstaticCallNonvirtualMethod() {
@@ -565,20 +564,20 @@
 
 extern "C" JNIEXPORT void JNICALL Java_Main_testNewStringObject(JNIEnv* env, jclass) {
   jclass c = env->FindClass("java/lang/String");
-  assert(c != nullptr);
+  CHECK(c != nullptr);
 
   jmethodID mid1 = env->GetMethodID(c, "<init>", "()V");
-  assert(mid1 != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(mid1 != nullptr);
+  CHECK(!env->ExceptionCheck());
   jmethodID mid2 = env->GetMethodID(c, "<init>", "([B)V");
-  assert(mid2 != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(mid2 != nullptr);
+  CHECK(!env->ExceptionCheck());
   jmethodID mid3 = env->GetMethodID(c, "<init>", "([C)V");
-  assert(mid3 != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(mid3 != nullptr);
+  CHECK(!env->ExceptionCheck());
   jmethodID mid4 = env->GetMethodID(c, "<init>", "(Ljava/lang/String;)V");
-  assert(mid4 != nullptr);
-  assert(!env->ExceptionCheck());
+  CHECK(mid4 != nullptr);
+  CHECK(!env->ExceptionCheck());
 
   const char* test_array = "Test";
   int byte_array_length = strlen(test_array);
@@ -587,22 +586,22 @@
 
   // Test NewObject
   jstring s = reinterpret_cast<jstring>(env->NewObject(c, mid2, byte_array));
-  assert(s != nullptr);
-  assert(env->GetStringLength(s) == byte_array_length);
-  assert(env->GetStringUTFLength(s) == byte_array_length);
+  CHECK(s != nullptr);
+  CHECK_EQ(env->GetStringLength(s), byte_array_length);
+  CHECK_EQ(env->GetStringUTFLength(s), byte_array_length);
   const char* chars = env->GetStringUTFChars(s, nullptr);
-  assert(strcmp(test_array, chars) == 0);
+  CHECK_EQ(strcmp(test_array, chars), 0);
   env->ReleaseStringUTFChars(s, chars);
 
   // Test AllocObject and Call(Nonvirtual)VoidMethod
   jstring s1 = reinterpret_cast<jstring>(env->AllocObject(c));
-  assert(s1 != nullptr);
+  CHECK(s1 != nullptr);
   jstring s2 = reinterpret_cast<jstring>(env->AllocObject(c));
-  assert(s2 != nullptr);
+  CHECK(s2 != nullptr);
   jstring s3 = reinterpret_cast<jstring>(env->AllocObject(c));
-  assert(s3 != nullptr);
+  CHECK(s3 != nullptr);
   jstring s4 = reinterpret_cast<jstring>(env->AllocObject(c));
-  assert(s4 != nullptr);
+  CHECK(s4 != nullptr);
 
   jcharArray char_array = env->NewCharArray(5);
   jstring string_arg = env->NewStringUTF("helloworld");
@@ -621,18 +620,18 @@
 
   // Test with global and weak global references
   jstring s5 = reinterpret_cast<jstring>(env->AllocObject(c));
-  assert(s5 != nullptr);
+  CHECK(s5 != nullptr);
   s5 = reinterpret_cast<jstring>(env->NewGlobalRef(s5));
   jstring s6 = reinterpret_cast<jstring>(env->AllocObject(c));
-  assert(s6 != nullptr);
+  CHECK(s6 != nullptr);
   s6 = reinterpret_cast<jstring>(env->NewWeakGlobalRef(s6));
 
   env->CallVoidMethod(s5, mid1);
   env->CallNonvirtualVoidMethod(s6, c, mid2, byte_array);
-  assert(env->GetStringLength(s5) == 0);
-  assert(env->GetStringLength(s6) == byte_array_length);
+  CHECK_EQ(env->GetStringLength(s5), 0);
+  CHECK_EQ(env->GetStringLength(s6), byte_array_length);
   const char* chars6 = env->GetStringUTFChars(s6, nullptr);
-  assert(strcmp(test_array, chars6) == 0);
+  CHECK_EQ(strcmp(test_array, chars6), 0);
   env->ReleaseStringUTFChars(s6, chars6);
 }
 
@@ -664,8 +663,8 @@
  public:
   explicit JniCallDefaultMethodsTest(JNIEnv* env)
       : env_(env), concrete_class_(env_->FindClass("ConcreteClass")) {
-    assert(!env_->ExceptionCheck());
-    assert(concrete_class_ != nullptr);
+    CHECK(!env_->ExceptionCheck());
+    CHECK(concrete_class_ != nullptr);
   }
 
   void Test() {
@@ -688,14 +687,14 @@
   void TestCalls(const char* declaring_class, std::vector<const char*> methods) {
     jmethodID new_method = env_->GetMethodID(concrete_class_, "<init>", "()V");
     jobject obj = env_->NewObject(concrete_class_, new_method);
-    assert(!env_->ExceptionCheck());
-    assert(obj != nullptr);
+    CHECK(!env_->ExceptionCheck());
+    CHECK(obj != nullptr);
     jclass decl_class = env_->FindClass(declaring_class);
-    assert(!env_->ExceptionCheck());
-    assert(decl_class != nullptr);
+    CHECK(!env_->ExceptionCheck());
+    CHECK(decl_class != nullptr);
     for (const char* method : methods) {
       jmethodID method_id = env_->GetMethodID(decl_class, method, "()V");
-      assert(!env_->ExceptionCheck());
+      CHECK(!env_->ExceptionCheck());
       printf("Calling method %s->%s on object of type ConcreteClass\n", declaring_class, method);
       env_->CallVoidMethod(obj, method_id);
       if (env_->ExceptionCheck()) {
@@ -704,10 +703,10 @@
         jmethodID to_string = env_->GetMethodID(
             env_->FindClass("java/lang/Object"), "toString", "()Ljava/lang/String;");
         jstring exception_string = (jstring) env_->CallObjectMethod(thrown, to_string);
-        assert(!env_->ExceptionCheck());
+        CHECK(!env_->ExceptionCheck());
         const char* exception_string_utf8 = env_->GetStringUTFChars(exception_string, nullptr);
-        assert(!env_->ExceptionCheck());
-        assert(exception_string_utf8 != nullptr);
+        CHECK(!env_->ExceptionCheck());
+        CHECK(exception_string_utf8 != nullptr);
         printf("EXCEPTION OCCURED: %s\n", exception_string_utf8);
         env_->ReleaseStringUTFChars(exception_string, exception_string_utf8);
       }
@@ -724,12 +723,12 @@
 
 static void InvokeSpecificMethod(JNIEnv* env, jobject obj, const char* method) {
   jclass lambda_class = env->FindClass("LambdaInterface");
-  assert(!env->ExceptionCheck());
-  assert(lambda_class != nullptr);
+  CHECK(!env->ExceptionCheck());
+  CHECK(lambda_class != nullptr);
   jmethodID method_id = env->GetMethodID(lambda_class, method, "()V");
-  assert(!env->ExceptionCheck());
+  CHECK(!env->ExceptionCheck());
   env->CallVoidMethod(obj, method_id);
-  assert(!env->ExceptionCheck());
+  CHECK(!env->ExceptionCheck());
 }
 
 extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaDefaultMethod(
@@ -740,3 +739,6 @@
 extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaMethod(JNIEnv* e, jclass, jobject l) {
   InvokeSpecificMethod(e, l, "sayHi");
 }
+
+}  // namespace art
+
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index 284e554..5304590 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "art_method-inl.h"
 #include "check_reference_map_visitor.h"
 #include "jni.h"
 
diff --git a/test/004-StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc
index 51bb68f..420224d 100644
--- a/test/004-StackWalk/stack_walk_jni.cc
+++ b/test/004-StackWalk/stack_walk_jni.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "art_method-inl.h"
 #include "check_reference_map_visitor.h"
 #include "jni.h"
 
diff --git a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
index 54879fb..c9110a9 100644
--- a/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
+++ b/test/136-daemon-jni-shutdown/daemon_jni_shutdown.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <dlfcn.h>
 #include <iostream>
 
 #include "base/casts.h"
@@ -45,6 +46,10 @@
   self->SetTopOfShadowStack(nullptr);
   JavaVM* vm = down_cast<JNIEnvExt*>(env)->vm;
   vm->DetachCurrentThread();
+  // Open ourself again to make sure the native library does not get unloaded from
+  // underneath us due to DestroyJavaVM. b/28406866
+  void* handle = dlopen(kIsDebugBuild ? "libarttestd.so" : "libarttest.so", RTLD_NOW);
+  CHECK(handle != nullptr);
   vm->DestroyJavaVM();
   vm_was_shutdown.store(true);
   // Give threads some time to get stuck in ExceptionCheck.
diff --git a/test/566-polymorphic-inlining/src/Main.java b/test/566-polymorphic-inlining/src/Main.java
index 286f0d9..a59ce5b 100644
--- a/test/566-polymorphic-inlining/src/Main.java
+++ b/test/566-polymorphic-inlining/src/Main.java
@@ -98,6 +98,7 @@
   public static native void ensureJittedAndPolymorphicInline();
 
   public void increment() {
+    field.getClass(); // null check to ensure we get an inlined frame in the CodeInfo
     counter++;
   }
   public static int counter = 0;
diff --git a/test/570-checker-osr/osr.cc b/test/570-checker-osr/osr.cc
index bd8f0a9..2fa5800 100644
--- a/test/570-checker-osr/osr.cc
+++ b/test/570-checker-osr/osr.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "art_method.h"
+#include "art_method-inl.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
 #include "jit/profiling_info.h"
diff --git a/test/594-load-string-regression/expected.txt b/test/594-load-string-regression/expected.txt
new file mode 100644
index 0000000..365b0e1
--- /dev/null
+++ b/test/594-load-string-regression/expected.txt
@@ -0,0 +1 @@
+String: ""
diff --git a/test/594-load-string-regression/info.txt b/test/594-load-string-regression/info.txt
new file mode 100644
index 0000000..6a07ace
--- /dev/null
+++ b/test/594-load-string-regression/info.txt
@@ -0,0 +1,2 @@
+Regression test for LoadString listing side effects when it doesn't have any
+and triggering a DCHECK() failure when merging ClinitCheck into NewInstance.
diff --git a/test/594-load-string-regression/src/Main.java b/test/594-load-string-regression/src/Main.java
new file mode 100644
index 0000000..0b9f7b5
--- /dev/null
+++ b/test/594-load-string-regression/src/Main.java
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+public class Main {
+  static boolean doThrow = false;
+
+  // Note: We're not doing checker tests as we cannot do them specifically for a non-PIC
+  // configuration. The check here would be "prepare_for_register_allocation (before)"
+  //     CHECK:         LoadClass
+  //     CHECK-NEXT:    ClinitCheck
+  //     CHECK-NEXT:    LoadString load_kind:BootImageAddress
+  //     CHECK-NEXT:    NewInstance
+  // and "prepare_for_register_allocation (after)"
+  //     CHECK:         LoadString
+  //     CHECK-NEXT:    NewInstance
+  // but the order of instructions for non-PIC mode is different.
+  public static int $noinline$test() {
+    if (doThrow) { throw new Error(); }
+
+    int r = 0x12345678;
+    do {
+      // LICM pulls the LoadClass and ClinitCheck out of the loop, leaves NewInstance in the loop.
+      Helper h = new Helper();
+      // For non-PIC mode, LICM pulls the boot image LoadString out of the loop.
+      // (For PIC mode, the LoadString can throw and will not be moved out of the loop.)
+      String s = "";  // Empty string is known to be in the boot image.
+      r = r ^ (r >> 5);
+      h.$noinline$printString(s);
+      // During DCE after inlining, the loop back-edge disappears and the pre-header is
+      // merged with the body, leaving consecutive LoadClass, ClinitCheck, LoadString
+      // and NewInstance in non-PIC mode. The prepare_for_register_allocation pass
+      // merges the LoadClass and ClinitCheck with the NewInstance and checks that
+      // there are no instructions with side effects in between. This check used to
+      // fail because LoadString was always listing SideEffects::CanTriggerGC() even
+      // when it doesn't really have any side effects, i.e. for direct references to
+      // boot image Strings or for Strings known to be in the dex cache.
+    } while ($inline$shouldContinue());
+    return r;
+  }
+
+  static boolean $inline$shouldContinue() {
+    return false;
+  }
+
+  public static void main(String[] args) {
+    assertIntEquals(0x12345678 ^ (0x12345678 >> 5), $noinline$test());
+  }
+
+  public static void assertIntEquals(int expected, int result) {
+    if (expected != result) {
+      throw new Error("Expected: " + expected + ", found: " + result);
+    }
+  }
+}
+
+class Helper {
+  static boolean doThrow = false;
+
+  public void $noinline$printString(String s) {
+    if (doThrow) { throw new Error(); }
+
+    System.out.println("String: \"" + s + "\"");
+  }
+}
diff --git a/test/595-profile-saving/profile-saving.cc b/test/595-profile-saving/profile-saving.cc
index a7e6f8b..0d26f45 100644
--- a/test/595-profile-saving/profile-saving.cc
+++ b/test/595-profile-saving/profile-saving.cc
@@ -16,6 +16,7 @@
 
 #include "dex_file.h"
 
+#include "art_method-inl.h"
 #include "jit/offline_profiling_info.h"
 #include "jit/profile_saver.h"
 #include "jni.h"
diff --git a/test/596-app-images/app_images.cc b/test/596-app-images/app_images.cc
index 11c0f42..a5bbf5f 100644
--- a/test/596-app-images/app_images.cc
+++ b/test/596-app-images/app_images.cc
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <assert.h>
 #include <iostream>
 #include <pthread.h>
 #include <stdio.h>
diff --git a/test/597-deopt-new-string/deopt.cc b/test/597-deopt-new-string/deopt.cc
new file mode 100644
index 0000000..844a786
--- /dev/null
+++ b/test/597-deopt-new-string/deopt.cc
@@ -0,0 +1,59 @@
+/*
+ * 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"
+#include "mirror/class-inl.h"
+#include "runtime.h"
+#include "thread_list.h"
+#include "thread_state.h"
+#include "gc/gc_cause.h"
+#include "gc/scoped_gc_critical_section.h"
+
+namespace art {
+
+extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeAll(
+    JNIEnv* env,
+    jclass cls ATTRIBUTE_UNUSED) {
+  ScopedObjectAccess soa(env);
+  ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization);
+  gc::ScopedGCCriticalSection gcs(Thread::Current(),
+                                  gc::kGcCauseInstrumentation,
+                                  gc::kCollectorTypeInstrumentation);
+  // We need to suspend mutator threads first.
+  ScopedSuspendAll ssa(__FUNCTION__);
+  static bool first = true;
+  if (first) {
+    // We need to enable deoptimization once in order to call DeoptimizeEverything().
+    Runtime::Current()->GetInstrumentation()->EnableDeoptimization();
+    first = false;
+  }
+  Runtime::Current()->GetInstrumentation()->DeoptimizeEverything("test");
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_undeoptimizeAll(
+    JNIEnv* env,
+    jclass cls ATTRIBUTE_UNUSED) {
+  ScopedObjectAccess soa(env);
+  ScopedThreadSuspension sts(Thread::Current(), kWaitingForDeoptimization);
+  gc::ScopedGCCriticalSection gcs(Thread::Current(),
+                                  gc::kGcCauseInstrumentation,
+                                  gc::kCollectorTypeInstrumentation);
+  // We need to suspend mutator threads first.
+  ScopedSuspendAll ssa(__FUNCTION__);
+  Runtime::Current()->GetInstrumentation()->UndeoptimizeEverything("test");
+}
+
+}  // namespace art
diff --git a/test/597-deopt-new-string/expected.txt b/test/597-deopt-new-string/expected.txt
new file mode 100644
index 0000000..f993efc
--- /dev/null
+++ b/test/597-deopt-new-string/expected.txt
@@ -0,0 +1,2 @@
+JNI_OnLoad called
+Finishing
diff --git a/test/597-deopt-new-string/info.txt b/test/597-deopt-new-string/info.txt
new file mode 100644
index 0000000..1bd1f79
--- /dev/null
+++ b/test/597-deopt-new-string/info.txt
@@ -0,0 +1 @@
+Regression test for b/28555675
diff --git a/test/597-deopt-new-string/run b/test/597-deopt-new-string/run
new file mode 100644
index 0000000..9776ab3
--- /dev/null
+++ b/test/597-deopt-new-string/run
@@ -0,0 +1,18 @@
+#!/bin/bash
+#
+# 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.
+
+# We want to run in debuggable mode which keeps the call into StringFactory.newEmptyString().
+exec ${RUN} -Xcompiler-option --debuggable "${@}"
diff --git a/test/597-deopt-new-string/src/Main.java b/test/597-deopt-new-string/src/Main.java
new file mode 100644
index 0000000..1224e40
--- /dev/null
+++ b/test/597-deopt-new-string/src/Main.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+public class Main implements Runnable {
+    static final int numberOfThreads = 2;
+    static final int totalOperations = 40000;
+    static boolean sFlag = false;
+    static volatile boolean done = false;
+    int threadIndex;
+
+    public static native void deoptimizeAll();
+    public static native void undeoptimizeAll();
+
+    Main(int index) {
+        threadIndex = index;
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.loadLibrary(args[0]);
+
+        final Thread[] threads = new Thread[numberOfThreads];
+        for (int t = 0; t < threads.length; t++) {
+            threads[t] = new Thread(new Main(t));
+            threads[t].start();
+        }
+        for (Thread t : threads) {
+            t.join();
+        }
+        System.out.println("Finishing");
+    }
+
+    public String $noinline$run0() {
+        // Prevent inlining.
+        if (sFlag) {
+            throw new Error();
+        }
+        char[] arr = {'a', 'b', 'c'};
+        return new String(arr, 0, arr.length);
+    }
+
+    public void run() {
+        if (threadIndex == 0) {
+            // This thread keeps doing deoptimization of all threads.
+            // Hopefully that will trigger one deoptimization when returning from
+            // StringFactory.newEmptyString() in one of the other threads.
+            for (int i = 0; i < totalOperations; ++i) {
+                if (i % 50 == 0) {
+                    deoptimizeAll();
+                }
+                if (i % 50 == 25) {
+                    undeoptimizeAll();
+                }
+            }
+            done = true;
+        } else {
+            // This thread keeps doing new String() from a char array.
+            while (!done) {
+                $noinline$run0();
+            }
+        }
+    }
+}
diff --git a/test/598-checker-irreducible-dominance/expected.txt b/test/598-checker-irreducible-dominance/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/598-checker-irreducible-dominance/expected.txt
diff --git a/test/598-checker-irreducible-dominance/info.txt b/test/598-checker-irreducible-dominance/info.txt
new file mode 100644
index 0000000..8ca4e63
--- /dev/null
+++ b/test/598-checker-irreducible-dominance/info.txt
@@ -0,0 +1,2 @@
+Regression test for HGraphBuilder which would compute wrong dominance information
+in the presence of irreducible loops.
\ No newline at end of file
diff --git a/test/598-checker-irreducible-dominance/smali/IrreducibleLoop.smali b/test/598-checker-irreducible-dominance/smali/IrreducibleLoop.smali
new file mode 100644
index 0000000..4d8b515
--- /dev/null
+++ b/test/598-checker-irreducible-dominance/smali/IrreducibleLoop.smali
@@ -0,0 +1,52 @@
+# 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.
+
+.class public LIrreducibleLoop;
+.super Ljava/lang/Object;
+
+# Test case in which `inner_back_edge` is not dominated by `inner_header` and
+# causes `outer_back_edge` to not be dominated by `outer_header`. HGraphBuilder
+# not do a fix-point iteration and would miss the path to `outer_back_edge`
+# through `inner_back_edge` and incorrectly label the outer loop non-irreducible.
+
+## CHECK-START: int IrreducibleLoop.dominance(int) builder (after)
+## CHECK:         Add irreducible:true
+
+.method public static dominance(I)I
+    .registers 2
+
+    if-eqz p0, :outer_header
+    goto :inner_back_edge
+
+    :outer_header
+    if-eqz p0, :inner_header
+
+    :outer_branch_exit
+    if-eqz p0, :outer_merge
+    return p0
+
+    :inner_header
+    goto :outer_merge
+
+    :inner_back_edge
+    goto :inner_header
+
+    :outer_merge
+    if-eqz p0, :inner_back_edge
+
+    :outer_back_edge
+    add-int/2addr p0, p0
+    goto :outer_header
+
+.end method
diff --git a/test/598-checker-irreducible-dominance/src/Main.java b/test/598-checker-irreducible-dominance/src/Main.java
new file mode 100644
index 0000000..38b2ab4
--- /dev/null
+++ b/test/598-checker-irreducible-dominance/src/Main.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+public class Main {
+  // Workaround for b/18051191.
+  class InnerClass {}
+
+  public static void main(String[] args) {
+    // Nothing to run. This regression test merely makes sure the smali test
+    // case successfully compiles.
+  }
+}
diff --git a/test/Android.libarttest.mk b/test/Android.libarttest.mk
index d6f5d37..21f8141 100644
--- a/test/Android.libarttest.mk
+++ b/test/Android.libarttest.mk
@@ -43,7 +43,8 @@
   566-polymorphic-inlining/polymorphic_inline.cc \
   570-checker-osr/osr.cc \
   595-profile-saving/profile-saving.cc \
-  596-app-images/app_images.cc
+  596-app-images/app_images.cc \
+  597-deopt-new-string/deopt.cc
 
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttest.so
 ART_TARGET_LIBARTTEST_$(ART_PHONY_TEST_TARGET_SUFFIX) += $(ART_TARGET_TEST_OUT)/$(TARGET_ARCH)/libarttestd.so
@@ -92,7 +93,12 @@
     include $(BUILD_SHARED_LIBRARY)
   else # host
     LOCAL_CLANG := $(ART_HOST_CLANG)
-    LOCAL_CFLAGS := $(ART_HOST_CFLAGS) $(ART_HOST_DEBUG_CFLAGS)
+    LOCAL_CFLAGS := $(ART_HOST_CFLAGS)
+    ifeq ($$(suffix),d)
+      LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
+    else
+      LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS)
+    endif
     LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS)
     LOCAL_LDLIBS := $(ART_HOST_LDLIBS) -ldl -lpthread
     LOCAL_IS_HOST_MODULE := true
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 01114b7..aa45d40 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -473,11 +473,14 @@
       LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBRARY_DIRECTORY
     fi
 
+    PUBLIC_LIBS=libart.so:libartd.so
+
     # Create a script with the command. The command can get longer than the longest
     # allowed adb command and there is no way to get the exit status from a adb shell
     # command.
     cmdline="cd $DEX_LOCATION && \
              export ANDROID_DATA=$DEX_LOCATION && \
+             export ANDROID_ADDITIONAL_PUBLIC_LIBRARIES=$PUBLIC_LIBS && \
              export DEX_LOCATION=$DEX_LOCATION && \
              export ANDROID_ROOT=$ANDROID_ROOT && \
              $mkdir_cmdline && \
diff --git a/test/run-test b/test/run-test
index 424c54f..bfb1709 100755
--- a/test/run-test
+++ b/test/run-test
@@ -467,7 +467,7 @@
         run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}"
     else
         guess_target_arch_name
-        run_args="${run_args} --runtime-option -Djava.library.path=/data/art-test/${target_arch_name}"
+        run_args="${run_args} --runtime-option -Djava.library.path=/data/art-test/${target_arch_name}:/system/lib${suffix64}"
         run_args="${run_args} --boot /data/art-test/core${image_suffix}${pic_image_suffix}${multi_image_suffix}.art"
     fi
     if [ "$relocate" = "yes" ]; then