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
diff --git a/test/921-hello-failure/expected.txt b/test/921-hello-failure/expected.txt
index 9615e6b..1c1d4d9 100644
--- a/test/921-hello-failure/expected.txt
+++ b/test/921-hello-failure/expected.txt
@@ -21,11 +21,3 @@
Transformation error : java.lang.Exception(Failed to redefine classes <LTransform;, LTransform2;> due to JVMTI_ERROR_NAMES_DONT_MATCH)
hello - MultiRedef
hello2 - MultiRedef
-hello - MultiRetrans
-hello2 - MultiRetrans
-Transformation error : java.lang.Exception(Failed to retransform classes <LTransform2;, LTransform;> due to JVMTI_ERROR_NAMES_DONT_MATCH)
-hello - MultiRetrans
-hello2 - MultiRetrans
-Transformation error : java.lang.Exception(Failed to retransform classes <LTransform;, LTransform2;> due to JVMTI_ERROR_NAMES_DONT_MATCH)
-hello - MultiRetrans
-hello2 - MultiRetrans
diff --git a/test/921-hello-failure/src/Main.java b/test/921-hello-failure/src/Main.java
index 43d6e9e..1fe2599 100644
--- a/test/921-hello-failure/src/Main.java
+++ b/test/921-hello-failure/src/Main.java
@@ -25,7 +25,6 @@
MissingInterface.doTest(new Transform2());
ReorderInterface.doTest(new Transform2());
MultiRedef.doTest(new Transform(), new Transform2());
- MultiRetrans.doTest(new Transform(), new Transform2());
}
// Transforms the class. This throws an exception if something goes wrong.
@@ -48,20 +47,7 @@
dex_files.toArray(new byte[0][]));
}
- public static void addMultiTransformationResults(CommonClassDefinition... defs) throws Exception {
- for (CommonClassDefinition d : defs) {
- addCommonTransformationResult(d.target.getCanonicalName(),
- d.class_file_bytes,
- d.dex_file_bytes);
- }
- }
-
public static native void doCommonMultiClassRedefinition(Class<?>[] targets,
byte[][] classfiles,
byte[][] dexfiles) throws Exception;
- public static native void doCommonClassRetransformation(Class<?>... target) throws Exception;
- public static native void enableCommonRetransformation(boolean enable);
- public static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
}
diff --git a/test/921-hello-failure/src/MultiRetrans.java b/test/921-hello-failure/src/MultiRetrans.java
deleted file mode 100644
index 95aaf07..0000000
--- a/test/921-hello-failure/src/MultiRetrans.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.
- */
-
-import java.util.Base64;
-
-class MultiRetrans {
-
- // class NotTransform {
- // public void sayHi(String name) {
- // throw new Error("Should not be called!");
- // }
- // }
- private static CommonClassDefinition INVALID_DEFINITION_T1 = new CommonClassDefinition(
- Transform.class,
- Base64.getDecoder().decode(
- "yv66vgAAADQAFQoABgAPBwAQCAARCgACABIHABMHABQBAAY8aW5pdD4BAAMoKVYBAARDb2RlAQAP" +
- "TGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VG" +
- "aWxlAQARTm90VHJhbnNmb3JtLmphdmEMAAcACAEAD2phdmEvbGFuZy9FcnJvcgEAFVNob3VsZCBu" +
- "b3QgYmUgY2FsbGVkIQwABwAMAQAMTm90VHJhbnNmb3JtAQAQamF2YS9sYW5nL09iamVjdAAgAAUA" +
- "BgAAAAAAAgAAAAcACAABAAkAAAAdAAEAAQAAAAUqtwABsQAAAAEACgAAAAYAAQAAAAEAAQALAAwA" +
- "AQAJAAAAIgADAAIAAAAKuwACWRIDtwAEvwAAAAEACgAAAAYAAQAAAAMAAQANAAAAAgAO"),
- Base64.getDecoder().decode(
- "ZGV4CjAzNQDLV95i5xnv6iUi6uIeDoY5jP5Xe9NP1AiYAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAL" +
- "AAAAcAAAAAUAAACcAAAAAgAAALAAAAAAAAAAAAAAAAQAAADIAAAAAQAAAOgAAACQAQAACAEAAEoB" +
- "AABSAQAAYgEAAHUBAACJAQAAnQEAALABAADHAQAAygEAAM4BAADiAQAAAQAAAAIAAAADAAAABAAA" +
- "AAcAAAAHAAAABAAAAAAAAAAIAAAABAAAAEQBAAAAAAAAAAAAAAAAAQAKAAAAAQABAAAAAAACAAAA" +
- "AAAAAAAAAAAAAAAAAgAAAAAAAAAFAAAAAAAAAPQBAAAAAAAAAQABAAEAAADpAQAABAAAAHAQAwAA" +
- "AA4ABAACAAIAAADuAQAACQAAACIAAQAbAQYAAABwIAIAEAAnAAAAAQAAAAMABjxpbml0PgAOTE5v" +
- "dFRyYW5zZm9ybTsAEUxqYXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZh" +
- "L2xhbmcvU3RyaW5nOwARTm90VHJhbnNmb3JtLmphdmEAFVNob3VsZCBub3QgYmUgY2FsbGVkIQAB" +
- "VgACVkwAEmVtaXR0ZXI6IGphY2stNC4yMAAFc2F5SGkAAQAHDgADAQAHDgAAAAEBAICABIgCAQGg" +
- "AgAADAAAAAAAAAABAAAAAAAAAAEAAAALAAAAcAAAAAIAAAAFAAAAnAAAAAMAAAACAAAAsAAAAAUA" +
- "AAAEAAAAyAAAAAYAAAABAAAA6AAAAAEgAAACAAAACAEAAAEQAAABAAAARAEAAAIgAAALAAAASgEA" +
- "AAMgAAACAAAA6QEAAAAgAAABAAAA9AEAAAAQAAABAAAABAIAAA=="));
-
- // Valid redefinition of Transform2
- // class Transform2 implements Iface1, Iface2 {
- // public void sayHi(String name) {
- // throw new Error("Should not be called!");
- // }
- // }
- private static CommonClassDefinition VALID_DEFINITION_T2 = new CommonClassDefinition(
- Transform2.class,
- Base64.getDecoder().decode(
- "yv66vgAAADQAGQoABgARBwASCAATCgACABQHABUHABYHABcHABgBAAY8aW5pdD4BAAMoKVYBAARD" +
- "b2RlAQAPTGluZU51bWJlclRhYmxlAQAFc2F5SGkBABUoTGphdmEvbGFuZy9TdHJpbmc7KVYBAApT" +
- "b3VyY2VGaWxlAQAPVHJhbnNmb3JtMi5qYXZhDAAJAAoBAA9qYXZhL2xhbmcvRXJyb3IBABVTaG91" +
- "bGQgbm90IGJlIGNhbGxlZCEMAAkADgEAClRyYW5zZm9ybTIBABBqYXZhL2xhbmcvT2JqZWN0AQAG" +
- "SWZhY2UxAQAGSWZhY2UyACAABQAGAAIABwAIAAAAAgAAAAkACgABAAsAAAAdAAEAAQAAAAUqtwAB" +
- "sQAAAAEADAAAAAYAAQAAAAEAAQANAA4AAQALAAAAIgADAAIAAAAKuwACWRIDtwAEvwAAAAEADAAA" +
- "AAYAAQAAAAMAAQAPAAAAAgAQ"),
- Base64.getDecoder().decode(
- "ZGV4CjAzNQDSWls05CPkX+gbTGMVRvx9dc9vozzVbu7AAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAN" +
- "AAAAcAAAAAcAAACkAAAAAgAAAMAAAAAAAAAAAAAAAAQAAADYAAAAAQAAAPgAAACoAQAAGAEAAGIB" +
- "AABqAQAAdAEAAH4BAACMAQAAnwEAALMBAADHAQAA3gEAAO8BAADyAQAA9gEAAAoCAAABAAAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAJAAAACQAAAAYAAAAAAAAACgAAAAYAAABcAQAAAgAAAAAAAAACAAEA" +
- "DAAAAAMAAQAAAAAABAAAAAAAAAACAAAAAAAAAAQAAABUAQAACAAAAAAAAAAcAgAAAAAAAAEAAQAB" +
- "AAAAEQIAAAQAAABwEAMAAAAOAAQAAgACAAAAFgIAAAkAAAAiAAMAGwEHAAAAcCACABAAJwAAAAIA" +
- "AAAAAAEAAQAAAAUABjxpbml0PgAITElmYWNlMTsACExJZmFjZTI7AAxMVHJhbnNmb3JtMjsAEUxq" +
- "YXZhL2xhbmcvRXJyb3I7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAV" +
- "U2hvdWxkIG5vdCBiZSBjYWxsZWQhAA9UcmFuc2Zvcm0yLmphdmEAAVYAAlZMABJlbWl0dGVyOiBq" +
- "YWNrLTQuMjAABXNheUhpAAEABw4AAwEABw4AAAABAQCAgASYAgEBsAIAAAwAAAAAAAAAAQAAAAAA" +
- "AAABAAAADQAAAHAAAAACAAAABwAAAKQAAAADAAAAAgAAAMAAAAAFAAAABAAAANgAAAAGAAAAAQAA" +
- "APgAAAABIAAAAgAAABgBAAABEAAAAgAAAFQBAAACIAAADQAAAGIBAAADIAAAAgAAABECAAAAIAAA" +
- "AQAAABwCAAAAEAAAAQAAACwCAAA="));
-
- public static void doTest(Transform t1, Transform2 t2) {
- t1.sayHi("MultiRetrans");
- t2.sayHi("MultiRetrans");
- try {
- Main.addMultiTransformationResults(VALID_DEFINITION_T2, INVALID_DEFINITION_T1);
- Main.enableCommonRetransformation(true);
- Main.doCommonClassRetransformation(Transform2.class, Transform.class);
- } catch (Exception e) {
- System.out.println(
- "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
- } finally {
- Main.enableCommonRetransformation(false);
- }
- t1.sayHi("MultiRetrans");
- t2.sayHi("MultiRetrans");
- try {
- Main.addMultiTransformationResults(VALID_DEFINITION_T2, INVALID_DEFINITION_T1);
- Main.enableCommonRetransformation(true);
- Main.doCommonClassRetransformation(Transform.class, Transform2.class);
- } catch (Exception e) {
- System.out.println(
- "Transformation error : " + e.getClass().getName() + "(" + e.getMessage() + ")");
- } finally {
- Main.enableCommonRetransformation(false);
- }
- t1.sayHi("MultiRetrans");
- t2.sayHi("MultiRetrans");
- }
-}
diff --git a/test/930-hello-retransform/build b/test/930-hello-retransform/build
deleted file mode 100755
index 898e2e5..0000000
--- a/test/930-hello-retransform/build
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/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-build "$@" --experimental agents
diff --git a/test/930-hello-retransform/expected.txt b/test/930-hello-retransform/expected.txt
deleted file mode 100644
index 4774b81..0000000
--- a/test/930-hello-retransform/expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-hello
-Goodbye
diff --git a/test/930-hello-retransform/info.txt b/test/930-hello-retransform/info.txt
deleted file mode 100644
index 875a5f6..0000000
--- a/test/930-hello-retransform/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Tests basic functions in the jvmti plugin.
diff --git a/test/930-hello-retransform/run b/test/930-hello-retransform/run
deleted file mode 100755
index 4379349..0000000
--- a/test/930-hello-retransform/run
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/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 "$@" --experimental agents \
- --experimental runtime-plugins \
- --jvmti
diff --git a/test/930-hello-retransform/src/Main.java b/test/930-hello-retransform/src/Main.java
deleted file mode 100644
index 12194c3..0000000
--- a/test/930-hello-retransform/src/Main.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.
- */
-
-import java.util.Base64;
-public class Main {
-
- /**
- * base64 encoded class/dex file for
- * class Transform {
- * public void sayHi() {
- * System.out.println("Goodbye");
- * }
- * }
- */
- private static final byte[] CLASS_BYTES = Base64.getDecoder().decode(
- "yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUB" +
- "AA9MaW5lTnVtYmVyVGFibGUBAAVzYXlIaQEAClNvdXJjZUZpbGUBAA5UcmFuc2Zvcm0uamF2YQwA" +
- "BwAIBwAWDAAXABgBAAdHb29kYnllBwAZDAAaABsBAAlUcmFuc2Zvcm0BABBqYXZhL2xhbmcvT2Jq" +
- "ZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2ph" +
- "dmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACAABQAG" +
- "AAAAAAACAAAABwAIAAEACQAAAB0AAQABAAAABSq3AAGxAAAAAQAKAAAABgABAAAAEQABAAsACAAB" +
- "AAkAAAAlAAIAAQAAAAmyAAISA7YABLEAAAABAAoAAAAKAAIAAAATAAgAFAABAAwAAAACAA0=");
- private static final byte[] DEX_BYTES = Base64.getDecoder().decode(
- "ZGV4CjAzNQCLXSBQ5FiS3f16krSYZFF8xYZtFVp0GRXMAgAAcAAAAHhWNBIAAAAAAAAAACwCAAAO" +
- "AAAAcAAAAAYAAACoAAAAAgAAAMAAAAABAAAA2AAAAAQAAADgAAAAAQAAAAABAACsAQAAIAEAAGIB" +
- "AABqAQAAcwEAAIABAACXAQAAqwEAAL8BAADTAQAA4wEAAOYBAADqAQAA/gEAAAMCAAAMAgAAAgAA" +
- "AAMAAAAEAAAABQAAAAYAAAAIAAAACAAAAAUAAAAAAAAACQAAAAUAAABcAQAABAABAAsAAAAAAAAA" +
- "AAAAAAAAAAANAAAAAQABAAwAAAACAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAHAAAAAAAAAB4CAAAA" +
- "AAAAAQABAAEAAAATAgAABAAAAHAQAwAAAA4AAwABAAIAAAAYAgAACQAAAGIAAAAbAQEAAABuIAIA" +
- "EAAOAAAAAQAAAAMABjxpbml0PgAHR29vZGJ5ZQALTFRyYW5zZm9ybTsAFUxqYXZhL2lvL1ByaW50" +
- "U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xh" +
- "bmcvU3lzdGVtOwAOVHJhbnNmb3JtLmphdmEAAVYAAlZMABJlbWl0dGVyOiBqYWNrLTMuMzYAA291" +
- "dAAHcHJpbnRsbgAFc2F5SGkAEQAHDgATAAcOhQAAAAEBAICABKACAQG4Ag0AAAAAAAAAAQAAAAAA" +
- "AAABAAAADgAAAHAAAAACAAAABgAAAKgAAAADAAAAAgAAAMAAAAAEAAAAAQAAANgAAAAFAAAABAAA" +
- "AOAAAAAGAAAAAQAAAAABAAABIAAAAgAAACABAAABEAAAAQAAAFwBAAACIAAADgAAAGIBAAADIAAA" +
- "AgAAABMCAAAAIAAAAQAAAB4CAAAAEAAAAQAAACwCAAA=");
-
- public static void main(String[] args) {
- System.loadLibrary(args[1]);
- doTest(new Transform());
- }
-
- public static void doTest(Transform t) {
- t.sayHi();
- addCommonTransformationResult("Transform", CLASS_BYTES, DEX_BYTES);
- enableCommonRetransformation(true);
- doCommonClassRetransformation(Transform.class);
- t.sayHi();
- }
-
- // Transforms the class
- private static native void doCommonClassRetransformation(Class<?>... target);
- private static native void enableCommonRetransformation(boolean enable);
- private static native void addCommonTransformationResult(String target_name,
- byte[] class_bytes,
- byte[] dex_bytes);
-}
diff --git a/test/930-hello-retransform/src/Transform.java b/test/930-hello-retransform/src/Transform.java
deleted file mode 100644
index 8e8af35..0000000
--- a/test/930-hello-retransform/src/Transform.java
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.
- */
-
-class Transform {
- public void sayHi() {
- // Use lower 'h' to make sure the string will have a different string id
- // than the transformation (the transformation code is the same except
- // the actual printed String, which was making the test inacurately passing
- // in JIT mode when loading the string from the dex cache, as the string ids
- // of the two different strings were the same).
- // We know the string ids will be different because lexicographically:
- // "Goodbye" < "LTransform;" < "hello".
- System.out.println("hello");
- }
-}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 38b88e4..e604c93 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -309,7 +309,6 @@
927-timers \
928-jni-table \
929-search \
- 930-hello-retransform \
ifneq (,$(filter target,$(TARGET_TYPES)))
ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,target,$(RUN_TYPES),$(PREBUILD_TYPES), \
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index 8799c91..2c6d3ed 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -18,7 +18,6 @@
#include <stdio.h>
#include <sstream>
-#include <deque>
#include "art_method.h"
#include "jni.h"
@@ -61,17 +60,17 @@
return true;
}
+namespace common_redefine {
-template <bool is_redefine>
-static void throwCommonRedefinitionError(jvmtiEnv* jvmti,
- JNIEnv* env,
- jint num_targets,
- jclass* target,
- jvmtiError res) {
+static void throwRedefinitionError(jvmtiEnv* jvmti,
+ JNIEnv* env,
+ jint num_targets,
+ jclass* target,
+ jvmtiError res) {
std::stringstream err;
char* error = nullptr;
jvmti->GetErrorName(res, &error);
- err << "Failed to " << (is_redefine ? "redefine" : "retransform") << " class";
+ err << "Failed to redefine class";
if (num_targets > 1) {
err << "es";
}
@@ -93,16 +92,6 @@
env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
}
-namespace common_redefine {
-
-static void throwRedefinitionError(jvmtiEnv* jvmti,
- JNIEnv* env,
- jint num_targets,
- jclass* target,
- jvmtiError res) {
- return throwCommonRedefinitionError<true>(jvmti, env, num_targets, target, res);
-}
-
static void DoMultiClassRedefine(jvmtiEnv* jvmti_env,
JNIEnv* env,
jint num_redefines,
@@ -172,138 +161,7 @@
dex_files.data());
}
-// Get all capabilities except those related to retransformation.
-jint OnLoad(JavaVM* vm,
- char* options ATTRIBUTE_UNUSED,
- void* reserved ATTRIBUTE_UNUSED) {
- if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
- printf("Unable to get jvmti env!\n");
- return 1;
- }
- jvmtiCapabilities caps;
- jvmti_env->GetPotentialCapabilities(&caps);
- caps.can_retransform_classes = 0;
- caps.can_retransform_any_class = 0;
- jvmti_env->AddCapabilities(&caps);
- return 0;
-}
-
-} // namespace common_redefine
-
-namespace common_retransform {
-
-struct CommonTransformationResult {
- std::vector<unsigned char> class_bytes;
- std::vector<unsigned char> dex_bytes;
-
- CommonTransformationResult(size_t class_size, size_t dex_size)
- : class_bytes(class_size), dex_bytes(dex_size) {}
-
- CommonTransformationResult() = default;
- CommonTransformationResult(CommonTransformationResult&&) = default;
- CommonTransformationResult(CommonTransformationResult&) = default;
-};
-
-// Map from class name to transformation result.
-std::map<std::string, std::deque<CommonTransformationResult>> gTransformations;
-
-extern "C" JNIEXPORT void JNICALL Java_Main_addCommonTransformationResult(JNIEnv* env,
- jclass,
- jstring class_name,
- jbyteArray class_array,
- jbyteArray dex_array) {
- const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
- std::string name_str(name_chrs);
- env->ReleaseStringUTFChars(class_name, name_chrs);
- CommonTransformationResult trans(env->GetArrayLength(class_array),
- env->GetArrayLength(dex_array));
- if (env->ExceptionOccurred()) {
- return;
- }
- env->GetByteArrayRegion(class_array,
- 0,
- env->GetArrayLength(class_array),
- reinterpret_cast<jbyte*>(trans.class_bytes.data()));
- if (env->ExceptionOccurred()) {
- return;
- }
- env->GetByteArrayRegion(dex_array,
- 0,
- env->GetArrayLength(dex_array),
- reinterpret_cast<jbyte*>(trans.dex_bytes.data()));
- if (env->ExceptionOccurred()) {
- return;
- }
- if (gTransformations.find(name_str) == gTransformations.end()) {
- std::deque<CommonTransformationResult> list;
- gTransformations[name_str] = std::move(list);
- }
- gTransformations[name_str].push_back(std::move(trans));
-}
-
-// The hook we are using.
-void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env,
- JNIEnv* jni_env ATTRIBUTE_UNUSED,
- jclass class_being_redefined ATTRIBUTE_UNUSED,
- jobject loader ATTRIBUTE_UNUSED,
- const char* name,
- jobject protection_domain ATTRIBUTE_UNUSED,
- jint class_data_len ATTRIBUTE_UNUSED,
- const unsigned char* class_dat ATTRIBUTE_UNUSED,
- jint* new_class_data_len,
- unsigned char** new_class_data) {
- std::string name_str(name);
- if (gTransformations.find(name_str) != gTransformations.end()) {
- CommonTransformationResult& res = gTransformations[name_str][0];
- const std::vector<unsigned char>& desired_array = IsJVM() ? res.class_bytes : res.dex_bytes;
- unsigned char* new_data;
- jvmti_env->Allocate(desired_array.size(), &new_data);
- memcpy(new_data, desired_array.data(), desired_array.size());
- *new_class_data = new_data;
- *new_class_data_len = desired_array.size();
- gTransformations[name_str].pop_front();
- }
-}
-
-extern "C" JNIEXPORT void Java_Main_enableCommonRetransformation(JNIEnv* env,
- jclass,
- jboolean enable) {
- jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
- JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
- nullptr);
- if (res != JVMTI_ERROR_NONE) {
- JvmtiErrorToException(env, res);
- }
-}
-
-static void throwRetransformationError(jvmtiEnv* jvmti,
- JNIEnv* env,
- jint num_targets,
- jclass* targets,
- jvmtiError res) {
- return throwCommonRedefinitionError<false>(jvmti, env, num_targets, targets, res);
-}
-
-static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArray targets) {
- std::vector<jclass> classes;
- jint len = env->GetArrayLength(targets);
- for (jint i = 0; i < len; i++) {
- classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
- }
- jvmtiError res = jvmti_env->RetransformClasses(len, classes.data());
- if (res != JVMTI_ERROR_NONE) {
- throwRetransformationError(jvmti_env, env, len, classes.data(), res);
- }
-}
-
-// TODO Write something useful.
-extern "C" JNIEXPORT void JNICALL Java_Main_doCommonClassRetransformation(JNIEnv* env,
- jclass,
- jobjectArray targets) {
- DoClassRetransformation(jvmti_env, env, targets);
-}
-
-// Get all capabilities except those related to retransformation.
+// Don't do anything
jint OnLoad(JavaVM* vm,
char* options ATTRIBUTE_UNUSED,
void* reserved ATTRIBUTE_UNUSED) {
@@ -312,16 +170,9 @@
return 1;
}
SetAllCapabilities(jvmti_env);
- jvmtiEventCallbacks cb;
- memset(&cb, 0, sizeof(cb));
- cb.ClassFileLoadHook = CommonClassFileLoadHookRetransformable;
- if (jvmti_env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
- printf("Unable to set class file load hook cb!\n");
- return 1;
- }
return 0;
}
-} // namespace common_retransform
+} // namespace common_redefine
} // namespace art
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
index 8599fc4..642ca03 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -27,10 +27,6 @@
jint OnLoad(JavaVM* vm, char* options, void* reserved);
} // namespace common_redefine
-namespace common_retransform {
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-} // namespace common_retransform
-
extern bool RuntimeIsJVM;
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index 1b11442..521e672 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -64,9 +64,8 @@
{ "916-obsolete-jit", common_redefine::OnLoad, nullptr },
{ "917-fields-transformation", common_redefine::OnLoad, nullptr },
{ "919-obsolete-fields", common_redefine::OnLoad, nullptr },
- { "921-hello-failure", common_retransform::OnLoad, nullptr },
+ { "921-hello-failure", common_redefine::OnLoad, nullptr },
{ "926-multi-obsolescence", common_redefine::OnLoad, nullptr },
- { "930-hello-retransform", common_retransform::OnLoad, nullptr },
};
static AgentLib* FindAgent(char* name) {