Revert "Revert "Implement RetransformClasses""
This reverts commit 52a2db50b76f2b981d21d5508c3d9e8ab4c5fe93.
Reason for revert: Issue with RedefineClasses was resolved.
Test: ART_TEST_JNI_FORCECOPY=true mma -j40 test-art-host
Change-Id: I06f198df4fb40c48647b358d241710329e0812e9
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 6af51c4..2db8a40 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -242,14 +242,12 @@
}
}
-// 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,
- std::string* error_msg) {
+ /*out*/std::string* error_msg) {
if (env == nullptr) {
*error_msg = "env was null!";
return ERR(INVALID_ENVIRONMENT);
@@ -263,46 +261,95 @@
*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++) {
+ // We make a copy of the class_bytes to pass into the retransformation.
+ // This makes cleanup easier (since we unambiguously own the bytes) and also is useful since we
+ // will need to keep the original bytes around unaltered for subsequent RetransformClasses calls
+ // to get the passed in bytes.
+ // TODO Implement saving the original bytes.
+ unsigned char* class_bytes_copy = nullptr;
+ jvmtiError res = env->Allocate(definitions[i].class_byte_count, &class_bytes_copy);
+ if (res != OK) {
+ return res;
+ }
+ memcpy(class_bytes_copy, definitions[i].class_bytes, definitions[i].class_byte_count);
+
+ ArtClassDefinition def;
+ def.dex_len = definitions[i].class_byte_count;
+ def.dex_data = MakeJvmtiUniquePtr(env, class_bytes_copy);
+ // We are definitely modified.
+ def.modified = true;
+ 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(class_count);
+ redefinitions.reserve(definitions.size());
Redefiner r(runtime, self, error_msg);
- for (jint i = 0; i < class_count; i++) {
- jvmtiError res = r.AddRedefinition(env, definitions[i]);
- if (res != OK) {
- return res;
+ 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;
+ }
}
}
return r.Run();
}
-jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const jvmtiClassDefinition& def) {
+jvmtiError Redefiner::AddRedefinition(ArtJvmTiEnv* env, const ArtClassDefinition& 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;
}
- std::unique_ptr<art::MemMap> map(MoveDataToMemMap(original_dex_location,
- 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);
+ if ((ret = env->GetClassSignature(def.klass, &signature_ptr, &generic_ptr_unused)) != OK) {
+ *error_msg_ = "Unable to get class signature!";
+ return ret;
}
- // 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));
+ 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(),
+ error_msg_));
+ std::ostringstream os;
if (map.get() == nullptr) {
- os << "Failed to create anonymous mmap for modified dex file of class " << signature_ptr
+ os << "Failed to create anonymous mmap for modified dex file of class " << def.name
<< "in dex file " << original_dex_location << " because: " << *error_msg_;
*error_msg_ = os.str();
return ERR(OUT_OF_MEMORY);
@@ -319,7 +366,7 @@
/*verify_checksum*/true,
error_msg_));
if (dex_file.get() == nullptr) {
- os << "Unable to load modified dex file for " << signature_ptr << ": " << *error_msg_;
+ os << "Unable to load modified dex file for " << def.name << ": " << *error_msg_;
*error_msg_ = os.str();
return ERR(INVALID_CLASS_FORMAT);
}
@@ -989,17 +1036,16 @@
// 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) {
- 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);
+ DCHECK_EQ(dex_file_->NumClassDefs(), 1u);
+ const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(0);
+ 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())));
}