summaryrefslogtreecommitdiff
path: root/openjdkjvmti/ti_extension.cc
diff options
context:
space:
mode:
author Alex Light <allight@google.com> 2019-10-15 15:46:07 -0700
committer Alex Light <allight@google.com> 2019-10-30 16:53:25 -0700
commitd55b844e39c4d5eb1a56de6cb95c891659f8a27f (patch)
treeed2f7809528e8b44985edc12d75fb0965806045f /openjdkjvmti/ti_extension.cc
parent436c6f5fae95aae332361060778599d0ef24a167 (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/ti_extension.cc')
-rw-r--r--openjdkjvmti/ti_extension.cc69
1 files changed, 66 insertions, 3 deletions
diff --git a/openjdkjvmti/ti_extension.cc b/openjdkjvmti/ti_extension.cc
index 5dc7445681..058a188630 100644
--- a/openjdkjvmti/ti_extension.cc
+++ b/openjdkjvmti/ti_extension.cc
@@ -30,6 +30,7 @@
#include <vector>
+#include "jvmti.h"
#include "ti_extension.h"
#include "art_jvmti.h"
@@ -45,6 +46,7 @@
#include "ti_monitor.h"
#include "ti_redefine.h"
#include "ti_search.h"
+#include "transform.h"
#include "thread-inl.h"
@@ -416,7 +418,40 @@ jvmtiError ExtensionUtil::GetExtensionFunctions(jvmtiEnv* env,
return error;
}
- // StructurallyRedefineClass
+ // StructurallyRedefineClasses
+ error = add_extension(
+ reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClasses),
+ "com.android.art.class.structurally_redefine_classes",
+ "Entrypoint for structural class redefinition. Has the same signature as RedefineClasses."
+ " Currently this only supports adding new static fields to a class without any instance"
+ " fields or methods. After calling this com.android.art.structural_dex_file_load_hook"
+ " events will be triggered, followed by re-transformable ClassFileLoadHook events. After"
+ " this method completes subsequent RetransformClasses calls will use the input to this"
+ " function as the initial class definition.",
+ {
+ { "num_classes", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
+ { "class_definitions", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CVOID, false },
+ },
+ {
+ ERR(CLASS_LOADER_UNSUPPORTED),
+ ERR(FAILS_VERIFICATION),
+ ERR(ILLEGAL_ARGUMENT),
+ ERR(INVALID_CLASS),
+ ERR(MUST_POSSESS_CAPABILITY),
+ ERR(MUST_POSSESS_CAPABILITY),
+ ERR(NULL_POINTER),
+ ERR(OUT_OF_MEMORY),
+ ERR(UNMODIFIABLE_CLASS),
+ ERR(UNSUPPORTED_REDEFINITION_HIERARCHY_CHANGED),
+ ERR(UNSUPPORTED_REDEFINITION_METHOD_ADDED),
+ ERR(UNSUPPORTED_REDEFINITION_METHOD_DELETED),
+ ERR(UNSUPPORTED_REDEFINITION_SCHEMA_CHANGED),
+ });
+ if (error != ERR(NONE)) {
+ return error;
+ }
+
+ // StructurallyRedefineClassDirect
error = add_extension(
reinterpret_cast<jvmtiExtensionFunction>(Redefiner::StructurallyRedefineClassDirect),
"com.android.art.UNSAFE.class.structurally_redefine_class_direct",
@@ -494,7 +529,7 @@ jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
const char* id,
const char* short_description,
const std::vector<CParamInfo>& params) {
- DCHECK(IsExtensionEvent(extension_event_index));
+ DCHECK(IsExtensionEvent(extension_event_index)) << static_cast<jint>(extension_event_index);
jvmtiExtensionEventInfo event_info;
jvmtiError error;
@@ -592,7 +627,35 @@ jvmtiError ExtensionUtil::GetExtensionEvents(jvmtiEnv* env,
if (error != OK) {
return error;
}
-
+ art::Runtime* runtime = art::Runtime::Current();
+ if (runtime->GetJniIdType() == art::JniIdType::kIndices &&
+ (runtime->GetInstrumentation()->IsForcedInterpretOnly() || runtime->IsJavaDebuggable())) {
+ error = add_extension(
+ ArtJvmtiEvent::kStructuralDexFileLoadHook,
+ "com.android.art.class.structural_dex_file_load_hook",
+ "Called during class load, after a 'RetransformClasses' call, or after a 'RedefineClasses'"
+ " call in order to allow the agent to modify the class. This event is called after any"
+ " non-can_retransform_classes ClassFileLoadHookEvents and before any"
+ " can_retransform_classes ClassFileLoadHookEvents. The transformations applied are"
+ " restricted in the same way that transformations applied via the "
+ " 'com.android.art.class.structurally_redefine_classes' extension function. The arguments"
+ " to the event are identical to the ones in the ClassFileLoadHook and have the same"
+ " semantics.",
+ {
+ { "jni_env", JVMTI_KIND_IN, JVMTI_TYPE_JNIENV, false },
+ { "class_being_redefined", JVMTI_KIND_IN, JVMTI_TYPE_JCLASS, true },
+ { "loader", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, false },
+ { "name", JVMTI_KIND_IN_PTR, JVMTI_TYPE_CCHAR, false },
+ { "protection_domain", JVMTI_KIND_IN, JVMTI_TYPE_JOBJECT, true },
+ { "dex_data_len", JVMTI_KIND_IN, JVMTI_TYPE_JINT, false },
+ { "dex_data", JVMTI_KIND_IN_BUF, JVMTI_TYPE_CCHAR, false },
+ { "new_dex_data_len", JVMTI_KIND_OUT, JVMTI_TYPE_JINT, false },
+ { "new_dex_data", JVMTI_KIND_ALLOC_BUF, JVMTI_TYPE_CCHAR, true },
+ });
+ } else {
+ LOG(INFO) << "debuggable & jni-type indices are required to implement structural "
+ << "class redefinition extensions.";
+ }
// Copy into output buffer.
*extension_count_ptr = ext_vector.size();