Rename a couple of methods related to redefinition for readability
TransformClasses is a method to actually redefine the method and
TransformClassesDirect is a method to call ClassFileLoadHooks which is
confusing. So rename TransformClassesDirect to CallClassFileLoadHooks
and also add some comments
Also rename GetRedefinitionError to CanRedefineClass.
Test: art/test.py
Change-Id: Ie04927f1aae2880d87bcb9bb19b5f3971911fd43
diff --git a/openjdkjvmti/ti_class.cc b/openjdkjvmti/ti_class.cc
index 7ded350..5581bc2 100644
--- a/openjdkjvmti/ti_class.cc
+++ b/openjdkjvmti/ti_class.cc
@@ -192,8 +192,8 @@
def.InitFirstLoad(descriptor, class_loader, initial_dex_file);
// Call all non-retransformable agents.
- Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
- event_handler, self, &def);
+ Transformer::CallClassFileLoadHooksSingleClass<
+ ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(event_handler, self, &def);
std::vector<unsigned char> post_non_retransform;
if (def.IsModified()) {
@@ -203,11 +203,11 @@
}
// Call all structural transformation agents.
- Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
+ Transformer::CallClassFileLoadHooksSingleClass<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
event_handler, self, &def);
// Call all retransformable agents.
- Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
- event_handler, self, &def);
+ Transformer::CallClassFileLoadHooksSingleClass<
+ ArtJvmtiEvent::kClassFileLoadHookRetransformable>(event_handler, self, &def);
if (def.IsModified()) {
VLOG(class_linker) << "Changing class " << descriptor;
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index c9efee6..8ffdb8e 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -378,7 +378,7 @@
art::Handle<art::mirror::Class> h_klass(hs.NewHandle(obj->AsClass()));
std::string err_unused;
*is_redefinable =
- Redefiner::GetClassRedefinitionError<kType>(h_klass, &err_unused) != ERR(UNMODIFIABLE_CLASS)
+ Redefiner::CanRedefineClass<kType>(h_klass, &err_unused) != ERR(UNMODIFIABLE_CLASS)
? JNI_TRUE
: JNI_FALSE;
return OK;
@@ -395,7 +395,7 @@
}
template <RedefinitionType kType>
-jvmtiError Redefiner::GetClassRedefinitionError(jclass klass, /*out*/ std::string* error_msg) {
+jvmtiError Redefiner::CanRedefineClass(jclass klass, /*out*/ std::string* error_msg) {
art::Thread* self = art::Thread::Current();
art::ScopedObjectAccess soa(self);
art::StackHandleScope<1> hs(self);
@@ -404,12 +404,12 @@
return ERR(INVALID_CLASS);
}
art::Handle<art::mirror::Class> h_klass(hs.NewHandle(obj->AsClass()));
- return Redefiner::GetClassRedefinitionError<kType>(h_klass, error_msg);
+ return Redefiner::CanRedefineClass<kType>(h_klass, error_msg);
}
template <RedefinitionType kType>
-jvmtiError Redefiner::GetClassRedefinitionError(art::Handle<art::mirror::Class> klass,
- /*out*/ std::string* error_msg) {
+jvmtiError Redefiner::CanRedefineClass(art::Handle<art::mirror::Class> klass,
+ /*out*/ std::string* error_msg) {
art::Thread* self = art::Thread::Current();
if (!klass->IsResolved()) {
// It's only a problem to try to retransform/redefine a unprepared class if it's happening on
@@ -526,9 +526,9 @@
return OK;
}
-template jvmtiError Redefiner::GetClassRedefinitionError<RedefinitionType::kNormal>(
+template jvmtiError Redefiner::CanRedefineClass<RedefinitionType::kNormal>(
art::Handle<art::mirror::Class> klass, /*out*/ std::string* error_msg);
-template jvmtiError Redefiner::GetClassRedefinitionError<RedefinitionType::kStructural>(
+template jvmtiError Redefiner::CanRedefineClass<RedefinitionType::kStructural>(
art::Handle<art::mirror::Class> klass, /*out*/ std::string* error_msg);
// Moves dex data to an anonymous, read-only mmap'd region.
@@ -604,8 +604,8 @@
std::vector<ArtClassDefinition> def_vector;
def_vector.reserve(class_count);
for (jint i = 0; i < class_count; i++) {
- jvmtiError res = Redefiner::GetClassRedefinitionError<RedefinitionType::kNormal>(
- definitions[i].klass, &error_msg);
+ jvmtiError res =
+ Redefiner::CanRedefineClass<RedefinitionType::kNormal>(definitions[i].klass, &error_msg);
if (res != OK) {
JVMTI_LOG(WARNING, env) << "FAILURE TO REDEFINE " << error_msg;
return res;
@@ -618,11 +618,12 @@
}
def_vector.push_back(std::move(def));
}
- // Call all the transformation events.
- Transformer::RetransformClassesDirect<kType>(self, &def_vector);
- if (kType == RedefinitionType::kStructural) {
- Transformer::RetransformClassesDirect<RedefinitionType::kNormal>(self, &def_vector);
- }
+
+ // Call necessary hooks. According to the spec we should send class file load hooks here. We
+ // handle it slightly differently to support structural redefinition. Look at the comments
+ // in Transformer::CallClassFileLoadHooks for more details.
+ Transformer::CallClassFileLoadHooks<kType>(self, &def_vector);
+
jvmtiError res = RedefineClassesDirect(env, runtime, self, def_vector, kType, &error_msg);
if (res != OK) {
JVMTI_LOG(WARNING, env) << "FAILURE TO REDEFINE " << error_msg;
@@ -1155,9 +1156,9 @@
art::Handle<art::mirror::Class> h_klass(hs.NewHandle(GetMirrorClass()));
jvmtiError res;
if (driver_->type_ == RedefinitionType::kStructural && this->IsStructuralRedefinition()) {
- res = Redefiner::GetClassRedefinitionError<RedefinitionType::kStructural>(h_klass, &err);
+ res = Redefiner::CanRedefineClass<RedefinitionType::kStructural>(h_klass, &err);
} else {
- res = Redefiner::GetClassRedefinitionError<RedefinitionType::kNormal>(h_klass, &err);
+ res = Redefiner::CanRedefineClass<RedefinitionType::kNormal>(h_klass, &err);
}
if (res != OK) {
RecordFailure(res, err);
diff --git a/openjdkjvmti/ti_redefine.h b/openjdkjvmti/ti_redefine.h
index 8c2965b..46b50fa 100644
--- a/openjdkjvmti/ti_redefine.h
+++ b/openjdkjvmti/ti_redefine.h
@@ -103,8 +103,8 @@
std::string* error_msg);
// Helper for checking if redefinition/retransformation is allowed.
- template<RedefinitionType kType = RedefinitionType::kNormal>
- static jvmtiError GetClassRedefinitionError(jclass klass, /*out*/std::string* error_msg)
+ template <RedefinitionType kType = RedefinitionType::kNormal>
+ static jvmtiError CanRedefineClass(jclass klass, /*out*/ std::string* error_msg)
REQUIRES(!art::Locks::mutator_lock_);
static jvmtiError StructurallyRedefineClassDirect(jvmtiEnv* env,
@@ -322,9 +322,9 @@
template<RedefinitionType kType = RedefinitionType::kNormal>
static jvmtiError IsModifiableClassGeneric(jvmtiEnv* env, jclass klass, jboolean* is_redefinable);
- template<RedefinitionType kType = RedefinitionType::kNormal>
- static jvmtiError GetClassRedefinitionError(art::Handle<art::mirror::Class> klass,
- /*out*/std::string* error_msg)
+ template <RedefinitionType kType = RedefinitionType::kNormal>
+ static jvmtiError CanRedefineClass(art::Handle<art::mirror::Class> klass,
+ /*out*/ std::string* error_msg)
REQUIRES_SHARED(art::Locks::mutator_lock_);
jvmtiError Run() REQUIRES_SHARED(art::Locks::mutator_lock_);
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc
index bccdcb1..d3448d9 100644
--- a/openjdkjvmti/transform.cc
+++ b/openjdkjvmti/transform.cc
@@ -76,20 +76,23 @@
}
// Initialize templates.
-template
-void Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(
- EventHandler* event_handler, art::Thread* self, /*in-out*/ArtClassDefinition* def);
-template
-void Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
- EventHandler* event_handler, art::Thread* self, /*in-out*/ArtClassDefinition* def);
-template
-void Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
- EventHandler* event_handler, art::Thread* self, /*in-out*/ArtClassDefinition* def);
+template void Transformer::CallClassFileLoadHooksSingleClass<
+ ArtJvmtiEvent::kClassFileLoadHookNonRetransformable>(EventHandler* event_handler,
+ art::Thread* self,
+ /*in-out*/ ArtClassDefinition* def);
+template void Transformer::CallClassFileLoadHooksSingleClass<
+ ArtJvmtiEvent::kClassFileLoadHookRetransformable>(EventHandler* event_handler,
+ art::Thread* self,
+ /*in-out*/ ArtClassDefinition* def);
+template void Transformer::CallClassFileLoadHooksSingleClass<
+ ArtJvmtiEvent::kStructuralDexFileLoadHook>(EventHandler* event_handler,
+ art::Thread* self,
+ /*in-out*/ ArtClassDefinition* def);
-template<ArtJvmtiEvent kEvent>
-void Transformer::TransformSingleClassDirect(EventHandler* event_handler,
- art::Thread* self,
- /*in-out*/ArtClassDefinition* def) {
+template <ArtJvmtiEvent kEvent>
+void Transformer::CallClassFileLoadHooksSingleClass(EventHandler* event_handler,
+ art::Thread* self,
+ /*in-out*/ ArtClassDefinition* def) {
static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable ||
kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable ||
kEvent == ArtJvmtiEvent::kStructuralDexFileLoadHook,
@@ -115,21 +118,41 @@
}
template <RedefinitionType kType>
-void Transformer::RetransformClassesDirect(
- art::Thread* self,
- /*in-out*/ std::vector<ArtClassDefinition>* definitions) {
- constexpr ArtJvmtiEvent kEvent = kType == RedefinitionType::kNormal
- ? ArtJvmtiEvent::kClassFileLoadHookRetransformable
- : ArtJvmtiEvent::kStructuralDexFileLoadHook;
- for (ArtClassDefinition& def : *definitions) {
- TransformSingleClassDirect<kEvent>(gEventHandler, self, &def);
+void Transformer::CallClassFileLoadHooks(art::Thread* self,
+ /*in-out*/ std::vector<ArtClassDefinition>* definitions) {
+ if (kType == RedefinitionType::kNormal) {
+ // For normal redefinition we have to call ClassFileLoadHook according to the spec. We use an
+ // internal event "ClassFileLoadHookRetransformable" for agents that can redefine and a
+ // "ClassFileLoadHookNonRetransformable" for agents that cannot redefine. When an agent is
+ // attached to a non-debuggable environment, we cannot redefine any classes. Splitting the
+ // ClassFileLoadHooks allows us to differentiate between these two cases. This method is only
+ // called when redefinition is allowed so just run ClassFileLoadHookRetransformable hooks.
+ for (ArtClassDefinition& def : *definitions) {
+ CallClassFileLoadHooksSingleClass<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+ gEventHandler, self, &def);
+ }
+ } else {
+ // For structural redefinition we call StructualDexFileLoadHook in addition to the
+ // ClassFileLoadHooks. This let's us specify if structural modifications are allowed.
+ // TODO(mythria): The spec only specifies we need to call ClassFileLoadHooks, the
+ // StructuralDexFileLoadHooks is internal to ART. It is not clear if we need to run all
+ // StructuralDexFileHooks before ClassFileLoadHooks. Doing it this way to keep the existing
+ // behaviour.
+ for (ArtClassDefinition& def : *definitions) {
+ CallClassFileLoadHooksSingleClass<ArtJvmtiEvent::kStructuralDexFileLoadHook>(
+ gEventHandler, self, &def);
+ }
+ for (ArtClassDefinition& def : *definitions) {
+ CallClassFileLoadHooksSingleClass<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+ gEventHandler, self, &def);
+ }
}
}
-template void Transformer::RetransformClassesDirect<RedefinitionType::kNormal>(
- art::Thread* self, /*in-out*/std::vector<ArtClassDefinition>* definitions);
-template void Transformer::RetransformClassesDirect<RedefinitionType::kStructural>(
- art::Thread* self, /*in-out*/std::vector<ArtClassDefinition>* definitions);
+template void Transformer::CallClassFileLoadHooks<RedefinitionType::kNormal>(
+ art::Thread* self, /*in-out*/ std::vector<ArtClassDefinition>* definitions);
+template void Transformer::CallClassFileLoadHooks<RedefinitionType::kStructural>(
+ art::Thread* self, /*in-out*/ std::vector<ArtClassDefinition>* definitions);
jvmtiError Transformer::RetransformClasses(jvmtiEnv* env,
jint class_count,
@@ -151,7 +174,7 @@
std::vector<ArtClassDefinition> definitions;
jvmtiError res = OK;
for (jint i = 0; i < class_count; i++) {
- res = Redefiner::GetClassRedefinitionError<RedefinitionType::kNormal>(classes[i], &error_msg);
+ res = Redefiner::CanRedefineClass<RedefinitionType::kNormal>(classes[i], &error_msg);
if (res != OK) {
JVMTI_LOG(WARNING, env) << "FAILURE TO RETRANSFORM " << error_msg;
return res;
@@ -164,8 +187,8 @@
}
definitions.push_back(std::move(def));
}
- RetransformClassesDirect<RedefinitionType::kStructural>(self, &definitions);
- RetransformClassesDirect<RedefinitionType::kNormal>(self, &definitions);
+
+ CallClassFileLoadHooks<RedefinitionType::kStructural>(self, &definitions);
RedefinitionType redef_type =
std::any_of(definitions.cbegin(),
definitions.cend(),
diff --git a/openjdkjvmti/transform.h b/openjdkjvmti/transform.h
index a58b50e..3b7f855 100644
--- a/openjdkjvmti/transform.h
+++ b/openjdkjvmti/transform.h
@@ -51,16 +51,14 @@
public:
static void Register(EventHandler* eh);
- template<ArtJvmtiEvent kEvent>
- static void TransformSingleClassDirect(
- EventHandler* event_handler,
- art::Thread* self,
- /*in-out*/ArtClassDefinition* def);
+ template <ArtJvmtiEvent kEvent>
+ static void CallClassFileLoadHooksSingleClass(EventHandler* event_handler,
+ art::Thread* self,
+ /*in-out*/ ArtClassDefinition* def);
- template<RedefinitionType kType>
- static void RetransformClassesDirect(
- art::Thread* self,
- /*in-out*/std::vector<ArtClassDefinition>* definitions);
+ template <RedefinitionType kType>
+ static void CallClassFileLoadHooks(art::Thread* self,
+ /*in-out*/ std::vector<ArtClassDefinition>* definitions);
static jvmtiError RetransformClasses(jvmtiEnv* env,
jint class_count,