Revert "Revert "Basic obsolete methods support""

This reverts commit b81a9840b44480bfeacd74b8d9f51e06f295411d.

There were 2 issues with the original CL's test 916-obsolete-jit that
caused it to sporadically fail.

First, when checking if we had jitted the function under test in
916-obsolete-jit we failed to check to see if the function 'doCall',
which is used to work-around bugs in our deoptimization & compilation
systems, had also been jitted.

In the case where the 'sayHi' function had been jitted but the
'doCall' function had not we would (correctly) fail to redefine the
'Transform' class since we would not be able to deoptimize the 'sayHi'
function since it is under a quick_to_interpreter_bridge (runtime)
frame.

Secondly, the function Main.isInterpretedFunction was incorrect and
would always return false, regardless of the actual state of the
function. This would cause the test to fail as the
quick_to_interpreter_bridge frame prevented deoptimization of the
obsoleted function. Usually the warm-up period was enough to make sure
the methods were jitted anyway but this was not guaranteed.

Both of these problems become more likely to occur on systems with
more cpu contention such as the buildbots.

Test: stress --cpu 60 &; while ./test/run-test --host --jit 916; do ; done

Reason for revert: Fixed bug in test that was causing failures.

Original Tests:

Test: ./test/run-test --host 914
Test: ./test/run-test --host 915
Test: ./test/run-test --host 916
Test: mma -j40 test-art-host
Test: ART_TEST_JIT=true \
      ART_TEST_INTERPRETER=true mma -j40 test-art-host
Test: ./art/tools/run-jdwp-tests.sh --mode=host --variant=X64
Test: ./art/tools/run-jdwp-tests.sh --mode=host --variant=X64 --no-jit

Bug: 32369913
Bug: 33630159

Change-Id: If1a92e47b90965a7dc21c5826185debe62bd1554
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index 4df2d47..df7fa20 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -18,6 +18,7 @@
 
 #include "base/logging.h"
 #include "dex_file-inl.h"
+#include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "nth_caller_visitor.h"
 #include "oat_file.h"
@@ -52,6 +53,89 @@
   return IsInterpreted(env, klass, 1);
 }
 
+// public static native boolean isInterpreted(int depth);
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpretedAt(JNIEnv* env,
+                                                                jclass klass,
+                                                                jint depth) {
+  return IsInterpreted(env, klass, depth);
+}
+
+
+// public static native boolean isInterpretedFunction(String smali);
+
+// TODO Remove 'allow_runtime_frames' option once we have deoptimization through runtime frames.
+struct MethodIsInterpretedVisitor : public StackVisitor {
+ public:
+  MethodIsInterpretedVisitor(Thread* thread, ArtMethod* goal, bool require_deoptable)
+      : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames),
+        goal_(goal),
+        method_is_interpreted_(true),
+        method_found_(false),
+        prev_was_runtime_(true),
+        require_deoptable_(require_deoptable) {}
+
+  virtual bool VisitFrame() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) {
+    if (goal_ == GetMethod()) {
+      method_is_interpreted_ = (require_deoptable_ && prev_was_runtime_) || IsShadowFrame();
+      method_found_ = true;
+      return false;
+    }
+    prev_was_runtime_ = GetMethod()->IsRuntimeMethod();
+    return true;
+  }
+
+  bool IsInterpreted() {
+    return method_is_interpreted_;
+  }
+
+  bool IsFound() {
+    return method_found_;
+  }
+
+ private:
+  const ArtMethod* goal_;
+  bool method_is_interpreted_;
+  bool method_found_;
+  bool prev_was_runtime_;
+  bool require_deoptable_;
+};
+
+// TODO Remove 'require_deoptimizable' option once we have deoptimization through runtime frames.
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_isInterpretedFunction(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method, jboolean require_deoptimizable) {
+  // Return false if this seems to not be an ART runtime.
+  if (Runtime::Current() == nullptr) {
+    return JNI_FALSE;
+  }
+  if (method == nullptr) {
+    env->ThrowNew(env->FindClass("java/lang/NullPointerException"), "method is null!");
+    return JNI_FALSE;
+  }
+  jmethodID id = env->FromReflectedMethod(method);
+  if (id == nullptr) {
+    env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to interpret method argument!");
+    return JNI_FALSE;
+  }
+  bool result;
+  bool found;
+  {
+    ScopedObjectAccess soa(env);
+    ArtMethod* goal = jni::DecodeArtMethod(id);
+    MethodIsInterpretedVisitor v(soa.Self(), goal, require_deoptimizable);
+    v.WalkStack();
+    bool enters_interpreter = Runtime::Current()->GetClassLinker()->IsQuickToInterpreterBridge(
+        goal->GetEntryPointFromQuickCompiledCode());
+    result = (v.IsInterpreted() || enters_interpreter);
+    found = v.IsFound();
+  }
+  if (!found) {
+    env->ThrowNew(env->FindClass("java/lang/Error"), "Unable to find given method in stack!");
+    return JNI_FALSE;
+  }
+  return result;
+}
+
 // public static native void assertIsInterpreted();
 
 extern "C" JNIEXPORT void JNICALL Java_Main_assertIsInterpreted(JNIEnv* env, jclass klass) {