Clean up ti-stress
Wrap some jvmti calls in scoped accessors that do cleanup and some
other miscellaneous cleanup.
Test: ./test.py -j40
Test: ./test/run-test --host --jvmti-trace-stress 001-HelloWorld
Change-Id: Ide807972903cb25efa38c0d03938d8e43fa89389
diff --git a/test/ti-stress/stress.cc b/test/ti-stress/stress.cc
index 497db1c..515a391 100644
--- a/test/ti-stress/stress.cc
+++ b/test/ti-stress/stress.cc
@@ -18,6 +18,7 @@
#include <stdio.h>
#include <iostream>
#include <fstream>
+#include <memory>
#include <stdio.h>
#include <sstream>
#include <strstream>
@@ -87,6 +88,142 @@
return ReadIntoBuffer(data->out_temp_dex, dex);
}
+class ScopedThreadInfo {
+ public:
+ ScopedThreadInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jthread thread)
+ : jvmtienv_(jvmtienv), env_(env), free_name_(false) {
+ memset(&info_, 0, sizeof(info_));
+ if (thread == nullptr) {
+ info_.name = const_cast<char*>("<NULLPTR>");
+ } else if (jvmtienv->GetThreadInfo(thread, &info_) != JVMTI_ERROR_NONE) {
+ info_.name = const_cast<char*>("<UNKNOWN THREAD>");
+ } else {
+ free_name_ = true;
+ }
+ }
+
+ ~ScopedThreadInfo() {
+ if (free_name_) {
+ jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(info_.name));
+ }
+ env_->DeleteLocalRef(info_.thread_group);
+ env_->DeleteLocalRef(info_.context_class_loader);
+ }
+
+ const char* GetName() const {
+ return info_.name;
+ }
+
+ private:
+ jvmtiEnv* jvmtienv_;
+ JNIEnv* env_;
+ bool free_name_;
+ jvmtiThreadInfo info_;
+};
+
+class ScopedClassInfo {
+ public:
+ ScopedClassInfo(jvmtiEnv* jvmtienv, jclass c)
+ : jvmtienv_(jvmtienv),
+ class_(c),
+ name_(nullptr),
+ generic_(nullptr) {}
+
+ ~ScopedClassInfo() {
+ jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
+ jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
+ }
+
+ bool Init() {
+ return jvmtienv_->GetClassSignature(class_, &name_, &generic_) == JVMTI_ERROR_NONE;
+ }
+
+ jclass GetClass() const {
+ return class_;
+ }
+ const char* GetName() const {
+ return name_;
+ }
+ const char* GetGeneric() const {
+ return generic_;
+ }
+
+ private:
+ jvmtiEnv* jvmtienv_;
+ jclass class_;
+ char* name_;
+ char* generic_;
+};
+
+class ScopedMethodInfo {
+ public:
+ ScopedMethodInfo(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m)
+ : jvmtienv_(jvmtienv),
+ env_(env),
+ method_(m),
+ declaring_class_(nullptr),
+ class_info_(nullptr),
+ name_(nullptr),
+ signature_(nullptr),
+ generic_(nullptr) {}
+
+ ~ScopedMethodInfo() {
+ env_->DeleteLocalRef(declaring_class_);
+ jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(name_));
+ jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(signature_));
+ jvmtienv_->Deallocate(reinterpret_cast<unsigned char*>(generic_));
+ }
+
+ bool Init() {
+ if (jvmtienv_->GetMethodDeclaringClass(method_, &declaring_class_) != JVMTI_ERROR_NONE) {
+ return false;
+ }
+ class_info_.reset(new ScopedClassInfo(jvmtienv_, declaring_class_));
+ return class_info_->Init() &&
+ (jvmtienv_->GetMethodName(method_, &name_, &signature_, &generic_) == JVMTI_ERROR_NONE);
+ }
+
+ const ScopedClassInfo& GetDeclaringClassInfo() const {
+ return *class_info_;
+ }
+
+ jclass GetDeclaringClass() const {
+ return declaring_class_;
+ }
+
+ const char* GetName() const {
+ return name_;
+ }
+
+ const char* GetSignature() const {
+ return signature_;
+ }
+
+ const char* GetGeneric() const {
+ return generic_;
+ }
+
+ private:
+ jvmtiEnv* jvmtienv_;
+ JNIEnv* env_;
+ jmethodID method_;
+ jclass declaring_class_;
+ std::unique_ptr<ScopedClassInfo> class_info_;
+ char* name_;
+ char* signature_;
+ char* generic_;
+
+ friend std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m);
+};
+
+std::ostream& operator<<(std::ostream &os, const ScopedMethodInfo* m) {
+ return os << *m;
+}
+
+std::ostream& operator<<(std::ostream &os, ScopedMethodInfo const& m) {
+ return os << m.GetDeclaringClassInfo().GetName() << "->" << m.GetName() << m.GetSignature();
+}
+
static void doJvmtiMethodBind(jvmtiEnv* jvmtienv,
JNIEnv* env,
jthread thread,
@@ -94,38 +231,14 @@
void* address,
/*out*/void** out_address) {
*out_address = address;
- jvmtiThreadInfo info;
- if (thread == nullptr) {
- info.name = const_cast<char*>("<NULLPTR>");
- } else if (jvmtienv->GetThreadInfo(thread, &info) != JVMTI_ERROR_NONE) {
- info.name = const_cast<char*>("<UNKNOWN THREAD>");
- }
- char *fname, *fsig, *fgen;
- char *cname, *cgen;
- jclass klass = nullptr;
- if (jvmtienv->GetMethodDeclaringClass(m, &klass) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get method declaring class!";
+ ScopedThreadInfo thread_info(jvmtienv, env, thread);
+ ScopedMethodInfo method_info(jvmtienv, env, m);
+ if (!method_info.Init()) {
+ LOG(ERROR) << "Unable to get method info!";
return;
}
- if (jvmtienv->GetMethodName(m, &fname, &fsig, &fgen) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get method name!";
- env->DeleteLocalRef(klass);
- return;
- }
- if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get class name!";
- env->DeleteLocalRef(klass);
- return;
- }
- LOG(INFO) << "Loading native method \"" << cname << "->" << fname << fsig << "\". Thread is \""
- << info.name << "\"";
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fname));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fsig));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fgen));
- env->DeleteLocalRef(klass);
- return;
+ LOG(INFO) << "Loading native method \"" << method_info << "\". Thread is "
+ << thread_info.GetName();
}
static std::string GetName(jvmtiEnv* jvmtienv, JNIEnv* jnienv, jobject obj) {
@@ -197,80 +310,32 @@
jmethodID m,
jboolean was_popped_by_exception,
jvalue val) {
- jvmtiThreadInfo info;
- if (thread == nullptr) {
- info.name = const_cast<char*>("<NULLPTR>");
- } else if (jvmtienv->GetThreadInfo(thread, &info) != JVMTI_ERROR_NONE) {
- // LOG(WARNING) << "Unable to get thread info!";
- info.name = const_cast<char*>("<UNKNOWN THREAD>");
- }
- char *fname, *fsig, *fgen;
- char *cname, *cgen;
- jclass klass = nullptr;
- if (jvmtienv->GetMethodDeclaringClass(m, &klass) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get method declaring class!";
+ ScopedThreadInfo info(jvmtienv, env, thread);
+ ScopedMethodInfo method_info(jvmtienv, env, m);
+ if (!method_info.Init()) {
+ LOG(ERROR) << "Unable to get method info!";
return;
}
- if (jvmtienv->GetMethodName(m, &fname, &fsig, &fgen) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get method name!";
- env->DeleteLocalRef(klass);
- return;
- }
- if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get class name!";
- env->DeleteLocalRef(klass);
- return;
- }
- std::string type(fsig);
+ std::string type(method_info.GetSignature());
type = type.substr(type.find(")") + 1);
std::string out_val(was_popped_by_exception ? "" : GetValOf(jvmtienv, env, type, val));
- LOG(INFO) << "Leaving method \"" << cname << "->" << fname << fsig << "\". Thread is \""
- << info.name << "\"." << std::endl
+ LOG(INFO) << "Leaving method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"."
+ << std::endl
<< " Cause: " << (was_popped_by_exception ? "exception" : "return ")
<< out_val << ".";
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fname));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fsig));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fgen));
- env->DeleteLocalRef(klass);
}
void JNICALL MethodEntryHook(jvmtiEnv* jvmtienv,
JNIEnv* env,
jthread thread,
jmethodID m) {
- jvmtiThreadInfo info;
- if (thread == nullptr) {
- info.name = const_cast<char*>("<NULLPTR>");
- } else if (jvmtienv->GetThreadInfo(thread, &info) != JVMTI_ERROR_NONE) {
- info.name = const_cast<char*>("<UNKNOWN THREAD>");
- }
- char *fname, *fsig, *fgen;
- char *cname, *cgen;
- jclass klass = nullptr;
- if (jvmtienv->GetMethodDeclaringClass(m, &klass) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get method declaring class!";
+ ScopedThreadInfo info(jvmtienv, env, thread);
+ ScopedMethodInfo method_info(jvmtienv, env, m);
+ if (!method_info.Init()) {
+ LOG(ERROR) << "Unable to get method info!";
return;
}
- if (jvmtienv->GetMethodName(m, &fname, &fsig, &fgen) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get method name!";
- env->DeleteLocalRef(klass);
- return;
- }
- if (jvmtienv->GetClassSignature(klass, &cname, &cgen) != JVMTI_ERROR_NONE) {
- LOG(ERROR) << "Unable to get class name!";
- env->DeleteLocalRef(klass);
- return;
- }
- LOG(INFO) << "Entering method \"" << cname << "->" << fname << fsig << "\". Thread is \""
- << info.name << "\"";
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cname));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(cgen));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fname));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fsig));
- jvmtienv->Deallocate(reinterpret_cast<unsigned char*>(fgen));
- env->DeleteLocalRef(klass);
+ LOG(INFO) << "Entering method \"" << method_info << "\". Thread is \"" << info.GetName() << "\"";
}
// The hook we are using.