summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
l---------openjdkjvmti/generate-operator-out.py1
-rw-r--r--openjdkjvmti/ti_phase.cc13
-rw-r--r--openjdkjvmti/ti_thread.cc24
-rw-r--r--openjdkjvmti/ti_thread.h7
-rw-r--r--test/1919-vminit-thread-start-timing/expected.txt4
-rw-r--r--test/1919-vminit-thread-start-timing/info.txt3
-rwxr-xr-xtest/1919-vminit-thread-start-timing/run17
-rw-r--r--test/1919-vminit-thread-start-timing/src/Main.java21
-rw-r--r--test/1919-vminit-thread-start-timing/src/art/Main.java28
-rw-r--r--test/1919-vminit-thread-start-timing/src/art/Test1919.java53
-rw-r--r--test/1919-vminit-thread-start-timing/vminit.cc192
-rw-r--r--test/1919-vminit-thread-start-timing/vminit.h30
-rw-r--r--test/Android.bp1
-rw-r--r--test/ti-agent/common_load.cc2
14 files changed, 380 insertions, 16 deletions
diff --git a/openjdkjvmti/generate-operator-out.py b/openjdkjvmti/generate-operator-out.py
new file mode 120000
index 0000000000..cc291d20c1
--- /dev/null
+++ b/openjdkjvmti/generate-operator-out.py
@@ -0,0 +1 @@
+../tools/generate-operator-out.py \ No newline at end of file
diff --git a/openjdkjvmti/ti_phase.cc b/openjdkjvmti/ti_phase.cc
index e8c1ca7335..07cf31c354 100644
--- a/openjdkjvmti/ti_phase.cc
+++ b/openjdkjvmti/ti_phase.cc
@@ -72,9 +72,16 @@ struct PhaseUtil::PhaseCallback : public art::RuntimePhaseCallback {
{
ThreadUtil::CacheData();
PhaseUtil::current_phase_ = JVMTI_PHASE_LIVE;
- ScopedLocalRef<jthread> thread(GetJniEnv(), GetCurrentJThread());
- art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative);
- event_handler->DispatchEvent<ArtJvmtiEvent::kVmInit>(nullptr, GetJniEnv(), thread.get());
+ {
+ ScopedLocalRef<jthread> thread(GetJniEnv(), GetCurrentJThread());
+ art::ScopedThreadSuspension sts(art::Thread::Current(), art::ThreadState::kNative);
+ event_handler->DispatchEvent<ArtJvmtiEvent::kVmInit>(
+ nullptr, GetJniEnv(), thread.get());
+ }
+ // We need to have these events be ordered to match behavior expected by some real-world
+ // agents. The spec does not really require this but compatibility is a useful property to
+ // maintain.
+ ThreadUtil::VMInitEventSent();
}
break;
case RuntimePhase::kDeath:
diff --git a/openjdkjvmti/ti_thread.cc b/openjdkjvmti/ti_thread.cc
index 6fa73f8a8c..b0a1a8556a 100644
--- a/openjdkjvmti/ti_thread.cc
+++ b/openjdkjvmti/ti_thread.cc
@@ -57,13 +57,14 @@ namespace openjdkjvmti {
art::ArtField* ThreadUtil::context_class_loader_ = nullptr;
-struct ThreadCallback : public art::ThreadLifecycleCallback, public art::RuntimePhaseCallback {
+struct ThreadCallback : public art::ThreadLifecycleCallback {
jthread GetThreadObject(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) {
if (self->GetPeer() == nullptr) {
return nullptr;
}
return self->GetJniEnv()->AddLocalReference<jthread>(self->GetPeer());
}
+
template <ArtJvmtiEvent kEvent>
void Post(art::Thread* self) REQUIRES_SHARED(art::Locks::mutator_lock_) {
DCHECK_EQ(self, art::Thread::Current());
@@ -96,15 +97,6 @@ struct ThreadCallback : public art::ThreadLifecycleCallback, public art::Runtime
Post<ArtJvmtiEvent::kThreadEnd>(self);
}
- void NextRuntimePhase(RuntimePhase phase) OVERRIDE REQUIRES_SHARED(art::Locks::mutator_lock_) {
- if (phase == RuntimePhase::kInit) {
- // We moved to VMInit. Report the main thread as started (it was attached early, and must
- // not be reported until Init.
- started = true;
- Post<ArtJvmtiEvent::kThreadStart>(art::Thread::Current());
- }
- }
-
EventHandler* event_handler = nullptr;
bool started = false;
};
@@ -121,10 +113,19 @@ void ThreadUtil::Register(EventHandler* handler) {
art::ThreadState::kWaitingForDebuggerToAttach);
art::ScopedSuspendAll ssa("Add thread callback");
runtime->GetRuntimeCallbacks()->AddThreadLifecycleCallback(&gThreadCallback);
- runtime->GetRuntimeCallbacks()->AddRuntimePhaseCallback(&gThreadCallback);
+}
+
+void ThreadUtil::VMInitEventSent() {
+ // We should have already started.
+ DCHECK(gThreadCallback.started);
+ // We moved to VMInit. Report the main thread as started (it was attached early, and must not be
+ // reported until Init.
+ gThreadCallback.Post<ArtJvmtiEvent::kThreadStart>(art::Thread::Current());
}
void ThreadUtil::CacheData() {
+ // We must have started since it is now safe to cache our data;
+ gThreadCallback.started = true;
art::ScopedObjectAccess soa(art::Thread::Current());
art::ObjPtr<art::mirror::Class> thread_class =
soa.Decode<art::mirror::Class>(art::WellKnownClasses::java_lang_Thread);
@@ -140,7 +141,6 @@ void ThreadUtil::Unregister() {
art::ScopedSuspendAll ssa("Remove thread callback");
art::Runtime* runtime = art::Runtime::Current();
runtime->GetRuntimeCallbacks()->RemoveThreadLifecycleCallback(&gThreadCallback);
- runtime->GetRuntimeCallbacks()->RemoveRuntimePhaseCallback(&gThreadCallback);
}
jvmtiError ThreadUtil::GetCurrentThread(jvmtiEnv* env ATTRIBUTE_UNUSED, jthread* thread_ptr) {
diff --git a/openjdkjvmti/ti_thread.h b/openjdkjvmti/ti_thread.h
index 03c49d7788..a19974aa16 100644
--- a/openjdkjvmti/ti_thread.h
+++ b/openjdkjvmti/ti_thread.h
@@ -53,9 +53,14 @@ class ThreadUtil {
static void Register(EventHandler* event_handler);
static void Unregister();
- // To be called when it is safe to cache data.
+ // To be called when it is safe to cache data. This means that we have at least entered the
+ // RuntimePhase::kInit but we might or might not have already called VMInit event.
static void CacheData();
+ // Called just after we have sent the VMInit callback so that ThreadUtil can do final setup. This
+ // ensures that there are no timing issues between the two callbacks.
+ static void VMInitEventSent() REQUIRES_SHARED(art::Locks::mutator_lock_);
+
// Handle a jvmtiEnv going away.
static void RemoveEnvironment(jvmtiEnv* env);
diff --git a/test/1919-vminit-thread-start-timing/expected.txt b/test/1919-vminit-thread-start-timing/expected.txt
new file mode 100644
index 0000000000..63614512cf
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/expected.txt
@@ -0,0 +1,4 @@
+VMInit: main
+ThreadStart: JVMTI_THREAD-Test1919
+Test1919AgentThread: JVMTI_THREAD-Test1919
+ThreadStart: main
diff --git a/test/1919-vminit-thread-start-timing/info.txt b/test/1919-vminit-thread-start-timing/info.txt
new file mode 100644
index 0000000000..995f0a1209
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/info.txt
@@ -0,0 +1,3 @@
+Tests basic functions in the jvmti plugin.
+
+Test the interaction of VMInit events and thread starts.
diff --git a/test/1919-vminit-thread-start-timing/run b/test/1919-vminit-thread-start-timing/run
new file mode 100755
index 0000000000..c6e62ae6cd
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+./default-run "$@" --jvmti
diff --git a/test/1919-vminit-thread-start-timing/src/Main.java b/test/1919-vminit-thread-start-timing/src/Main.java
new file mode 100644
index 0000000000..65781b8484
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/src/Main.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+ public static void main(String[] args) {
+ art.Test1919.run();
+ }
+}
diff --git a/test/1919-vminit-thread-start-timing/src/art/Main.java b/test/1919-vminit-thread-start-timing/src/art/Main.java
new file mode 100644
index 0000000000..8b01920638
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/src/art/Main.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2017 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;
+
+// Binder class so the agent's C code has something that can be bound and exposed to tests.
+// In a package to separate cleanly and work around CTS reference issues (though this class
+// should be replaced in the CTS version).
+public class Main {
+ // Load the given class with the given classloader, and bind all native methods to corresponding
+ // C methods in the agent. Will abort if any of the steps fail.
+ public static native void bindAgentJNI(String className, ClassLoader classLoader);
+ // Same as above, giving the class directly.
+ public static native void bindAgentJNIForClass(Class<?> klass);
+}
diff --git a/test/1919-vminit-thread-start-timing/src/art/Test1919.java b/test/1919-vminit-thread-start-timing/src/art/Test1919.java
new file mode 100644
index 0000000000..3d5c079f74
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/src/art/Test1919.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 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;
+
+public class Test1919 {
+ public static final boolean PRINT_ALL_THREADS = false;
+
+ public static void run() {
+ for (Event e : getEvents()) {
+ if (PRINT_ALL_THREADS ||
+ e.thr.equals(Thread.currentThread()) ||
+ e.thr.getName().equals("JVMTI_THREAD-Test1919")) {
+ System.out.println(e.name + ": " + e.thr.getName());
+ }
+ }
+ }
+
+ static class Event {
+ public final String name;
+ public final Thread thr;
+ public Event(String name, Thread thr) {
+ this.name = name;
+ this.thr = thr;
+ }
+ }
+
+ public static Event[] getEvents() {
+ String[] ns = getEventNames();
+ Thread[] ts = getEventThreads();
+ Event[] es = new Event[Math.min(ns.length, ts.length)];
+ for (int i = 0; i < es.length; i++) {
+ es[i] = new Event(ns[i], ts[i]);
+ }
+ return es;
+ }
+
+ public static native String[] getEventNames();
+ public static native Thread[] getEventThreads();
+}
diff --git a/test/1919-vminit-thread-start-timing/vminit.cc b/test/1919-vminit-thread-start-timing/vminit.cc
new file mode 100644
index 0000000000..109c61f05c
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/vminit.cc
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "1919-vminit-thread-start-timing/vminit.h"
+
+#include <mutex>
+#include <thread>
+#include <vector>
+
+#include <jni.h>
+#include <stdio.h>
+#include <string.h>
+#include "android-base/macros.h"
+#include "jvmti.h"
+
+// Test infrastructure
+#include "scoped_local_ref.h"
+#include "jvmti_helper.h"
+#include "jni_helper.h"
+#include "test_env.h"
+
+namespace art {
+namespace Test1919VMInitThreadStart {
+
+struct EventData {
+ std::string event;
+ jobject data;
+};
+
+struct EventList {
+ jrawMonitorID events_mutex;
+ std::vector<EventData> events;
+};
+
+
+static void EnableEvent(jvmtiEnv* env, jvmtiEvent evt) {
+ jvmtiError error = env->SetEventNotificationMode(JVMTI_ENABLE, evt, nullptr);
+ if (error != JVMTI_ERROR_NONE) {
+ printf("Failed to enable event");
+ }
+}
+
+static void JNICALL ThreadStartCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) {
+ EventList* list = nullptr;
+ CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list)));
+ CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex));
+ list->events.push_back({ "ThreadStart", env->NewGlobalRef(thread) });
+ CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex));
+}
+
+static void JNICALL Test1919AgentThread(jvmtiEnv* jvmti,
+ JNIEnv* env,
+ void* arg ATTRIBUTE_UNUSED) {
+ EventList* list = nullptr;
+ CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list)));
+ CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex));
+ jthread cur;
+ CheckJvmtiError(jvmti, jvmti->GetCurrentThread(&cur));
+ list->events.push_back({ "Test1919AgentThread", env->NewGlobalRef(cur) });
+ env->DeleteLocalRef(cur);
+ // Wake up VMInit
+ CheckJvmtiError(jvmti, jvmti->RawMonitorNotify(list->events_mutex));
+ CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex));
+}
+
+static void CreateAgentThread(jvmtiEnv* jvmti, JNIEnv* env) {
+ // Create a Thread object.
+ ScopedLocalRef<jobject> thread_name(env, env->NewStringUTF("JVMTI_THREAD-Test1919"));
+ CHECK(thread_name.get() != nullptr);
+
+ ScopedLocalRef<jclass> thread_klass(env, env->FindClass("java/lang/Thread"));
+ CHECK(thread_klass.get() != nullptr);
+
+ ScopedLocalRef<jobject> thread(env, env->AllocObject(thread_klass.get()));
+ CHECK(thread.get() != nullptr);
+
+ jmethodID initID = env->GetMethodID(thread_klass.get(), "<init>", "(Ljava/lang/String;)V");
+ CHECK(initID != nullptr);
+
+ env->CallNonvirtualVoidMethod(thread.get(), thread_klass.get(), initID, thread_name.get());
+ CHECK(!env->ExceptionCheck());
+
+ // Run agent thread.
+ CheckJvmtiError(jvmti, jvmti->RunAgentThread(thread.get(),
+ Test1919AgentThread,
+ nullptr,
+ JVMTI_THREAD_NORM_PRIORITY));
+}
+
+static void JNICALL VMInitCallback(jvmtiEnv *jvmti, JNIEnv* env, jthread thread) {
+ EventList* list = nullptr;
+ CheckJvmtiError(jvmti, jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&list)));
+ CheckJvmtiError(jvmti, jvmti->RawMonitorEnter(list->events_mutex));
+ list->events.push_back({ "VMInit", env->NewGlobalRef(thread) });
+ // Create a new thread.
+ CreateAgentThread(jvmti, env);
+ // Wait for new thread to run.
+ CheckJvmtiError(jvmti, jvmti->RawMonitorWait(list->events_mutex, 0));
+ CheckJvmtiError(jvmti, jvmti->RawMonitorExit(list->events_mutex));
+}
+
+static void InstallVMEvents(jvmtiEnv* env) {
+ jvmtiEventCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+ callbacks.VMInit = VMInitCallback;
+ callbacks.ThreadStart = ThreadStartCallback;
+ jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+ if (ret != JVMTI_ERROR_NONE) {
+ printf("Failed to install callbacks");
+ }
+
+ EnableEvent(env, JVMTI_EVENT_VM_INIT);
+ EnableEvent(env, JVMTI_EVENT_THREAD_START);
+}
+
+static void InstallEventList(jvmtiEnv* env) {
+ EventList* list = nullptr;
+ CheckJvmtiError(env, env->Allocate(sizeof(EventList), reinterpret_cast<unsigned char**>(&list)));
+ memset(list, 0, sizeof(EventList));
+ CheckJvmtiError(env, env->CreateRawMonitor("Test1919 Monitor", &list->events_mutex));
+ CheckJvmtiError(env, env->SetEnvironmentLocalStorage(list));
+}
+
+jint OnLoad(JavaVM* vm,
+ char* options ATTRIBUTE_UNUSED,
+ void* reserved ATTRIBUTE_UNUSED) {
+ if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0) != 0) {
+ printf("Unable to get jvmti env!\n");
+ return 1;
+ }
+ InstallVMEvents(jvmti_env);
+ InstallEventList(jvmti_env);
+ return 0;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventNames(JNIEnv* env, jclass) {
+ EventList* list = nullptr;
+ if (JvmtiErrorToException(env,
+ jvmti_env,
+ jvmti_env->GetEnvironmentLocalStorage(
+ reinterpret_cast<void**>(&list)))) {
+ return nullptr;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) {
+ return nullptr;
+ }
+ jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/String",
+ [&](jint i) {
+ return env->NewStringUTF(list->events[i].event.c_str());
+ });
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) {
+ return nullptr;
+ }
+ return ret;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Test1919_getEventThreads(JNIEnv* env, jclass) {
+ EventList* list = nullptr;
+ if (JvmtiErrorToException(env,
+ jvmti_env,
+ jvmti_env->GetEnvironmentLocalStorage(
+ reinterpret_cast<void**>(&list)))) {
+ return nullptr;
+ }
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorEnter(list->events_mutex))) {
+ return nullptr;
+ }
+ jobjectArray ret = CreateObjectArray(env, list->events.size(), "java/lang/Thread",
+ [&](jint i) {
+ return env->NewLocalRef(list->events[i].data);
+ });
+ if (JvmtiErrorToException(env, jvmti_env, jvmti_env->RawMonitorExit(list->events_mutex))) {
+ return nullptr;
+ }
+ return ret;
+}
+
+} // namespace Test1919VMInitThreadStart
+} // namespace art
diff --git a/test/1919-vminit-thread-start-timing/vminit.h b/test/1919-vminit-thread-start-timing/vminit.h
new file mode 100644
index 0000000000..c4a5ea8ef1
--- /dev/null
+++ b/test/1919-vminit-thread-start-timing/vminit.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_TEST_1919_VMINIT_THREAD_START_TIMING_VMINIT_H_
+#define ART_TEST_1919_VMINIT_THREAD_START_TIMING_VMINIT_H_
+
+#include <jni.h>
+
+namespace art {
+namespace Test1919VMInitThreadStart {
+
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+
+} // namespace Test1919VMInitThreadStart
+} // namespace art
+
+#endif // ART_TEST_1919_VMINIT_THREAD_START_TIMING_VMINIT_H_
diff --git a/test/Android.bp b/test/Android.bp
index fab664a3e2..9b9ab108e6 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -295,6 +295,7 @@ art_cc_defaults {
"1908-suspend-native-resume-self/native_suspend_resume.cc",
"1909-per-agent-tls/agent_tls.cc",
"1914-get-local-instance/local_instance.cc",
+ "1919-vminit-thread-start-timing/vminit.cc",
],
shared_libs: [
"libbase",
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 1d13c620e3..d85f33a05d 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -28,6 +28,7 @@
#include "909-attach-agent/attach.h"
#include "936-search-onload/search_onload.h"
#include "983-source-transform-verify/source_transform.h"
+#include "1919-vminit-thread-start-timing/vminit.h"
namespace art {
@@ -82,6 +83,7 @@ static AgentLib agents[] = {
{ "941-recursive-obsolete-jit", common_redefine::OnLoad, nullptr },
{ "943-private-recursive-jit", common_redefine::OnLoad, nullptr },
{ "983-source-transform-verify", Test983SourceTransformVerify::OnLoad, nullptr },
+ { "1919-vminit-thread-start-timing", Test1919VMInitThreadStart::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {