Fix incorrect DCHECK

We were incorrectly asserting that the disable_pop_frame_depth field
always increased instead of that it never decreased. This meant that
we would get DCHECK failures if one caused a recursive ClassPrepare or
ClassLoad event to trigger.

Test: ./test.py --host
Bug: 146170757
Change-Id: I980a8511033fa88f3fccebb7e654336133cf33bd
diff --git a/openjdkjvmti/events-inl.h b/openjdkjvmti/events-inl.h
index 23f7151..883a4cc 100644
--- a/openjdkjvmti/events-inl.h
+++ b/openjdkjvmti/events-inl.h
@@ -453,8 +453,10 @@
         thread_, art::StackVisitor::StackWalkKind::kIncludeInlinedFrames);
     old_disable_frame_pop_depth_ = data->disable_pop_frame_depth;
     data->disable_pop_frame_depth = current_top_frame_;
+    // Check that we cleaned up any old disables. This should only increase (or be equals if we do
+    // another ClassLoad/Prepare recursively).
     DCHECK(old_disable_frame_pop_depth_ == JvmtiGlobalTLSData::kNoDisallowedPopFrame ||
-           current_top_frame_ > old_disable_frame_pop_depth_)
+           current_top_frame_ >= old_disable_frame_pop_depth_)
         << "old: " << old_disable_frame_pop_depth_ << " current: " << current_top_frame_;
   }
 
diff --git a/test/912-classes/classes.cc b/test/912-classes/classes.cc
index 1f6954e..5032762 100644
--- a/test/912-classes/classes.cc
+++ b/test/912-classes/classes.cc
@@ -596,5 +596,30 @@
   }
 }
 
+static jobject gRunnableGlobal = nullptr;
+extern "C" JNIEXPORT void JNICALL Java_art_Test912_runRecursiveClassPrepareEvents(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject runnable) {
+  CHECK(gRunnableGlobal == nullptr);
+  gRunnableGlobal = env->NewGlobalRef(runnable);
+  EnableEvents(
+      env,
+      true,
+      nullptr,
+      [](jvmtiEnv* jenv ATTRIBUTE_UNUSED,
+         JNIEnv* jni_env,
+         jthread thread ATTRIBUTE_UNUSED,
+         jclass klass ATTRIBUTE_UNUSED) -> void {
+        jclass runnable_class = jni_env->FindClass("java/lang/Runnable");
+        jni_env->CallVoidMethod(
+            gRunnableGlobal, jni_env->GetMethodID(runnable_class, "run", "()V"));
+      });
+  jclass runnable_class = env->FindClass("java/lang/Runnable");
+  env->CallVoidMethod(
+      runnable, env->GetMethodID(runnable_class, "run", "()V"));
+  EnableEvents(env, false, nullptr, nullptr);
+  env->DeleteGlobalRef(gRunnableGlobal);
+  gRunnableGlobal = nullptr;
+}
+
 }  // namespace Test912Classes
 }  // namespace art
diff --git a/test/912-classes/expected.txt b/test/912-classes/expected.txt
index 7ad5d60..d7699b6 100644
--- a/test/912-classes/expected.txt
+++ b/test/912-classes/expected.txt
@@ -91,3 +91,7 @@
 Prepare: L$Proxy21; on ClassEvents (cur=ClassEvents)
 Load: [Lart/Test912; on ClassEvents
 Prepare: [Lart/Test912; on ClassEvents (cur=ClassEvents)
+class-prepare event START!
+class-prepare event START!
+class-prepare event END!
+class-prepare event END!
diff --git a/test/912-classes/src-art/art/Test912.java b/test/912-classes/src-art/art/Test912.java
index 1a60185..a2e8934 100644
--- a/test/912-classes/src-art/art/Test912.java
+++ b/test/912-classes/src-art/art/Test912.java
@@ -105,6 +105,9 @@
     };
     classEventsThread.start();
     classEventsThread.join();
+
+    // b/146170757
+    TestRecursiveClassPrepareEvents();
   }
 
   private static void testClass(String className) throws Exception {
@@ -394,6 +397,32 @@
   private static native void setEqualityEventStorageClass(Class<?> c);
   private static native void enableClassLoadPrepareEqualityEvents(boolean b);
 
+  private static native void runRecursiveClassPrepareEvents(Runnable forceLoad);
+
+  private static void TestRecursiveClassPrepareEvents() {
+    final int[] called = new int[] { 0 };
+    runRecursiveClassPrepareEvents(() -> {
+      if (called[0] == 2) {
+        return;
+      } else {
+        called[0]++;
+      }
+      try {
+        System.out.println("class-prepare event START!");
+        // Load a new class in a new class-loader.
+        Class<?> class_loader_class = Class.forName("dalvik.system.InMemoryDexClassLoader");
+        Constructor<?> ctor = class_loader_class.getConstructor(ByteBuffer.class, ClassLoader.class);
+        Class<?> target = ((ClassLoader)ctor.newInstance(
+            ByteBuffer.wrap(DEX_BYTES), Test912.class.getClassLoader())).loadClass("Transform");
+        target.newInstance();
+      } catch (Exception e) { }
+      System.out.println("class-prepare event END!");
+    });
+    if (called[0] != 2) {
+      System.out.println("Failed to cause recursive Class prepare.");
+    }
+  }
+
   private static class TestForNonInit {
     public static double dummy = Math.random();  // So it can't be compile-time initialized.
   }