diff options
author | 2019-10-15 15:46:07 -0700 | |
---|---|---|
committer | 2019-10-30 16:53:25 -0700 | |
commit | d55b844e39c4d5eb1a56de6cb95c891659f8a27f (patch) | |
tree | ed2f7809528e8b44985edc12d75fb0965806045f /openjdkjvmti/transform.cc | |
parent | 436c6f5fae95aae332361060778599d0ef24a167 (diff) |
Add more standard structural redefinition entrypoints
Add structural redefinition extension function and event that mirror
the 'RedefineClasses' function and 'ClassFileLoadHook' event. The new
extension function is called
'com.android.art.class.structurally_redefine_classes' and the new
extension event is called
'com.android.art.class.structural_dex_file_load_hook'.
These extensions are the preferred way to use structural redefinition.
Like the standard 'RedefineClasses' multiple classes may be redefined
at a time.
The structural_dex_file_load_hook is triggered prior to the
can_retransform_classes ClassFileLoadHook. It is triggered on all
classes, even ones that cannot be structurally changed by
class-loading, class redefinition or by calling the RetransformClasses
function.
Calling 'structurally_redefine_classes' with new definitions that do
not require structural changes will fall back to non-structural
redefinition.
Test: ./test.py --host
Bug: 134162467
Change-Id: If4810930470c5c6509cf6db779910006e114b39f
Diffstat (limited to 'openjdkjvmti/transform.cc')
-rw-r--r-- | openjdkjvmti/transform.cc | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/openjdkjvmti/transform.cc b/openjdkjvmti/transform.cc index aa37793e49..613368525e 100644 --- a/openjdkjvmti/transform.cc +++ b/openjdkjvmti/transform.cc @@ -255,13 +255,17 @@ void Transformer::TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookNo 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<ArtJvmtiEvent kEvent> void Transformer::TransformSingleClassDirect(EventHandler* event_handler, art::Thread* self, /*in-out*/ArtClassDefinition* def) { static_assert(kEvent == ArtJvmtiEvent::kClassFileLoadHookNonRetransformable || - kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable, + kEvent == ArtJvmtiEvent::kClassFileLoadHookRetransformable || + kEvent == ArtJvmtiEvent::kStructuralDexFileLoadHook, "bad event type"); // We don't want to do transitions between calling the event and setting the new data so change to // native state early. This also avoids any problems that the FaultHandler might have in @@ -282,25 +286,30 @@ void Transformer::TransformSingleClassDirect(EventHandler* event_handler, dex_data.data(), /*out*/&new_len, /*out*/&new_data); - def->SetNewDexData(new_len, new_data); + def->SetNewDexData(new_len, new_data, kEvent); } +template <RedefinitionType kType> void Transformer::RetransformClassesDirect( - art::Thread* self, - /*in-out*/std::vector<ArtClassDefinition>* definitions) { + art::Thread* self, + /*in-out*/ std::vector<ArtClassDefinition>* definitions) { + constexpr ArtJvmtiEvent kEvent = kType == RedefinitionType::kNormal + ? ArtJvmtiEvent::kClassFileLoadHookRetransformable + : ArtJvmtiEvent::kStructuralDexFileLoadHook; for (ArtClassDefinition& def : *definitions) { - TransformSingleClassDirect<ArtJvmtiEvent::kClassFileLoadHookRetransformable>( - gEventHandler, self, &def); + TransformSingleClassDirect<kEvent>(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); + jvmtiError Transformer::RetransformClasses(jvmtiEnv* env, jint class_count, const jclass* classes) { - if (env == nullptr) { - JVMTI_LOG(WARNING, env) << "FAILURE TO RETRANSFORM env was null!"; - return ERR(INVALID_ENVIRONMENT); - } else if (class_count < 0) { + if (class_count < 0) { JVMTI_LOG(WARNING, env) << "FAILURE TO RETRANSFORM class_count was less then 0"; return ERR(ILLEGAL_ARGUMENT); } else if (class_count == 0) { @@ -317,7 +326,7 @@ jvmtiError Transformer::RetransformClasses(jvmtiEnv* env, std::vector<ArtClassDefinition> definitions; jvmtiError res = OK; for (jint i = 0; i < class_count; i++) { - res = Redefiner::GetClassRedefinitionError(classes[i], &error_msg); + res = Redefiner::GetClassRedefinitionError<RedefinitionType::kNormal>(classes[i], &error_msg); if (res != OK) { JVMTI_LOG(WARNING, env) << "FAILURE TO RETRANSFORM " << error_msg; return res; @@ -330,13 +339,16 @@ jvmtiError Transformer::RetransformClasses(jvmtiEnv* env, } definitions.push_back(std::move(def)); } - RetransformClassesDirect(self, &definitions); - res = Redefiner::RedefineClassesDirect(ArtJvmTiEnv::AsArtJvmTiEnv(env), - runtime, - self, - definitions, - RedefinitionType::kNormal, - &error_msg); + RetransformClassesDirect<RedefinitionType::kStructural>(self, &definitions); + RetransformClassesDirect<RedefinitionType::kNormal>(self, &definitions); + RedefinitionType redef_type = + std::any_of(definitions.cbegin(), + definitions.cend(), + [](const auto& it) { return it.HasStructuralChanges(); }) + ? RedefinitionType::kStructural + : RedefinitionType::kNormal; + res = Redefiner::RedefineClassesDirect( + ArtJvmTiEnv::AsArtJvmTiEnv(env), runtime, self, definitions, redef_type, &error_msg); if (res != OK) { JVMTI_LOG(WARNING, env) << "FAILURE TO RETRANSFORM " << error_msg; } |