Refactor test 1953, 1954, 1955, & 1956 somewhat

These tests all use a common set of suspension triggering event code.
This will be useful in other tests later. To make it easier to use in
the future this code is separated into common ti-agent files.

Test: ./test.py --host -j80
Change-Id: I75f3fe8862c99bd32c5eabe0992fef911d7d9c56
diff --git a/test/1953-pop-frame/pop_frame.cc b/test/1953-pop-frame/pop_frame.cc
index 1c2d2a1..86345d6 100644
--- a/test/1953-pop-frame/pop_frame.cc
+++ b/test/1953-pop-frame/pop_frame.cc
@@ -36,898 +36,11 @@
 #include "test_env.h"
 #include "ti_macros.h"
 
+#include "suspend_event_helper.h"
+
 namespace art {
 namespace Test1953PopFrame {
 
-struct TestData {
-  jlocation target_loc;
-  jmethodID target_method;
-  jclass target_klass;
-  jfieldID target_field;
-  jrawMonitorID notify_monitor;
-  jint frame_pop_offset;
-  jmethodID frame_pop_setup_method;
-  std::vector<std::string> interesting_classes;
-  bool hit_location;
-
-  TestData(jvmtiEnv* jvmti,
-           JNIEnv* env,
-           jlocation loc,
-           jobject meth,
-           jclass klass,
-           jobject field,
-           jobject setup_meth,
-           jint pop_offset,
-           const std::vector<std::string>&& interesting)
-      : target_loc(loc),
-        target_method(meth != nullptr ? env->FromReflectedMethod(meth) : nullptr),
-        target_klass(reinterpret_cast<jclass>(env->NewGlobalRef(klass))),
-        target_field(field != nullptr ? env->FromReflectedField(field) : nullptr),
-        frame_pop_offset(pop_offset),
-        frame_pop_setup_method(setup_meth != nullptr ? env->FromReflectedMethod(setup_meth)
-                                                     : nullptr),
-        interesting_classes(interesting),
-        hit_location(false) {
-    JvmtiErrorToException(env, jvmti, jvmti->CreateRawMonitor("SuspendStopMonitor",
-                                                              &notify_monitor));
-  }
-
-  void PerformSuspend(jvmtiEnv* jvmti, JNIEnv* env) {
-    // Wake up the waiting thread.
-    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(notify_monitor));
-    hit_location = true;
-    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorNotifyAll(notify_monitor));
-    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(notify_monitor));
-    // Suspend ourself
-    jvmti->SuspendThread(nullptr);
-  }
-};
-
-void JNICALL cbSingleStep(jvmtiEnv* jvmti,
-                          JNIEnv* env,
-                          jthread thr,
-                          jmethodID meth,
-                          jlocation loc) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (meth != data->target_method || loc != data->target_loc) {
-    return;
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbExceptionCatch(jvmtiEnv *jvmti,
-                              JNIEnv* env,
-                              jthread thr,
-                              jmethodID method,
-                              jlocation location ATTRIBUTE_UNUSED,
-                              jobject exception ATTRIBUTE_UNUSED) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (method != data->target_method) {
-    return;
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbException(jvmtiEnv *jvmti,
-                         JNIEnv* env,
-                         jthread thr,
-                         jmethodID method,
-                         jlocation location ATTRIBUTE_UNUSED,
-                         jobject exception ATTRIBUTE_UNUSED,
-                         jmethodID catch_method ATTRIBUTE_UNUSED,
-                         jlocation catch_location ATTRIBUTE_UNUSED) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (method != data->target_method) {
-    return;
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbMethodEntry(jvmtiEnv *jvmti,
-                           JNIEnv* env,
-                           jthread thr,
-                           jmethodID method) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (method != data->target_method) {
-    return;
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbMethodExit(jvmtiEnv *jvmti,
-                          JNIEnv* env,
-                          jthread thr,
-                          jmethodID method,
-                          jboolean was_popped_by_exception ATTRIBUTE_UNUSED,
-                          jvalue return_value ATTRIBUTE_UNUSED) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (method != data->target_method) {
-    return;
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbFieldModification(jvmtiEnv* jvmti,
-                                 JNIEnv* env,
-                                 jthread thr,
-                                 jmethodID method ATTRIBUTE_UNUSED,
-                                 jlocation location ATTRIBUTE_UNUSED,
-                                 jclass field_klass ATTRIBUTE_UNUSED,
-                                 jobject object ATTRIBUTE_UNUSED,
-                                 jfieldID field,
-                                 char signature_type ATTRIBUTE_UNUSED,
-                                 jvalue new_value ATTRIBUTE_UNUSED) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (field != data->target_field) {
-    // TODO What to do here.
-    LOG(FATAL) << "Strange, shouldn't get here!";
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbFieldAccess(jvmtiEnv* jvmti,
-                           JNIEnv* env,
-                           jthread thr,
-                           jmethodID method ATTRIBUTE_UNUSED,
-                           jlocation location ATTRIBUTE_UNUSED,
-                           jclass field_klass,
-                           jobject object ATTRIBUTE_UNUSED,
-                           jfieldID field) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (field != data->target_field || !env->IsSameObject(field_klass, data->target_klass)) {
-    // TODO What to do here.
-    LOG(FATAL) << "Strange, shouldn't get here!";
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbBreakpointHit(jvmtiEnv* jvmti,
-                             JNIEnv* env,
-                             jthread thr,
-                             jmethodID method,
-                             jlocation loc) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (data->frame_pop_setup_method == method) {
-    CHECK(loc == 0) << "We should have stopped at location 0";
-    if (JvmtiErrorToException(env,
-                              jvmti,
-                              jvmti->NotifyFramePop(thr, data->frame_pop_offset))) {
-      return;
-    }
-    return;
-  }
-  if (method != data->target_method || loc != data->target_loc) {
-    // TODO What to do here.
-    LOG(FATAL) << "Strange, shouldn't get here!";
-  }
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbFramePop(jvmtiEnv* jvmti,
-                        JNIEnv* env,
-                        jthread thr,
-                        jmethodID method ATTRIBUTE_UNUSED,
-                        jboolean was_popped_by_exception ATTRIBUTE_UNUSED) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  data->PerformSuspend(jvmti, env);
-}
-
-void JNICALL cbClassLoadOrPrepare(jvmtiEnv* jvmti,
-                                  JNIEnv* env,
-                                  jthread thr,
-                                  jclass klass) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  char* name;
-  if (JvmtiErrorToException(env, jvmti, jvmti->GetClassSignature(klass, &name, nullptr))) {
-    return;
-  }
-  std::string name_str(name);
-  if (JvmtiErrorToException(env,
-                            jvmti,
-                            jvmti->Deallocate(reinterpret_cast<unsigned char*>(name)))) {
-    return;
-  }
-  if (std::find(data->interesting_classes.cbegin(),
-                data->interesting_classes.cend(),
-                name_str) != data->interesting_classes.cend()) {
-    data->PerformSuspend(jvmti, env);
-  }
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupTest(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
-  jvmtiCapabilities caps;
-  memset(&caps, 0, sizeof(caps));
-  // Most of these will already be there but might as well be complete.
-  caps.can_pop_frame                          = 1;
-  caps.can_generate_single_step_events        = 1;
-  caps.can_generate_breakpoint_events         = 1;
-  caps.can_suspend                            = 1;
-  caps.can_generate_method_entry_events       = 1;
-  caps.can_generate_method_exit_events        = 1;
-  caps.can_generate_monitor_events            = 1;
-  caps.can_generate_exception_events          = 1;
-  caps.can_generate_frame_pop_events          = 1;
-  caps.can_generate_field_access_events       = 1;
-  caps.can_generate_field_modification_events = 1;
-  caps.can_redefine_classes                   = 1;
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
-    return;
-  }
-  jvmtiEventCallbacks cb;
-  memset(&cb, 0, sizeof(cb));
-  // TODO Add the rest of these.
-  cb.Breakpoint        = cbBreakpointHit;
-  cb.SingleStep        = cbSingleStep;
-  cb.FieldAccess       = cbFieldAccess;
-  cb.FieldModification = cbFieldModification;
-  cb.MethodEntry       = cbMethodEntry;
-  cb.MethodExit        = cbMethodExit;
-  cb.Exception         = cbException;
-  cb.ExceptionCatch    = cbExceptionCatch;
-  cb.FramePop          = cbFramePop;
-  cb.ClassLoad         = cbClassLoadOrPrepare;
-  cb.ClassPrepare      = cbClassLoadOrPrepare;
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
-}
-
-static bool DeleteTestData(JNIEnv* env, jthread thr, TestData* data) {
-  env->DeleteGlobalRef(data->target_klass);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
-    return false;
-  }
-  return JvmtiErrorToException(env,
-                               jvmti_env,
-                               jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data)));
-}
-
-static TestData* SetupTestData(JNIEnv* env,
-                               jobject meth,
-                               jlocation loc,
-                               jclass target_klass,
-                               jobject field,
-                               jobject setup_meth,
-                               jint pop_offset,
-                               const std::vector<std::string>&& interesting_names) {
-  void* data_ptr;
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->Allocate(sizeof(TestData),
-                                                reinterpret_cast<uint8_t**>(&data_ptr)))) {
-    return nullptr;
-  }
-  data = new (data_ptr) TestData(jvmti_env,
-                                 env,
-                                 loc,
-                                 meth,
-                                 target_klass,
-                                 field,
-                                 setup_meth,
-                                 pop_offset,
-                                 std::move(interesting_names));
-  if (env->ExceptionCheck()) {
-    env->DeleteGlobalRef(data->target_klass);
-    jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data));
-    return nullptr;
-  }
-  return data;
-}
-
-static TestData* SetupTestData(JNIEnv* env,
-                               jobject meth,
-                               jlocation loc,
-                               jclass target_klass,
-                               jobject field,
-                               jobject setup_meth,
-                               jint pop_offset) {
-  std::vector<std::string> empty;
-  return SetupTestData(
-      env, meth, loc, target_klass, field, setup_meth, pop_offset, std::move(empty));
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupSuspendClassEvent(JNIEnv* env,
-                                                      jclass klass ATTRIBUTE_UNUSED,
-                                                      jint event_num,
-                                                      jobjectArray interesting_names,
-                                                      jthread thr) {
-  CHECK(event_num == JVMTI_EVENT_CLASS_LOAD || event_num == JVMTI_EVENT_CLASS_PREPARE);
-  std::vector<std::string> names;
-  jint cnt = env->GetArrayLength(interesting_names);
-  for (jint i = 0; i < cnt; i++) {
-    env->PushLocalFrame(1);
-    jstring name_obj = reinterpret_cast<jstring>(env->GetObjectArrayElement(interesting_names, i));
-    const char* name_chr = env->GetStringUTFChars(name_obj, nullptr);
-    names.push_back(std::string(name_chr));
-    env->ReleaseStringUTFChars(name_obj, name_chr);
-    env->PopLocalFrame(nullptr);
-  }
-  TestData* data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0, std::move(names));
-  if (data == nullptr) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-  JvmtiErrorToException(env,
-                        jvmti_env,
-                        jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                            static_cast<jvmtiEvent>(event_num),
-                                                            thr));
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearSuspendClassEvent(JNIEnv* env,
-                                                      jclass klass ATTRIBUTE_UNUSED,
-                                                      jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_CLASS_LOAD,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_CLASS_PREPARE,
-                                                                thr))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupSuspendSingleStepAt(JNIEnv* env,
-                                                        jclass klass ATTRIBUTE_UNUSED,
-                                                        jobject meth,
-                                                        jlocation loc,
-                                                        jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
-  if (data == nullptr) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                            JVMTI_EVENT_SINGLE_STEP,
-                                                                            thr));
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearSuspendSingleStepFor(JNIEnv* env,
-                                                         jclass klass ATTRIBUTE_UNUSED,
-                                                         jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_SINGLE_STEP,
-                                                                thr))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupSuspendPopFrameEvent(JNIEnv* env,
-                                                         jclass klass ATTRIBUTE_UNUSED,
-                                                         jint offset,
-                                                         jobject breakpoint_func,
-                                                         jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, breakpoint_func, offset);
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_FRAME_POP,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_BREAKPOINT,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetBreakpoint(data->frame_pop_setup_method, 0))) {
-    return;
-  }
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearSuspendPopFrameEvent(JNIEnv* env,
-                                                         jclass klass ATTRIBUTE_UNUSED,
-                                                         jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_FRAME_POP,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_BREAKPOINT,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->ClearBreakpoint(data->frame_pop_setup_method, 0))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupSuspendBreakpointFor(JNIEnv* env,
-                                                         jclass klass ATTRIBUTE_UNUSED,
-                                                         jobject meth,
-                                                         jlocation loc,
-                                                         jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
-  if (data == nullptr) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_BREAKPOINT,
-                                                                thr))) {
-    return;
-  }
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetBreakpoint(data->target_method,
-                                                                 data->target_loc));
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearSuspendBreakpointFor(JNIEnv* env,
-                                                         jclass klass ATTRIBUTE_UNUSED,
-                                                         jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_BREAKPOINT,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->ClearBreakpoint(data->target_method,
-                                                       data->target_loc))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupSuspendExceptionEvent(JNIEnv* env,
-                                                          jclass klass ATTRIBUTE_UNUSED,
-                                                          jobject method,
-                                                          jboolean is_catch,
-                                                          jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(
-                                thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
-  if (data == nullptr) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-  JvmtiErrorToException(env,
-                        jvmti_env,
-                        jvmti_env->SetEventNotificationMode(
-                            JVMTI_ENABLE,
-                            is_catch ? JVMTI_EVENT_EXCEPTION_CATCH : JVMTI_EVENT_EXCEPTION,
-                            thr));
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearSuspendExceptionEvent(JNIEnv* env,
-                                                          jclass klass ATTRIBUTE_UNUSED,
-                                                          jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_EXCEPTION_CATCH,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_EXCEPTION,
-                                                                thr))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupSuspendMethodEvent(JNIEnv* env,
-                                                       jclass klass ATTRIBUTE_UNUSED,
-                                                       jobject method,
-                                                       jboolean enter,
-                                                       jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(
-                                thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
-  if (data == nullptr) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-  JvmtiErrorToException(env,
-                        jvmti_env,
-                        jvmti_env->SetEventNotificationMode(
-                            JVMTI_ENABLE,
-                            enter ? JVMTI_EVENT_METHOD_ENTRY : JVMTI_EVENT_METHOD_EXIT,
-                            thr));
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearSuspendMethodEvent(JNIEnv* env,
-                                                       jclass klass ATTRIBUTE_UNUSED,
-                                                       jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_METHOD_EXIT,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_METHOD_ENTRY,
-                                                                thr))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupFieldSuspendFor(JNIEnv* env,
-                                                    jclass klass ATTRIBUTE_UNUSED,
-                                                    jclass target_klass,
-                                                    jobject field,
-                                                    jboolean access,
-                                                    jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(
-                                thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, nullptr, 0, target_klass, field, nullptr, 0);
-  if (data == nullptr) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(
-                                JVMTI_ENABLE,
-                                access ? JVMTI_EVENT_FIELD_ACCESS : JVMTI_EVENT_FIELD_MODIFICATION,
-                                thr))) {
-    return;
-  }
-  if (access) {
-    JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldAccessWatch(data->target_klass,
-                                                                         data->target_field));
-  } else {
-    JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldModificationWatch(data->target_klass,
-                                                                               data->target_field));
-  }
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearFieldSuspendFor(JNIEnv* env,
-                                                    jclass klass ATTRIBUTE_UNUSED,
-                                                    jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_FIELD_ACCESS,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_FIELD_MODIFICATION,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->ClearFieldModificationWatch(
-                                data->target_klass, data->target_field)) &&
-      JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->ClearFieldAccessWatch(
-                                data->target_klass, data->target_field))) {
-    return;
-  } else {
-    env->ExceptionClear();
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_setupWaitForNativeCall(JNIEnv* env,
-                                                      jclass klass ATTRIBUTE_UNUSED,
-                                                      jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(
-                                thr, reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data == nullptr) << "Data was not cleared!";
-  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0);
-  if (data == nullptr) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, data))) {
-    return;
-  }
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_clearWaitForNativeCall(JNIEnv* env,
-                                                      jclass klass ATTRIBUTE_UNUSED,
-                                                      jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
-    return;
-  }
-  DeleteTestData(env, thr, data);
-}
-
-extern "C" JNIEXPORT
-void JNICALL Java_art_Test1953_waitForSuspendHit(JNIEnv* env,
-                                                 jclass klass ATTRIBUTE_UNUSED,
-                                                 jthread thr) {
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(thr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(data->notify_monitor))) {
-    return;
-  }
-  while (!data->hit_location) {
-    if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorWait(data->notify_monitor, -1))) {
-      return;
-    }
-  }
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(data->notify_monitor))) {
-    return;
-  }
-  jint state = 0;
-  while (!JvmtiErrorToException(env, jvmti_env, jvmti_env->GetThreadState(thr, &state)) &&
-         (state & JVMTI_THREAD_STATE_SUSPENDED) == 0) { }
-}
 
 extern "C" JNIEXPORT
 void JNICALL Java_art_Test1953_popFrame(JNIEnv* env,
@@ -944,15 +57,7 @@
   jfieldID cnt = env->GetFieldID(klass, "cnt", "I");
   env->SetIntField(thiz, cnt, env->GetIntField(thiz, cnt) + 1);
   env->PopLocalFrame(nullptr);
-  TestData *data;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->GetThreadLocalStorage(/* thread */ nullptr,
-                                                             reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data != nullptr);
-  data->PerformSuspend(jvmti_env, env);
+  art::common_suspend_event::PerformSuspension(jvmti_env, env);
 }
 
 extern "C" JNIEXPORT
diff --git a/test/1953-pop-frame/src/art/SuspendEvents.java b/test/1953-pop-frame/src/art/SuspendEvents.java
new file mode 100644
index 0000000..6bf6bda
--- /dev/null
+++ b/test/1953-pop-frame/src/art/SuspendEvents.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package art;
+
+import java.lang.reflect.Executable;
+import java.lang.reflect.Field;
+
+/**
+ * A set of functions to request events that suspend the thread they trigger on.
+ */
+public final class SuspendEvents {
+  /**
+   * Sets up the suspension support. Must be called at the start of the test.
+   */
+  public static native void setupTest();
+
+  public static native void setupSuspendBreakpointFor(Executable meth, long loc, Thread thr);
+  public static native void clearSuspendBreakpointFor(Thread thr);
+
+  public static native void setupSuspendSingleStepAt(Executable meth, long loc, Thread thr);
+  public static native void clearSuspendSingleStepFor(Thread thr);
+
+  public static native void setupFieldSuspendFor(Class klass, Field f, boolean access, Thread thr);
+  public static native void clearFieldSuspendFor(Thread thr);
+
+  public static native void setupSuspendMethodEvent(Executable meth, boolean enter, Thread thr);
+  public static native void clearSuspendMethodEvent(Thread thr);
+
+  public static native void setupSuspendExceptionEvent(
+      Executable meth, boolean is_catch, Thread thr);
+  public static native void clearSuspendExceptionEvent(Thread thr);
+
+  public static native void setupSuspendPopFrameEvent(
+      int offset, Executable breakpointFunction, Thread thr);
+  public static native void clearSuspendPopFrameEvent(Thread thr);
+
+  public static final int EVENT_TYPE_CLASS_LOAD = 55;
+  public static final int EVENT_TYPE_CLASS_PREPARE = 56;
+  public static native void setupSuspendClassEvent(
+      int eventType, String[] interestingNames, Thread thr);
+  public static native void clearSuspendClassEvent(Thread thr);
+
+  public static native void setupWaitForNativeCall(Thread thr);
+  public static native void clearWaitForNativeCall(Thread thr);
+
+  /**
+   * Waits for the given thread to be suspended.
+   * @param thr the thread to wait for.
+   */
+  public static native void waitForSuspendHit(Thread thr);
+}
diff --git a/test/1953-pop-frame/src/art/Test1953.java b/test/1953-pop-frame/src/art/Test1953.java
index adec776..fa49134 100644
--- a/test/1953-pop-frame/src/art/Test1953.java
+++ b/test/1953-pop-frame/src/art/Test1953.java
@@ -24,6 +24,18 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Consumer;
 
+import static art.SuspendEvents.setupTest;
+import static art.SuspendEvents.setupSuspendBreakpointFor;
+import static art.SuspendEvents.clearSuspendBreakpointFor;
+import static art.SuspendEvents.setupSuspendSingleStepAt;
+import static art.SuspendEvents.setupFieldSuspendFor;
+import static art.SuspendEvents.setupSuspendMethodEvent;
+import static art.SuspendEvents.setupSuspendExceptionEvent;
+import static art.SuspendEvents.setupSuspendPopFrameEvent;
+import static art.SuspendEvents.EVENT_TYPE_CLASS_LOAD;
+import static art.SuspendEvents.EVENT_TYPE_CLASS_PREPARE;
+import static art.SuspendEvents.setupSuspendClassEvent;
+
 public class Test1953 {
   public final boolean canRunClassLoadTests;
   public static void doNothing() {}
@@ -46,7 +58,7 @@
   public static TestSuspender makeSuspend(final ThreadRunnable setup, final ThreadRunnable clean) {
     return new TestSuspender() {
       public void setup(Thread thr) { setup.run(thr); }
-      public void waitForSuspend(Thread thr) { Test1953.waitForSuspendHit(thr); }
+      public void waitForSuspend(Thread thr) { SuspendEvents.waitForSuspendHit(thr); }
       public void cleanup(Thread thr) { clean.run(thr); }
     };
   }
@@ -708,7 +720,7 @@
     System.out.println("Test stopped using breakpoint");
     runTestOn(new StandardTestObject(),
         (thr) -> setupSuspendBreakpointFor(calledFunction, loc, thr),
-        Test1953::clearSuspendBreakpointFor);
+        SuspendEvents::clearSuspendBreakpointFor);
 
     final Method syncFunctionCalledFunction =
         SynchronizedFunctionTestObject.class.getDeclaredMethod("calledFunction");
@@ -721,7 +733,7 @@
     System.out.println("Test stopped using breakpoint with declared synchronized function");
     runTestOn(new SynchronizedFunctionTestObject(),
         (thr) -> setupSuspendBreakpointFor(syncFunctionCalledFunction, syncFunctionLoc, thr),
-        Test1953::clearSuspendBreakpointFor);
+        SuspendEvents::clearSuspendBreakpointFor);
 
     final Method syncCalledFunction =
         SynchronizedTestObject.class.getDeclaredMethod("calledFunction");
@@ -731,86 +743,86 @@
     System.out.println("Test stopped using breakpoint with synchronized block");
     runTestOn(new SynchronizedTestObject(),
         (thr) -> setupSuspendBreakpointFor(syncCalledFunction, syncLoc, thr),
-        Test1953::clearSuspendBreakpointFor);
+        SuspendEvents::clearSuspendBreakpointFor);
 
     System.out.println("Test stopped on single step");
     runTestOn(new StandardTestObject(),
         (thr) -> setupSuspendSingleStepAt(calledFunction, loc, thr),
-        Test1953::clearSuspendSingleStepFor);
+        SuspendEvents::clearSuspendSingleStepFor);
 
     final Field target_field = FieldBasedTestObject.class.getDeclaredField("TARGET_FIELD");
     System.out.println("Test stopped on field access");
     runTestOn(new FieldBasedTestObject(),
         (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, true, thr),
-        Test1953::clearFieldSuspendFor);
+        SuspendEvents::clearFieldSuspendFor);
 
     System.out.println("Test stopped on field modification");
     runTestOn(new FieldBasedTestObject(),
         (thr) -> setupFieldSuspendFor(FieldBasedTestObject.class, target_field, false, thr),
-        Test1953::clearFieldSuspendFor);
+        SuspendEvents::clearFieldSuspendFor);
 
     System.out.println("Test stopped during Method Exit of doNothing");
     runTestOn(new StandardTestObject(false),
         (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ false, thr),
-        Test1953::clearSuspendMethodEvent);
+        SuspendEvents::clearSuspendMethodEvent);
 
     // NB We need another test to make sure the MethodEntered event is triggered twice.
     System.out.println("Test stopped during Method Enter of doNothing");
     runTestOn(new StandardTestObject(false),
         (thr) -> setupSuspendMethodEvent(doNothingMethod, /*enter*/ true, thr),
-        Test1953::clearSuspendMethodEvent);
+        SuspendEvents::clearSuspendMethodEvent);
 
     System.out.println("Test stopped during Method Exit of calledFunction");
     runTestOn(new StandardTestObject(false),
         (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ false, thr),
-        Test1953::clearSuspendMethodEvent);
+        SuspendEvents::clearSuspendMethodEvent);
 
     System.out.println("Test stopped during Method Enter of calledFunction");
     runTestOn(new StandardTestObject(false),
         (thr) -> setupSuspendMethodEvent(calledFunction, /*enter*/ true, thr),
-        Test1953::clearSuspendMethodEvent);
+        SuspendEvents::clearSuspendMethodEvent);
 
     final Method exceptionOnceCalledMethod =
         ExceptionOnceObject.class.getDeclaredMethod("calledFunction");
     System.out.println("Test stopped during Method Exit due to exception thrown in same function");
     runTestOn(new ExceptionOnceObject(/*throwInSub*/ false),
         (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr),
-        Test1953::clearSuspendMethodEvent);
+        SuspendEvents::clearSuspendMethodEvent);
 
     System.out.println("Test stopped during Method Exit due to exception thrown in subroutine");
     runTestOn(new ExceptionOnceObject(/*throwInSub*/ true),
         (thr) -> setupSuspendMethodEvent(exceptionOnceCalledMethod, /*enter*/ false, thr),
-        Test1953::clearSuspendMethodEvent);
+        SuspendEvents::clearSuspendMethodEvent);
 
     System.out.println("Test stopped during notifyFramePop without exception on pop of calledFunction");
     runTestOn(new StandardTestObject(false),
         (thr) -> setupSuspendPopFrameEvent(1, doNothingMethod, thr),
-        Test1953::clearSuspendPopFrameEvent);
+        SuspendEvents::clearSuspendPopFrameEvent);
 
     System.out.println("Test stopped during notifyFramePop without exception on pop of doNothing");
     runTestOn(new StandardTestObject(false),
         (thr) -> setupSuspendPopFrameEvent(0, doNothingMethod, thr),
-        Test1953::clearSuspendPopFrameEvent);
+        SuspendEvents::clearSuspendPopFrameEvent);
 
     final Method exceptionThrowCalledMethod =
         ExceptionThrowTestObject.class.getDeclaredMethod("calledFunction");
     System.out.println("Test stopped during notifyFramePop with exception on pop of calledFunction");
     runTestOn(new ExceptionThrowTestObject(false),
         (thr) -> setupSuspendPopFrameEvent(0, exceptionThrowCalledMethod, thr),
-        Test1953::clearSuspendPopFrameEvent);
+        SuspendEvents::clearSuspendPopFrameEvent);
 
     final Method exceptionCatchThrowMethod =
         ExceptionCatchTestObject.class.getDeclaredMethod("doThrow");
     System.out.println("Test stopped during notifyFramePop with exception on pop of doThrow");
     runTestOn(new ExceptionCatchTestObject(),
         (thr) -> setupSuspendPopFrameEvent(0, exceptionCatchThrowMethod, thr),
-        Test1953::clearSuspendPopFrameEvent);
+        SuspendEvents::clearSuspendPopFrameEvent);
 
     System.out.println("Test stopped during ExceptionCatch event of calledFunction " +
         "(catch in called function, throw in called function)");
     runTestOn(new ExceptionThrowTestObject(true),
         (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ true, thr),
-        Test1953::clearSuspendExceptionEvent);
+        SuspendEvents::clearSuspendExceptionEvent);
 
     final Method exceptionCatchCalledMethod =
         ExceptionCatchTestObject.class.getDeclaredMethod("calledFunction");
@@ -818,19 +830,19 @@
         "(catch in called function, throw in subroutine)");
     runTestOn(new ExceptionCatchTestObject(),
         (thr) -> setupSuspendExceptionEvent(exceptionCatchCalledMethod, /*catch*/ true, thr),
-        Test1953::clearSuspendExceptionEvent);
+        SuspendEvents::clearSuspendExceptionEvent);
 
     System.out.println("Test stopped during Exception event of calledFunction " +
         "(catch in calling function)");
     runTestOn(new ExceptionThrowTestObject(false),
         (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr),
-        Test1953::clearSuspendExceptionEvent);
+        SuspendEvents::clearSuspendExceptionEvent);
 
     System.out.println("Test stopped during Exception event of calledFunction " +
         "(catch in called function)");
     runTestOn(new ExceptionThrowTestObject(true),
         (thr) -> setupSuspendExceptionEvent(exceptionThrowCalledMethod, /*catch*/ false, thr),
-        Test1953::clearSuspendExceptionEvent);
+        SuspendEvents::clearSuspendExceptionEvent);
 
     final Method exceptionThrowFarCalledMethod =
         ExceptionThrowFarTestObject.class.getDeclaredMethod("calledFunction");
@@ -838,13 +850,13 @@
         "(catch in parent of calling function)");
     runTestOn(new ExceptionThrowFarTestObject(false),
         (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr),
-        Test1953::clearSuspendExceptionEvent);
+        SuspendEvents::clearSuspendExceptionEvent);
 
     System.out.println("Test stopped during Exception event of calledFunction " +
         "(catch in called function)");
     runTestOn(new ExceptionThrowFarTestObject(true),
         (thr) -> setupSuspendExceptionEvent(exceptionThrowFarCalledMethod, /*catch*/ false, thr),
-        Test1953::clearSuspendExceptionEvent);
+        SuspendEvents::clearSuspendExceptionEvent);
 
     // These tests are disabled for either the RI (b/116003018) or for jvmti-stress. For the
     // later it is due to the additional agent causing classes to be loaded earlier as it forces
@@ -857,7 +869,7 @@
       System.out.println("Test stopped during a ClassLoad event.");
       runTestOn(new ClassLoadObject(),
           (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_LOAD, ClassLoadObject.CLASS_NAMES, thr),
-          Test1953::clearSuspendClassEvent);
+          SuspendEvents::clearSuspendClassEvent);
 
       // The RI handles a PopFrame during a ClassPrepare event incorrectly. See b/116003018 for
       // more information.
@@ -866,7 +878,7 @@
           (thr) -> setupSuspendClassEvent(EVENT_TYPE_CLASS_PREPARE,
                                           ClassLoadObject.CLASS_NAMES,
                                           thr),
-          Test1953::clearSuspendClassEvent);
+          SuspendEvents::clearSuspendClassEvent);
     }
     System.out.println("Test stopped during random Suspend.");
     final SuspendSuddenlyObject sso = new SuspendSuddenlyObject();
@@ -899,14 +911,14 @@
 
     System.out.println("Test stopped during a native method fails");
     runTestOn(new NativeCalledObject(),
-        Test1953::setupWaitForNativeCall,
-        Test1953::clearWaitForNativeCall);
+        SuspendEvents::setupWaitForNativeCall,
+        SuspendEvents::clearWaitForNativeCall);
 
     System.out.println("Test stopped in a method called by native fails");
     final Method nativeCallerMethod = NativeCallerObject.class.getDeclaredMethod("calledFunction");
     runTestOn(new NativeCallerObject(),
         (thr) -> setupSuspendMethodEvent(nativeCallerMethod, /*enter*/ false, thr),
-        Test1953::clearSuspendMethodEvent);
+        SuspendEvents::clearSuspendMethodEvent);
   }
 
   // Volatile is to prevent any future optimizations that could invalidate this test by doing
@@ -939,38 +951,5 @@
   }
 
   public static native boolean isClassLoaded(String name);
-
-  public static native void setupTest();
   public static native void popFrame(Thread thr);
-
-  public static native void setupSuspendBreakpointFor(Executable meth, long loc, Thread thr);
-  public static native void clearSuspendBreakpointFor(Thread thr);
-
-  public static native void setupSuspendSingleStepAt(Executable meth, long loc, Thread thr);
-  public static native void clearSuspendSingleStepFor(Thread thr);
-
-  public static native void setupFieldSuspendFor(Class klass, Field f, boolean access, Thread thr);
-  public static native void clearFieldSuspendFor(Thread thr);
-
-  public static native void setupSuspendMethodEvent(Executable meth, boolean enter, Thread thr);
-  public static native void clearSuspendMethodEvent(Thread thr);
-
-  public static native void setupSuspendExceptionEvent(
-      Executable meth, boolean is_catch, Thread thr);
-  public static native void clearSuspendExceptionEvent(Thread thr);
-
-  public static native void setupSuspendPopFrameEvent(
-      int offset, Executable breakpointFunction, Thread thr);
-  public static native void clearSuspendPopFrameEvent(Thread thr);
-
-  public static final int EVENT_TYPE_CLASS_LOAD = 55;
-  public static final int EVENT_TYPE_CLASS_PREPARE = 56;
-  public static native void setupSuspendClassEvent(
-      int eventType, String[] interestingNames, Thread thr);
-  public static native void clearSuspendClassEvent(Thread thr);
-
-  public static native void setupWaitForNativeCall(Thread thr);
-  public static native void clearWaitForNativeCall(Thread thr);
-
-  public static native void waitForSuspendHit(Thread thr);
 }
diff --git a/test/1954-pop-frame-jit/src/art/SuspendEvents.java b/test/1954-pop-frame-jit/src/art/SuspendEvents.java
new file mode 120000
index 0000000..ee0632b
--- /dev/null
+++ b/test/1954-pop-frame-jit/src/art/SuspendEvents.java
@@ -0,0 +1 @@
+../../../1953-pop-frame/src/art/SuspendEvents.java
\ No newline at end of file
diff --git a/test/1955-pop-frame-jit-called/src/art/SuspendEvents.java b/test/1955-pop-frame-jit-called/src/art/SuspendEvents.java
new file mode 120000
index 0000000..ee0632b
--- /dev/null
+++ b/test/1955-pop-frame-jit-called/src/art/SuspendEvents.java
@@ -0,0 +1 @@
+../../../1953-pop-frame/src/art/SuspendEvents.java
\ No newline at end of file
diff --git a/test/1956-pop-frame-jit-calling/src/art/SuspendEvents.java b/test/1956-pop-frame-jit-calling/src/art/SuspendEvents.java
new file mode 120000
index 0000000..ee0632b
--- /dev/null
+++ b/test/1956-pop-frame-jit-calling/src/art/SuspendEvents.java
@@ -0,0 +1 @@
+../../../1953-pop-frame/src/art/SuspendEvents.java
\ No newline at end of file
diff --git a/test/Android.bp b/test/Android.bp
index fed3034..4513abc 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -229,6 +229,7 @@
         "ti-agent/monitors_helper.cc",
         "ti-agent/redefinition_helper.cc",
         "ti-agent/suspension_helper.cc",
+        "ti-agent/suspend_event_helper.cc",
         "ti-agent/stack_trace_helper.cc",
         "ti-agent/threads_helper.cc",
         "ti-agent/trace_helper.cc",
@@ -562,6 +563,7 @@
         "1927-exception-event/src/art/Exceptions.java",
         "1930-monitor-info/src/art/Monitors.java",
         "1934-jvmti-signal-thread/src/art/Threads.java",
+        "1953-pop-frame/src/art/SuspendEvents.java",
 
         // Actual test classes.
         "901-hello-ti-agent/src/art/Test901.java",
diff --git a/test/ti-agent/suspend_event_helper.cc b/test/ti-agent/suspend_event_helper.cc
new file mode 100644
index 0000000..29d94b1
--- /dev/null
+++ b/test/ti-agent/suspend_event_helper.cc
@@ -0,0 +1,802 @@
+/*
+ * Copyright (C) 2019 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 "suspend_event_helper.h"
+
+#include <inttypes.h>
+
+#include <cstdio>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+#include "jni.h"
+#include "jvmti.h"
+#include "scoped_local_ref.h"
+#include "scoped_utf_chars.h"
+
+// Test infrastructure
+#include "jni_binder.h"
+#include "jni_helper.h"
+#include "jvmti_helper.h"
+#include "test_env.h"
+#include "ti_macros.h"
+
+namespace art {
+namespace common_suspend_event {
+
+struct TestData {
+  jlocation target_loc;
+  jmethodID target_method;
+  jclass target_klass;
+  jfieldID target_field;
+  jrawMonitorID notify_monitor;
+  jint frame_pop_offset;
+  jmethodID frame_pop_setup_method;
+  std::vector<std::string> interesting_classes;
+  bool hit_location;
+
+  TestData(jvmtiEnv* jvmti,
+           JNIEnv* env,
+           jlocation loc,
+           jobject meth,
+           jclass klass,
+           jobject field,
+           jobject setup_meth,
+           jint pop_offset,
+           const std::vector<std::string>&& interesting)
+      : target_loc(loc), target_method(meth != nullptr ? env->FromReflectedMethod(meth) : nullptr),
+        target_klass(reinterpret_cast<jclass>(env->NewGlobalRef(klass))),
+        target_field(field != nullptr ? env->FromReflectedField(field) : nullptr),
+        frame_pop_offset(pop_offset),
+        frame_pop_setup_method(setup_meth != nullptr ? env->FromReflectedMethod(setup_meth)
+                                                     : nullptr),
+        interesting_classes(interesting), hit_location(false) {
+    JvmtiErrorToException(
+        env, jvmti, jvmti->CreateRawMonitor("SuspendStopMonitor", &notify_monitor));
+  }
+
+  void PerformSuspend(jvmtiEnv* jvmti, JNIEnv* env) {
+    // Wake up the waiting thread.
+    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorEnter(notify_monitor));
+    hit_location = true;
+    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorNotifyAll(notify_monitor));
+    JvmtiErrorToException(env, jvmti, jvmti->RawMonitorExit(notify_monitor));
+    // Suspend ourself
+    jvmti->SuspendThread(nullptr);
+  }
+};
+
+void PerformSuspension(jvmtiEnv* jvmti, JNIEnv* env) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti->GetThreadLocalStorage(/* thread */ nullptr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL
+cbSingleStep(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID meth, jlocation loc) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (meth != data->target_method || loc != data->target_loc) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbExceptionCatch(jvmtiEnv* jvmti,
+                              JNIEnv* env,
+                              jthread thr,
+                              jmethodID method,
+                              jlocation location ATTRIBUTE_UNUSED,
+                              jobject exception ATTRIBUTE_UNUSED) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbException(jvmtiEnv* jvmti,
+                         JNIEnv* env,
+                         jthread thr,
+                         jmethodID method,
+                         jlocation location ATTRIBUTE_UNUSED,
+                         jobject exception ATTRIBUTE_UNUSED,
+                         jmethodID catch_method ATTRIBUTE_UNUSED,
+                         jlocation catch_location ATTRIBUTE_UNUSED) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbMethodEntry(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbMethodExit(jvmtiEnv* jvmti,
+                          JNIEnv* env,
+                          jthread thr,
+                          jmethodID method,
+                          jboolean was_popped_by_exception ATTRIBUTE_UNUSED,
+                          jvalue return_value ATTRIBUTE_UNUSED) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (method != data->target_method) {
+    return;
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbFieldModification(jvmtiEnv* jvmti,
+                                 JNIEnv* env,
+                                 jthread thr,
+                                 jmethodID method ATTRIBUTE_UNUSED,
+                                 jlocation location ATTRIBUTE_UNUSED,
+                                 jclass field_klass ATTRIBUTE_UNUSED,
+                                 jobject object ATTRIBUTE_UNUSED,
+                                 jfieldID field,
+                                 char signature_type ATTRIBUTE_UNUSED,
+                                 jvalue new_value ATTRIBUTE_UNUSED) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (field != data->target_field) {
+    // TODO What to do here.
+    LOG(FATAL) << "Strange, shouldn't get here!";
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbFieldAccess(jvmtiEnv* jvmti,
+                           JNIEnv* env,
+                           jthread thr,
+                           jmethodID method ATTRIBUTE_UNUSED,
+                           jlocation location ATTRIBUTE_UNUSED,
+                           jclass field_klass,
+                           jobject object ATTRIBUTE_UNUSED,
+                           jfieldID field) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (field != data->target_field || !env->IsSameObject(field_klass, data->target_klass)) {
+    // TODO What to do here.
+    LOG(FATAL) << "Strange, shouldn't get here!";
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL
+cbBreakpointHit(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jmethodID method, jlocation loc) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (data->frame_pop_setup_method == method) {
+    CHECK(loc == 0) << "We should have stopped at location 0";
+    if (JvmtiErrorToException(env, jvmti, jvmti->NotifyFramePop(thr, data->frame_pop_offset))) {
+      return;
+    }
+    return;
+  }
+  if (method != data->target_method || loc != data->target_loc) {
+    // TODO What to do here.
+    LOG(FATAL) << "Strange, shouldn't get here!";
+  }
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbFramePop(jvmtiEnv* jvmti,
+                        JNIEnv* env,
+                        jthread thr,
+                        jmethodID method ATTRIBUTE_UNUSED,
+                        jboolean was_popped_by_exception ATTRIBUTE_UNUSED) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  data->PerformSuspend(jvmti, env);
+}
+
+void JNICALL cbClassLoadOrPrepare(jvmtiEnv* jvmti, JNIEnv* env, jthread thr, jclass klass) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  char* name;
+  if (JvmtiErrorToException(env, jvmti, jvmti->GetClassSignature(klass, &name, nullptr))) {
+    return;
+  }
+  std::string name_str(name);
+  if (JvmtiErrorToException(
+          env, jvmti, jvmti->Deallocate(reinterpret_cast<unsigned char*>(name)))) {
+    return;
+  }
+  if (std::find(data->interesting_classes.cbegin(), data->interesting_classes.cend(), name_str) !=
+      data->interesting_classes.cend()) {
+    data->PerformSuspend(jvmti, env);
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupTest(JNIEnv* env,
+                                                                   jclass klass ATTRIBUTE_UNUSED) {
+  jvmtiCapabilities caps;
+  memset(&caps, 0, sizeof(caps));
+  // Most of these will already be there but might as well be complete.
+  caps.can_pop_frame = 1;
+  caps.can_generate_single_step_events = 1;
+  caps.can_generate_breakpoint_events = 1;
+  caps.can_suspend = 1;
+  caps.can_generate_method_entry_events = 1;
+  caps.can_generate_method_exit_events = 1;
+  caps.can_generate_monitor_events = 1;
+  caps.can_generate_exception_events = 1;
+  caps.can_generate_frame_pop_events = 1;
+  caps.can_generate_field_access_events = 1;
+  caps.can_generate_field_modification_events = 1;
+  caps.can_redefine_classes = 1;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->AddCapabilities(&caps))) {
+    return;
+  }
+  jvmtiEventCallbacks cb;
+  memset(&cb, 0, sizeof(cb));
+  // TODO Add the rest of these.
+  cb.Breakpoint = cbBreakpointHit;
+  cb.SingleStep = cbSingleStep;
+  cb.FieldAccess = cbFieldAccess;
+  cb.FieldModification = cbFieldModification;
+  cb.MethodEntry = cbMethodEntry;
+  cb.MethodExit = cbMethodExit;
+  cb.Exception = cbException;
+  cb.ExceptionCatch = cbExceptionCatch;
+  cb.FramePop = cbFramePop;
+  cb.ClassLoad = cbClassLoadOrPrepare;
+  cb.ClassPrepare = cbClassLoadOrPrepare;
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)));
+}
+
+static bool DeleteTestData(JNIEnv* env, jthread thr, TestData* data) {
+  env->DeleteGlobalRef(data->target_klass);
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return false;
+  }
+  return JvmtiErrorToException(
+      env, jvmti_env, jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data)));
+}
+
+static TestData* SetupTestData(JNIEnv* env,
+                               jobject meth,
+                               jlocation loc,
+                               jclass target_klass,
+                               jobject field,
+                               jobject setup_meth,
+                               jint pop_offset,
+                               const std::vector<std::string>&& interesting_names) {
+  void* data_ptr;
+  TestData* data;
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->Allocate(sizeof(TestData), reinterpret_cast<uint8_t**>(&data_ptr)))) {
+    return nullptr;
+  }
+  data = new (data_ptr) TestData(jvmti_env,
+                                 env,
+                                 loc,
+                                 meth,
+                                 target_klass,
+                                 field,
+                                 setup_meth,
+                                 pop_offset,
+                                 std::move(interesting_names));
+  if (env->ExceptionCheck()) {
+    env->DeleteGlobalRef(data->target_klass);
+    jvmti_env->Deallocate(reinterpret_cast<uint8_t*>(data));
+    return nullptr;
+  }
+  return data;
+}
+
+static TestData* SetupTestData(JNIEnv* env,
+                               jobject meth,
+                               jlocation loc,
+                               jclass target_klass,
+                               jobject field,
+                               jobject setup_meth,
+                               jint pop_offset) {
+  std::vector<std::string> empty;
+  return SetupTestData(
+      env, meth, loc, target_klass, field, setup_meth, pop_offset, std::move(empty));
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_art_SuspendEvents_setupSuspendClassEvent(JNIEnv* env,
+                                              jclass klass ATTRIBUTE_UNUSED,
+                                              jint event_num,
+                                              jobjectArray interesting_names,
+                                              jthread thr) {
+  CHECK(event_num == JVMTI_EVENT_CLASS_LOAD || event_num == JVMTI_EVENT_CLASS_PREPARE);
+  std::vector<std::string> names;
+  jint cnt = env->GetArrayLength(interesting_names);
+  for (jint i = 0; i < cnt; i++) {
+    env->PushLocalFrame(1);
+    jstring name_obj = reinterpret_cast<jstring>(env->GetObjectArrayElement(interesting_names, i));
+    const char* name_chr = env->GetStringUTFChars(name_obj, nullptr);
+    names.push_back(std::string(name_chr));
+    env->ReleaseStringUTFChars(name_obj, name_chr);
+    env->PopLocalFrame(nullptr);
+  }
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0, std::move(names));
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(
+      env,
+      jvmti_env,
+      jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, static_cast<jvmtiEvent>(event_num), thr));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendClassEvent(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_LOAD, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_CLASS_PREPARE, thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendSingleStepAt(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject meth, jlocation loc, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(
+      env,
+      jvmti_env,
+      jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_SINGLE_STEP, thr));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendSingleStepFor(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_SINGLE_STEP, thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendPopFrameEvent(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jint offset, jobject breakpoint_func, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, breakpoint_func, offset);
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_FRAME_POP, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->SetBreakpoint(data->frame_pop_setup_method, 0))) {
+    return;
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendPopFrameEvent(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FRAME_POP, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->ClearBreakpoint(data->frame_pop_setup_method, 0))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendBreakpointFor(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject meth, jlocation loc, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, meth, loc, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
+    return;
+  }
+  JvmtiErrorToException(
+      env, jvmti_env, jvmti_env->SetBreakpoint(data->target_method, data->target_loc));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendBreakpointFor(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_BREAKPOINT, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->ClearBreakpoint(data->target_method, data->target_loc))) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendExceptionEvent(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method, jboolean is_catch, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(
+      env,
+      jvmti_env,
+      jvmti_env->SetEventNotificationMode(
+          JVMTI_ENABLE, is_catch ? JVMTI_EVENT_EXCEPTION_CATCH : JVMTI_EVENT_EXCEPTION, thr));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendExceptionEvent(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION_CATCH, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_EXCEPTION, thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupSuspendMethodEvent(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject method, jboolean enter, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, method, 0, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  JvmtiErrorToException(
+      env,
+      jvmti_env,
+      jvmti_env->SetEventNotificationMode(
+          JVMTI_ENABLE, enter ? JVMTI_EVENT_METHOD_ENTRY : JVMTI_EVENT_METHOD_EXIT, thr));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearSuspendMethodEvent(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_EXIT, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_METHOD_ENTRY, thr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_art_SuspendEvents_setupFieldSuspendFor(JNIEnv* env,
+                                            jclass klass ATTRIBUTE_UNUSED,
+                                            jclass target_klass,
+                                            jobject field,
+                                            jboolean access,
+                                            jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, target_klass, field, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(
+                                JVMTI_ENABLE,
+                                access ? JVMTI_EVENT_FIELD_ACCESS : JVMTI_EVENT_FIELD_MODIFICATION,
+                                thr))) {
+    return;
+  }
+  if (access) {
+    JvmtiErrorToException(
+        env, jvmti_env, jvmti_env->SetFieldAccessWatch(data->target_klass, data->target_field));
+  } else {
+    JvmtiErrorToException(
+        env,
+        jvmti_env,
+        jvmti_env->SetFieldModificationWatch(data->target_klass, data->target_field));
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearFieldSuspendFor(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->SetEventNotificationMode(JVMTI_DISABLE, JVMTI_EVENT_FIELD_ACCESS, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(
+                                JVMTI_DISABLE, JVMTI_EVENT_FIELD_MODIFICATION, thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->ClearFieldModificationWatch(data->target_klass, data->target_field)) &&
+      JvmtiErrorToException(
+          env,
+          jvmti_env,
+          jvmti_env->ClearFieldAccessWatch(data->target_klass, data->target_field))) {
+    return;
+  } else {
+    env->ExceptionClear();
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_setupWaitForNativeCall(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data == nullptr) << "Data was not cleared!";
+  data = SetupTestData(env, nullptr, 0, nullptr, nullptr, nullptr, 0);
+  if (data == nullptr) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, data))) {
+    return;
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_SuspendEvents_clearWaitForNativeCall(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetThreadLocalStorage(thr, nullptr))) {
+    return;
+  }
+  DeleteTestData(env, thr, data);
+}
+
+extern "C" JNIEXPORT void JNICALL
+Java_art_SuspendEvents_waitForSuspendHit(JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  TestData* data;
+  if (JvmtiErrorToException(
+          env, jvmti_env, jvmti_env->GetThreadLocalStorage(thr, reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data != nullptr);
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(data->notify_monitor))) {
+    return;
+  }
+  while (!data->hit_location) {
+    if (JvmtiErrorToException(
+            env, jvmti_env, jvmti_env->RawMonitorWait(data->notify_monitor, -1))) {
+      return;
+    }
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(data->notify_monitor))) {
+    return;
+  }
+  jint state = 0;
+  while (!JvmtiErrorToException(env, jvmti_env, jvmti_env->GetThreadState(thr, &state)) &&
+         (state & JVMTI_THREAD_STATE_SUSPENDED) == 0) {
+  }
+}
+}  // namespace common_suspend_event
+}  // namespace art
diff --git a/test/ti-agent/suspend_event_helper.h b/test/ti-agent/suspend_event_helper.h
new file mode 100644
index 0000000..74740bc
--- /dev/null
+++ b/test/ti-agent/suspend_event_helper.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 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_TEST_TI_AGENT_SUSPEND_EVENT_HELPER_H_
+#define ART_TEST_TI_AGENT_SUSPEND_EVENT_HELPER_H_
+
+#include "jni.h"
+#include "jvmti.h"
+
+namespace art {
+namespace common_suspend_event {
+
+void PerformSuspension(jvmtiEnv* jvmti, JNIEnv* env);
+
+}  // namespace common_suspend_event
+}  // namespace art
+#endif  // ART_TEST_TI_AGENT_SUSPEND_EVENT_HELPER_H_