ART: Add more deopt tests

Extend libarttest with the ability to turn off asserts for method
state. Use this to put asserts into test functions, but turn them
off if the test wouldn't react as we want, e.g., when we're in
interpreter mode.

Extend run-test 449 by adding asserts for the method state for the
expected deopt cases. This tests both standard behavior, as well
as single-frame deoptimization.

Bug: 21611912
Change-Id: I27fa5e3e44d8c5eab57962d144c6aec96587bf45
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 042b03b..082c9b3 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -66,4 +66,54 @@
   return Runtime::Current()->IsImageDex2OatEnabled();
 }
 
+// public static native boolean compiledWithOptimizing();
+// Did we use the optimizing compiler to compile this?
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_compiledWithOptimizing(JNIEnv* env, jclass cls) {
+  ScopedObjectAccess soa(env);
+
+  mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
+  const DexFile& dex_file = klass->GetDexFile();
+  const OatFile::OatDexFile* oat_dex_file = dex_file.GetOatDexFile();
+  if (oat_dex_file == nullptr) {
+    // Could be JIT, which also uses optimizing, but conservatively say no.
+    return JNI_FALSE;
+  }
+  const OatFile* oat_file = oat_dex_file->GetOatFile();
+  CHECK(oat_file != nullptr);
+
+  const char* cmd_line = oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kDex2OatCmdLineKey);
+  CHECK(cmd_line != nullptr);  // Huh? This should not happen.
+
+  // Check the backend.
+  constexpr const char* kCompilerBackend = "--compiler-backend=";
+  const char* backend = strstr(cmd_line, kCompilerBackend);
+  if (backend != nullptr) {
+    // If it's set, make sure it's optimizing.
+    backend += strlen(kCompilerBackend);
+    if (strncmp(backend, "Optimizing", strlen("Optimizing")) != 0) {
+      return JNI_FALSE;
+    }
+  }
+
+  // Check the filter.
+  constexpr const char* kCompilerFilter = "--compiler-filter=";
+  const char* filter = strstr(cmd_line, kCompilerFilter);
+  if (filter != nullptr) {
+    // If it's set, make sure it's not interpret-only|verify-none|verify-at-runtime.
+    // Note: The space filter might have an impact on the test, but ignore that for now.
+    filter += strlen(kCompilerFilter);
+    constexpr const char* kInterpretOnly = "interpret-only";
+    constexpr const char* kVerifyNone = "verify-none";
+    constexpr const char* kVerifyAtRuntime = "verify-at-runtime";
+    if (strncmp(filter, kInterpretOnly, strlen(kInterpretOnly)) == 0 ||
+        strncmp(filter, kVerifyNone, strlen(kVerifyNone)) == 0 ||
+        strncmp(filter, kVerifyAtRuntime, strlen(kVerifyAtRuntime)) == 0) {
+      return JNI_FALSE;
+    }
+  }
+
+  return JNI_TRUE;
+}
+
 }  // namespace art
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index d22cf52..922eae6 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -27,9 +27,20 @@
 
 namespace art {
 
-// public static native boolean isCallerInterpreted();
+static bool asserts_enabled = true;
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isCallerInterpreted(JNIEnv* env, jclass) {
+// public static native void disableStackFrameAsserts();
+// Note: to globally disable asserts in unsupported configurations.
+
+extern "C" JNIEXPORT void JNICALL Java_Main_disableStackFrameAsserts(JNIEnv* env ATTRIBUTE_UNUSED,
+                                                                     jclass cls ATTRIBUTE_UNUSED) {
+  asserts_enabled = false;
+}
+
+
+// public static native boolean isInterpreted();
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpreted(JNIEnv* env, jclass) {
   ScopedObjectAccess soa(env);
   NthCallerVisitor caller(soa.Self(), 1, false);
   caller.WalkStack();
@@ -37,16 +48,18 @@
   return caller.GetCurrentShadowFrame() != nullptr ? JNI_TRUE : JNI_FALSE;
 }
 
-// public static native void assertCallerIsInterpreted();
+// public static native void assertIsInterpreted();
 
-extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsInterpreted(JNIEnv* env, jclass klass) {
-  CHECK(Java_Main_isCallerInterpreted(env, klass));
+extern "C" JNIEXPORT void JNICALL Java_Main_assertIsInterpreted(JNIEnv* env, jclass klass) {
+  if (asserts_enabled) {
+    CHECK(Java_Main_isInterpreted(env, klass));
+  }
 }
 
 
-// public static native boolean isCallerManaged();
+// public static native boolean isManaged();
 
-extern "C" JNIEXPORT jboolean JNICALL Java_Main_isCallerManaged(JNIEnv* env, jclass cls) {
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isManaged(JNIEnv* env, jclass cls) {
   ScopedObjectAccess soa(env);
 
   mirror::Class* klass = soa.Decode<mirror::Class*>(cls);
@@ -65,10 +78,12 @@
   return caller.GetCurrentShadowFrame() != nullptr ? JNI_FALSE : JNI_TRUE;
 }
 
-// public static native void assertCallerIsManaged();
+// public static native void assertIsManaged();
 
-extern "C" JNIEXPORT void JNICALL Java_Main_assertCallerIsManaged(JNIEnv* env, jclass cls) {
-  CHECK(Java_Main_isCallerManaged(env, cls));
+extern "C" JNIEXPORT void JNICALL Java_Main_assertIsManaged(JNIEnv* env, jclass cls) {
+  if (asserts_enabled) {
+    CHECK(Java_Main_isManaged(env, cls));
+  }
 }
 
 }  // namespace art