Revert "Implement RetransformClasses"
This reverts commit a6c5e97a4395352bc8684e6af9cecb62b80c316c.
Reason for revert: Accidently introduces double-free bug in RedefineClasses.
Change-Id: I021336c4fcf0cfb304915b0ffc5eaba5f91fdd5e
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 32e3948..90467db 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -631,17 +631,7 @@
}
static jvmtiError RetransformClasses(jvmtiEnv* env, jint class_count, const jclass* classes) {
- std::string error_msg;
- jvmtiError res = Transformer::RetransformClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env),
- art::Runtime::Current(),
- art::Thread::Current(),
- class_count,
- classes,
- &error_msg);
- if (res != OK) {
- LOG(WARNING) << "FAILURE TO RETRANFORM " << error_msg;
- }
- return res;
+ return ERR(NOT_IMPLEMENTED);
}
static jvmtiError RedefineClasses(jvmtiEnv* env,
@@ -1265,6 +1255,78 @@
*format_ptr = jvmtiJlocationFormat::JVMTI_JLOCATION_JVMBCI;
return ERR(NONE);
}
+
+ // TODO Remove this once events are working.
+ static jvmtiError RetransformClassWithHook(jvmtiEnv* env,
+ jclass klass,
+ jvmtiEventClassFileLoadHook hook) {
+ std::vector<jclass> classes;
+ classes.push_back(klass);
+ return RetransformClassesWithHook(reinterpret_cast<ArtJvmTiEnv*>(env), classes, hook);
+ }
+
+ // TODO This will be called by the event handler for the art::ti Event Load Event
+ static jvmtiError RetransformClassesWithHook(ArtJvmTiEnv* env,
+ const std::vector<jclass>& classes,
+ jvmtiEventClassFileLoadHook hook) {
+ if (!IsValidEnv(env)) {
+ return ERR(INVALID_ENVIRONMENT);
+ }
+ jvmtiError res = OK;
+ std::string error;
+ for (jclass klass : classes) {
+ JNIEnv* jni_env = nullptr;
+ jobject loader = nullptr;
+ std::string name;
+ jobject protection_domain = nullptr;
+ jint data_len = 0;
+ unsigned char* dex_data = nullptr;
+ jvmtiError ret = OK;
+ std::string location;
+ if ((ret = GetTransformationData(env,
+ klass,
+ /*out*/&location,
+ /*out*/&jni_env,
+ /*out*/&loader,
+ /*out*/&name,
+ /*out*/&protection_domain,
+ /*out*/&data_len,
+ /*out*/&dex_data)) != OK) {
+ // TODO Do something more here? Maybe give log statements?
+ return ret;
+ }
+ jint new_data_len = 0;
+ unsigned char* new_dex_data = nullptr;
+ hook(env,
+ jni_env,
+ klass,
+ loader,
+ name.c_str(),
+ protection_domain,
+ data_len,
+ dex_data,
+ /*out*/&new_data_len,
+ /*out*/&new_dex_data);
+ // Check if anything actually changed.
+ if ((new_data_len != 0 || new_dex_data != nullptr) && new_dex_data != dex_data) {
+ jvmtiClassDefinition def = { klass, new_data_len, new_dex_data };
+ res = Redefiner::RedefineClasses(env,
+ art::Runtime::Current(),
+ art::Thread::Current(),
+ 1,
+ &def,
+ &error);
+ env->Deallocate(new_dex_data);
+ }
+ // Deallocate the old dex data.
+ env->Deallocate(dex_data);
+ if (res != OK) {
+ LOG(ERROR) << "FAILURE TO REDEFINE " << error;
+ return res;
+ }
+ }
+ return OK;
+ }
};
static bool IsJvmtiVersion(jint version) {
@@ -1307,7 +1369,10 @@
// The actual struct holding all of the entrypoints into the jvmti interface.
const jvmtiInterface_1 gJvmtiInterface = {
- nullptr, // reserved1
+ // SPECIAL FUNCTION: RetransformClassWithHook Is normally reserved1
+ // TODO Remove once we have events working.
+ reinterpret_cast<void*>(JvmtiFunctions::RetransformClassWithHook),
+ // nullptr, // reserved1
JvmtiFunctions::SetEventNotificationMode,
nullptr, // reserved3
JvmtiFunctions::GetAllThreads,
diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h
index 1c84d4d..5eadc5a 100644
--- a/runtime/openjdkjvmti/art_jvmti.h
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -47,7 +47,6 @@
namespace openjdkjvmti {
extern const jvmtiInterface_1 gJvmtiInterface;
-extern EventHandler gEventHandler;
// A structure that is a jvmtiEnv with additional information for the runtime.
struct ArtJvmTiEnv : public jvmtiEnv {
@@ -125,29 +124,6 @@
return ret;
}
-struct ArtClassDefinition {
- jclass klass;
- jobject loader;
- std::string name;
- jobject protection_domain;
- jint dex_len;
- JvmtiUniquePtr dex_data;
- bool modified;
-
- ArtClassDefinition() = default;
- ArtClassDefinition(ArtClassDefinition&& o) = default;
-
- void SetNewDexData(ArtJvmTiEnv* env, jint new_dex_len, unsigned char* new_dex_data) {
- if (new_dex_data == nullptr) {
- return;
- } else if (new_dex_data != dex_data.get() || new_dex_len != dex_len) {
- modified = true;
- dex_len = new_dex_len;
- dex_data = MakeJvmtiUniquePtr(env, new_dex_data);
- }
- }
-};
-
const jvmtiCapabilities kPotentialCapabilities = {
.can_tag_objects = 1,
.can_generate_field_modification_events = 0,
@@ -158,7 +134,7 @@
.can_get_current_contended_monitor = 0,
.can_get_monitor_info = 0,
.can_pop_frame = 0,
- .can_redefine_classes = 1,
+ .can_redefine_classes = 0,
.can_signal_thread = 0,
.can_get_source_file_name = 0,
.can_get_line_numbers = 0,
@@ -186,7 +162,7 @@
.can_get_owned_monitor_stack_depth_info = 0,
.can_get_constant_pool = 0,
.can_set_native_method_prefix = 0,
- .can_retransform_classes = 1,
+ .can_retransform_classes = 0,
.can_retransform_any_class = 0,
.can_generate_resource_exhaustion_heap_events = 0,
.can_generate_resource_exhaustion_threads_events = 0,
diff --git a/runtime/openjdkjvmti/events-inl.h b/runtime/openjdkjvmti/events-inl.h
index 21ec731..1e07bc6 100644
--- a/runtime/openjdkjvmti/events-inl.h
+++ b/runtime/openjdkjvmti/events-inl.h
@@ -115,95 +115,9 @@
}
template <typename ...Args>
-inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread*,
- ArtJvmtiEvent event,
- Args... args ATTRIBUTE_UNUSED) const {
- CHECK(event == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
- event == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
- LOG(FATAL) << "Incorrect arguments to ClassFileLoadHook!";
-}
-
-// TODO Locking of some type!
-template <>
-inline void EventHandler::DispatchClassFileLoadHookEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- JNIEnv* jnienv,
- jclass class_being_redefined,
- jobject loader,
- const char* name,
- jobject protection_domain,
- jint class_data_len,
- const unsigned char* class_data,
- jint* new_class_data_len,
- unsigned char** new_class_data) const {
- CHECK(event == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
- event == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable);
- using FnType = void(jvmtiEnv* /* jvmti_env */,
- JNIEnv* /* jnienv */,
- jclass /* class_being_redefined */,
- jobject /* loader */,
- const char* /* name */,
- jobject /* protection_domain */,
- jint /* class_data_len */,
- const unsigned char* /* class_data */,
- jint* /* new_class_data_len */,
- unsigned char** /* new_class_data */);
- jint current_len = class_data_len;
- unsigned char* current_class_data = const_cast<unsigned char*>(class_data);
- ArtJvmTiEnv* last_env = nullptr;
- for (ArtJvmTiEnv* env : envs) {
- if (ShouldDispatch(event, env, thread)) {
- jint new_len;
- unsigned char* new_data;
- FnType* callback = GetCallback<FnType>(env, event);
- callback(env,
- jnienv,
- class_being_redefined,
- loader,
- name,
- protection_domain,
- current_len,
- current_class_data,
- &new_len,
- &new_data);
- if (new_data != nullptr && new_data != current_class_data) {
- // Destroy the data the last transformer made. We skip this if the previous state was the
- // initial one since we don't know here which jvmtiEnv allocated it.
- // NB Currently this doesn't matter since all allocations just go to malloc but in the
- // future we might have jvmtiEnv's keep track of their allocations for leak-checking.
- if (last_env != nullptr) {
- last_env->Deallocate(current_class_data);
- }
- last_env = env;
- current_class_data = new_data;
- current_len = new_len;
- }
- }
- }
- if (last_env != nullptr) {
- *new_class_data_len = current_len;
- *new_class_data = current_class_data;
- }
-}
-
-template <typename ...Args>
inline void EventHandler::DispatchEvent(art::Thread* thread,
ArtJvmtiEvent event,
Args... args) const {
- switch (event) {
- case ArtJvmtiEvent::kClassFileLoadHookRetransformable:
- case ArtJvmtiEvent::kClassFileLoadHookNonRetransformable:
- return DispatchClassFileLoadHookEvent(thread, event, args...);
- default:
- return GenericDispatchEvent(thread, event, args...);
- }
-}
-
-// TODO Locking of some type!
-template <typename ...Args>
-inline void EventHandler::GenericDispatchEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- Args... args) const {
using FnType = void(jvmtiEnv*, Args...);
for (ArtJvmTiEnv* env : envs) {
if (ShouldDispatch(event, env, thread)) {
diff --git a/runtime/openjdkjvmti/events.h b/runtime/openjdkjvmti/events.h
index 08a8765..7990141 100644
--- a/runtime/openjdkjvmti/events.h
+++ b/runtime/openjdkjvmti/events.h
@@ -178,15 +178,6 @@
ALWAYS_INLINE
inline void RecalculateGlobalEventMask(ArtJvmtiEvent event);
- template <typename ...Args>
- ALWAYS_INLINE inline void GenericDispatchEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- Args... args) const;
- template <typename ...Args>
- ALWAYS_INLINE inline void DispatchClassFileLoadHookEvent(art::Thread* thread,
- ArtJvmtiEvent event,
- Args... args) const;
-
void HandleEventType(ArtJvmtiEvent event, bool enable);
// List of all JvmTiEnv objects that have been created, in their creation order.
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 28ea267..6af51c4 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -242,12 +242,14 @@
}
}
+// TODO This should handle doing multiple classes at once so we need to do less cleanup when things
+// go wrong.
jvmtiError Redefiner::RedefineClasses(ArtJvmTiEnv* env,
art::Runtime* runtime,
art::Thread* self,
jint class_count,
const jvmtiClassDefinition* definitions,
- /*out*/std::string* error_msg) {
+ std::string* error_msg) {
if (env == nullptr) {
*error_msg = "env was null!";
return ERR(INVALID_ENVIRONMENT);
@@ -261,83 +263,46 @@
*error_msg = "null definitions!";
return ERR(NULL_POINTER);
}
- std::vector<ArtClassDefinition> def_vector;
- def_vector.reserve(class_count);
- for (jint i = 0; i < class_count; i++) {
- ArtClassDefinition def;
- def.dex_len = definitions[i].class_byte_count;
- def.dex_data = MakeJvmtiUniquePtr(env, const_cast<unsigned char*>(definitions[i].class_bytes));
- // We are definitely modified.
- def.modified = true;
- jvmtiError res = Transformer::FillInTransformationData(env, definitions[i].klass, &def);
- if (res != OK) {
- return res;
- }
- def_vector.push_back(std::move(def));
- }
- // Call all the transformation events.
- jvmtiError res = Transformer::RetransformClassesDirect(env,
- self,
- &def_vector);
- if (res != OK) {
- // Something went wrong with transformation!
- return res;
- }
- return RedefineClassesDirect(env, runtime, self, def_vector, error_msg);
-}
-
-jvmtiError Redefiner::RedefineClassesDirect(ArtJvmTiEnv* env,
- art::Runtime* runtime,
- art::Thread* self,
- const std::vector<ArtClassDefinition>& definitions,
- std::string* error_msg) {
- DCHECK(env != nullptr);
- if (definitions.size() == 0) {
- // We don't actually need to do anything. Just return OK.
- return OK;
- }
// Stop JIT for the duration of this redefine since the JIT might concurrently compile a method we
// are going to redefine.
art::jit::ScopedJitSuspend suspend_jit;
// Get shared mutator lock so we can lock all the classes.
art::ScopedObjectAccess soa(self);
std::vector<Redefiner::ClassRedefinition> redefinitions;
- redefinitions.reserve(definitions.size());
+ redefinitions.reserve(class_count);
Redefiner r(runtime, self, error_msg);
- for (const ArtClassDefinition& def : definitions) {
- // Only try to transform classes that have been modified.
- if (def.modified) {
- jvmtiError res = r.AddRedefinition(env, def);
- if (res != OK) {
- return res;
- }
+ for (jint i = 0; i < class_count; i++) {
+ jvmtiError res = r.AddRedefinition(env, definitions[i]);
+ if (res != OK) {
+ return res;
}
}
return r.Run();
}
-jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const ArtClassDefinition& def) {
+jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const jvmtiClassDefinition& def) {
std::string original_dex_location;
jvmtiError ret = OK;
if ((ret = GetClassLocation(env, def.klass, &original_dex_location))) {
*error_msg_ = "Unable to get original dex file location!";
return ret;
}
- char* generic_ptr_unused = nullptr;
- char* signature_ptr = nullptr;
- if ((ret = env->GetClassSignature(def.klass, &signature_ptr, &generic_ptr_unused)) != OK) {
- *error_msg_ = "Unable to get class signature!";
- return ret;
- }
- JvmtiUniquePtr generic_unique_ptr(MakeJvmtiUniquePtr(env, generic_ptr_unused));
- JvmtiUniquePtr signature_unique_ptr(MakeJvmtiUniquePtr(env, signature_ptr));
std::unique_ptr<art::MemMap> map(MoveDataToMemMap(original_dex_location,
- def.dex_len,
- def.dex_data.get(),
+ def.class_byte_count,
+ def.class_bytes,
error_msg_));
std::ostringstream os;
+ char* generic_ptr_unused = nullptr;
+ char* signature_ptr = nullptr;
+ if (env->GetClassSignature(def.klass, &signature_ptr, &generic_ptr_unused) != OK) {
+ *error_msg_ = "A jclass passed in does not seem to be valid";
+ return ERR(INVALID_CLASS);
+ }
+ // These will make sure we deallocate the signature.
+ JvmtiUniquePtr sig_unique_ptr(MakeJvmtiUniquePtr(env, signature_ptr));
+ JvmtiUniquePtr generic_unique_ptr(MakeJvmtiUniquePtr(env, generic_ptr_unused));
if (map.get() == nullptr) {
- os << "Failed to create anonymous mmap for modified dex file of class " << def.name
+ os << "Failed to create anonymous mmap for modified dex file of class " << signature_ptr
<< "in dex file " << original_dex_location << " because: " << *error_msg_;
*error_msg_ = os.str();
return ERR(OUT_OF_MEMORY);
@@ -354,7 +319,7 @@
/*verify_checksum*/true,
error_msg_));
if (dex_file.get() == nullptr) {
- os << "Unable to load modified dex file for " << def.name << ": " << *error_msg_;
+ os << "Unable to load modified dex file for " << signature_ptr << ": " << *error_msg_;
*error_msg_ = os.str();
return ERR(INVALID_CLASS_FORMAT);
}
@@ -1024,16 +989,17 @@
// Performs updates to class that will allow us to verify it.
void Redefiner::ClassRedefinition::UpdateClass(art::ObjPtr<art::mirror::Class> mclass,
art::ObjPtr<art::mirror::DexCache> new_dex_cache) {
- DCHECK_EQ(dex_file_->NumClassDefs(), 1u);
- const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(0);
- UpdateMethods(mclass, new_dex_cache, class_def);
+ const art::DexFile::ClassDef* class_def = art::OatFile::OatDexFile::FindClassDef(
+ *dex_file_, class_sig_.c_str(), art::ComputeModifiedUtf8Hash(class_sig_.c_str()));
+ DCHECK(class_def != nullptr);
+ UpdateMethods(mclass, new_dex_cache, *class_def);
UpdateFields(mclass);
// Update the class fields.
// Need to update class last since the ArtMethod gets its DexFile from the class (which is needed
// to call GetReturnTypeDescriptor and GetParameterTypeList above).
mclass->SetDexCache(new_dex_cache.Ptr());
- mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(class_def));
+ mclass->SetDexClassDefIndex(dex_file_->GetIndexForClassDef(*class_def));
mclass->SetDexTypeIndex(dex_file_->GetIndexForTypeId(*dex_file_->FindTypeId(class_sig_.c_str())));
}
diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h
index f8d51ad..8626bc5 100644
--- a/runtime/openjdkjvmti/ti_redefine.h
+++ b/runtime/openjdkjvmti/ti_redefine.h
@@ -72,25 +72,13 @@
public:
// Redefine the given classes with the given dex data. Note this function does not take ownership
// of the dex_data pointers. It is not used after this call however and may be freed if desired.
- // The caller is responsible for freeing it. The runtime makes its own copy of the data. This
- // function does not call the transformation events.
- // TODO Check modified flag of the definitions.
- static jvmtiError RedefineClassesDirect(ArtJvmTiEnv* env,
- art::Runtime* runtime,
- art::Thread* self,
- const std::vector<ArtClassDefinition>& definitions,
- /*out*/std::string* error_msg);
-
- // Redefine the given classes with the given dex data. Note this function does not take ownership
- // of the dex_data pointers. It is not used after this call however and may be freed if desired.
// The caller is responsible for freeing it. The runtime makes its own copy of the data.
- // TODO This function should call the transformation events.
static jvmtiError RedefineClasses(ArtJvmTiEnv* env,
art::Runtime* runtime,
art::Thread* self,
jint class_count,
const jvmtiClassDefinition* definitions,
- /*out*/std::string* error_msg);
+ std::string* error_msg);
static jvmtiError IsModifiableClass(jvmtiEnv* env, jclass klass, jboolean* is_redefinable);
@@ -221,7 +209,7 @@
redefinitions_(),
error_msg_(error_msg) { }
- jvmtiError AddRedefinition(ArtJvmTiEnv* env, const ArtClassDefinition& def)
+ jvmtiError AddRedefinition(ArtJvmTiEnv* env, const jvmtiClassDefinition& def)
REQUIRES_SHARED(art::Locks::mutator_lock_);
static jvmtiError GetClassRedefinitionError(art::Handle<art::mirror::Class> klass,
diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc
index 2809cb6..f545125 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -38,7 +38,6 @@
#include "class_linker.h"
#include "dex_file.h"
#include "dex_file_types.h"
-#include "events-inl.h"
#include "gc_root-inl.h"
#include "globals.h"
#include "jni_env_ext-inl.h"
@@ -53,76 +52,12 @@
#include "scoped_thread_state_change-inl.h"
#include "stack.h"
#include "thread_list.h"
-#include "ti_redefine.h"
#include "transform.h"
#include "utf.h"
#include "utils/dex_cache_arrays_layout-inl.h"
namespace openjdkjvmti {
-jvmtiError Transformer::RetransformClassesDirect(
- ArtJvmTiEnv* env,
- art::Thread* self,
- /*in-out*/std::vector<ArtClassDefinition>* definitions) {
- for (ArtClassDefinition& def : *definitions) {
- jint new_len = -1;
- unsigned char* new_data = nullptr;
- // Static casts are so that we get the right template initialization for the special event
- // handling code required by the ClassFileLoadHooks.
- gEventHandler.DispatchEvent(self,
- ArtJvmtiEvent::kClassFileLoadHookRetransformable,
- GetJniEnv(env),
- static_cast<jclass>(def.klass),
- static_cast<jobject>(def.loader),
- static_cast<const char*>(def.name.c_str()),
- static_cast<jobject>(def.protection_domain),
- static_cast<jint>(def.dex_len),
- static_cast<const unsigned char*>(def.dex_data.get()),
- static_cast<jint*>(&new_len),
- static_cast<unsigned char**>(&new_data));
- def.SetNewDexData(env, new_len, new_data);
- }
- return OK;
-}
-
-jvmtiError Transformer::RetransformClasses(ArtJvmTiEnv* env,
- art::Runtime* runtime,
- art::Thread* self,
- jint class_count,
- const jclass* classes,
- /*out*/std::string* error_msg) {
- if (env == nullptr) {
- *error_msg = "env was null!";
- return ERR(INVALID_ENVIRONMENT);
- } else if (class_count < 0) {
- *error_msg = "class_count was less then 0";
- return ERR(ILLEGAL_ARGUMENT);
- } else if (class_count == 0) {
- // We don't actually need to do anything. Just return OK.
- return OK;
- } else if (classes == nullptr) {
- *error_msg = "null classes!";
- return ERR(NULL_POINTER);
- }
- // A holder that will Deallocate all the class bytes buffers on destruction.
- std::vector<ArtClassDefinition> definitions;
- jvmtiError res = OK;
- for (jint i = 0; i < class_count; i++) {
- ArtClassDefinition def;
- res = FillInTransformationData(env, classes[i], &def);
- if (res != OK) {
- return res;
- }
- definitions.push_back(std::move(def));
- }
- res = RetransformClassesDirect(env, self, &definitions);
- if (res != OK) {
- return res;
- }
- return Redefiner::RedefineClassesDirect(env, runtime, self, definitions, error_msg);
-}
-
-// TODO Move this somewhere else, ti_class?
jvmtiError GetClassLocation(ArtJvmTiEnv* env, jclass klass, /*out*/std::string* location) {
JNIEnv* jni_env = nullptr;
jint ret = env->art_vm->GetEnv(reinterpret_cast<void**>(&jni_env), JNI_VERSION_1_1);
@@ -138,61 +73,42 @@
return OK;
}
-// TODO Implement this for real once transformed dex data is actually saved.
-jvmtiError Transformer::GetDexDataForRetransformation(ArtJvmTiEnv* env,
- art::Handle<art::mirror::Class> klass,
- /*out*/jint* dex_data_len,
- /*out*/unsigned char** dex_data) {
- // TODO De-quicken the dex file before passing it to the agents.
- LOG(WARNING) << "Dex file is not de-quickened yet! Quickened dex instructions might be present";
- LOG(WARNING) << "Caching of initial dex data is not yet performed! Dex data might have been "
- << "transformed by agent already";
- const art::DexFile& dex = klass->GetDexFile();
- *dex_data_len = static_cast<jint>(dex.Size());
- unsigned char* new_dex_data = nullptr;
- jvmtiError alloc_error = env->Allocate(*dex_data_len, &new_dex_data);
+// TODO Move this function somewhere more appropriate.
+// Gets the data surrounding the given class.
+jvmtiError GetTransformationData(ArtJvmTiEnv* env,
+ jclass klass,
+ /*out*/std::string* location,
+ /*out*/JNIEnv** jni_env_ptr,
+ /*out*/jobject* loader,
+ /*out*/std::string* name,
+ /*out*/jobject* protection_domain,
+ /*out*/jint* data_len,
+ /*out*/unsigned char** dex_data) {
+ jint ret = env->art_vm->GetEnv(reinterpret_cast<void**>(jni_env_ptr), JNI_VERSION_1_1);
+ if (ret != JNI_OK) {
+ // TODO Different error might be better?
+ return ERR(INTERNAL);
+ }
+ JNIEnv* jni_env = *jni_env_ptr;
+ art::ScopedObjectAccess soa(jni_env);
+ art::StackHandleScope<3> hs(art::Thread::Current());
+ art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class>(klass)));
+ *loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader());
+ *name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8();
+ // TODO is this always null?
+ *protection_domain = nullptr;
+ const art::DexFile& dex = hs_klass->GetDexFile();
+ *location = dex.GetLocation();
+ *data_len = static_cast<jint>(dex.Size());
+ // TODO We should maybe change env->Allocate to allow us to mprotect this memory and stop writes.
+ jvmtiError alloc_error = env->Allocate(*data_len, dex_data);
if (alloc_error != OK) {
return alloc_error;
}
// Copy the data into a temporary buffer.
- memcpy(reinterpret_cast<void*>(new_dex_data),
- reinterpret_cast<const void*>(dex.Begin()),
- *dex_data_len);
- *dex_data = new_dex_data;
- return OK;
-}
-
-// TODO Move this function somewhere more appropriate.
-// Gets the data surrounding the given class.
-// TODO Make this less magical.
-jvmtiError Transformer::FillInTransformationData(ArtJvmTiEnv* env,
- jclass klass,
- ArtClassDefinition* def) {
- JNIEnv* jni_env = GetJniEnv(env);
- if (jni_env == nullptr) {
- // TODO Different error might be better?
- return ERR(INTERNAL);
- }
- art::ScopedObjectAccess soa(jni_env);
- art::StackHandleScope<3> hs(art::Thread::Current());
- art::Handle<art::mirror::Class> hs_klass(hs.NewHandle(soa.Decode<art::mirror::Class>(klass)));
- if (hs_klass.IsNull()) {
- return ERR(INVALID_CLASS);
- }
- def->klass = klass;
- def->loader = soa.AddLocalReference<jobject>(hs_klass->GetClassLoader());
- def->name = art::mirror::Class::ComputeName(hs_klass)->ToModifiedUtf8();
- // TODO is this always null?
- def->protection_domain = nullptr;
- if (def->dex_data.get() == nullptr) {
- unsigned char* new_data;
- jvmtiError res = GetDexDataForRetransformation(env, hs_klass, &def->dex_len, &new_data);
- if (res == OK) {
- def->dex_data = MakeJvmtiUniquePtr(env, new_data);
- } else {
- return res;
- }
- }
+ memcpy(reinterpret_cast<void*>(*dex_data),
+ reinterpret_cast<const void*>(dex.Begin()),
+ *data_len);
return OK;
}
diff --git a/runtime/openjdkjvmti/transform.h b/runtime/openjdkjvmti/transform.h
index 0ff2bd1..0ad5099 100644
--- a/runtime/openjdkjvmti/transform.h
+++ b/runtime/openjdkjvmti/transform.h
@@ -43,30 +43,16 @@
jvmtiError GetClassLocation(ArtJvmTiEnv* env, jclass klass, /*out*/std::string* location);
-class Transformer {
- public:
- static jvmtiError RetransformClassesDirect(
- ArtJvmTiEnv* env, art::Thread* self, /*in-out*/std::vector<ArtClassDefinition>* definitions);
-
- static jvmtiError RetransformClasses(ArtJvmTiEnv* env,
- art::Runtime* runtime,
- art::Thread* self,
- jint class_count,
- const jclass* classes,
- /*out*/std::string* error_msg);
-
- // Gets the data surrounding the given class.
- static jvmtiError FillInTransformationData(ArtJvmTiEnv* env,
- jclass klass,
- ArtClassDefinition* def);
-
- private:
- static jvmtiError GetDexDataForRetransformation(ArtJvmTiEnv* env,
- art::Handle<art::mirror::Class> klass,
- /*out*/jint* dex_data_length,
- /*out*/unsigned char** dex_data)
- REQUIRES_SHARED(art::Locks::mutator_lock_);
-};
+// Gets the data surrounding the given class.
+jvmtiError GetTransformationData(ArtJvmTiEnv* env,
+ jclass klass,
+ /*out*/std::string* location,
+ /*out*/JNIEnv** jni_env_ptr,
+ /*out*/jobject* loader,
+ /*out*/std::string* name,
+ /*out*/jobject* protection_domain,
+ /*out*/jint* data_len,
+ /*out*/unsigned char** dex_data);
} // namespace openjdkjvmti