From de19eb96dadaf41a600ccfcf3be32d66171be6b0 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Fri, 24 Feb 2017 16:21:18 -0800 Subject: [PATCH] ART: Fix tagging Tagging is local to the jvmtiEnv. Move from a global object tag table to a table local to the ArtJvmtiEnv. Bug: 31385027 Test: m test-art-host-run-test-903-hello-tagging Change-Id: I2faeed87fd0421631fee7cd97bb7d496bf4e6338 --- runtime/openjdkjvmti/OpenjdkJvmTi.cc | 42 ++++++++++++++++++--------- runtime/openjdkjvmti/art_jvmti.h | 11 ++++--- runtime/openjdkjvmti/ti_redefine.cc | 2 ++ runtime/openjdkjvmti/ti_redefine.h | 1 + runtime/openjdkjvmti/transform.cc | 6 ++-- runtime/openjdkjvmti/transform.h | 8 +++++- test/903-hello-tagging/expected.txt | 1 + test/903-hello-tagging/src/Main.java | 8 ++++++ test/903-hello-tagging/tagging.cc | 56 ++++++++++++++++++++++++++++++++++++ 9 files changed, 112 insertions(+), 23 deletions(-) diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc index 77ca9ce2e..450b6b6bc 100644 --- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc +++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc @@ -73,7 +73,6 @@ namespace openjdkjvmti { EventHandler gEventHandler; -ObjectTagTable gObjectTagTable(&gEventHandler); #define ENSURE_NON_NULL(n) \ do { \ @@ -334,7 +333,7 @@ class JvmtiFunctions { const jvmtiHeapCallbacks* callbacks, const void* user_data) { ENSURE_HAS_CAP(env, can_tag_objects); - HeapUtil heap_util(&gObjectTagTable); + HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get()); return heap_util.FollowReferences(env, heap_filter, klass, @@ -349,7 +348,7 @@ class JvmtiFunctions { const jvmtiHeapCallbacks* callbacks, const void* user_data) { ENSURE_HAS_CAP(env, can_tag_objects); - HeapUtil heap_util(&gObjectTagTable); + HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get()); return heap_util.IterateThroughHeap(env, heap_filter, klass, callbacks, user_data); } @@ -363,7 +362,7 @@ class JvmtiFunctions { art::ScopedObjectAccess soa(jni_env); art::ObjPtr obj = soa.Decode(object); - if (!gObjectTagTable.GetTag(obj.Ptr(), tag_ptr)) { + if (!ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->GetTag(obj.Ptr(), tag_ptr)) { *tag_ptr = 0; } @@ -384,7 +383,7 @@ class JvmtiFunctions { art::ScopedObjectAccess soa(jni_env); art::ObjPtr obj = soa.Decode(object); - gObjectTagTable.Set(obj.Ptr(), tag); + ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->Set(obj.Ptr(), tag); return ERR(NONE); } @@ -403,12 +402,12 @@ class JvmtiFunctions { } art::ScopedObjectAccess soa(jni_env); - return gObjectTagTable.GetTaggedObjects(env, - tag_count, - tags, - count_ptr, - object_result_ptr, - tag_result_ptr); + return ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->GetTaggedObjects(env, + tag_count, + tags, + count_ptr, + object_result_ptr, + tag_result_ptr); } static jvmtiError ForceGarbageCollection(jvmtiEnv* env) { @@ -579,7 +578,7 @@ class JvmtiFunctions { } static jvmtiError GetLoadedClasses(jvmtiEnv* env, jint* class_count_ptr, jclass** classes_ptr) { - HeapUtil heap_util(&gObjectTagTable); + HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get()); return heap_util.GetLoadedClasses(env, class_count_ptr, classes_ptr); } @@ -678,6 +677,7 @@ class JvmtiFunctions { ENSURE_HAS_CAP(env, can_retransform_classes); std::string error_msg; jvmtiError res = Transformer::RetransformClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env), + &gEventHandler, art::Runtime::Current(), art::Thread::Current(), class_count, @@ -695,6 +695,7 @@ class JvmtiFunctions { ENSURE_HAS_CAP(env, can_redefine_classes); std::string error_msg; jvmtiError res = Redefiner::RedefineClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env), + &gEventHandler, art::Runtime::Current(), art::Thread::Current(), class_count, @@ -1162,6 +1163,8 @@ class JvmtiFunctions { static jvmtiError DisposeEnvironment(jvmtiEnv* env) { ENSURE_VALID_ENV(env); gEventHandler.RemoveArtJvmTiEnv(ArtJvmTiEnv::AsArtJvmTiEnv(env)); + art::Runtime::Current()->RemoveSystemWeakHolder( + ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get()); delete env; return OK; } @@ -1333,13 +1336,25 @@ static bool IsJvmtiVersion(jint version) { version == JVMTI_VERSION; } +extern const jvmtiInterface_1 gJvmtiInterface; +ArtJvmTiEnv::ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler) + : art_vm(runtime), + local_data(nullptr), + capabilities(), + object_tag_table(new ObjectTagTable(event_handler)) { + functions = &gJvmtiInterface; +} + // Creates a jvmtiEnv and returns it with the art::ti::Env that is associated with it. new_art_ti // is a pointer to the uninitialized memory for an art::ti::Env. static void CreateArtJvmTiEnv(art::JavaVMExt* vm, /*out*/void** new_jvmtiEnv) { - struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm); + struct ArtJvmTiEnv* env = new ArtJvmTiEnv(vm, &gEventHandler); *new_jvmtiEnv = env; gEventHandler.RegisterArtJvmTiEnv(env); + + art::Runtime::Current()->AddSystemWeakHolder( + ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get()); } // A hook that the runtime uses to allow plugins to handle GetEnv calls. It returns true and @@ -1371,7 +1386,6 @@ extern "C" bool ArtPlugin_Initialize() { SearchUtil::Register(); runtime->GetJavaVM()->AddEnvironmentHook(GetEnvHandler); - runtime->AddSystemWeakHolder(&gObjectTagTable); return true; } diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h index 99139a1f3..2ff3a478c 100644 --- a/runtime/openjdkjvmti/art_jvmti.h +++ b/runtime/openjdkjvmti/art_jvmti.h @@ -48,8 +48,7 @@ namespace openjdkjvmti { -extern const jvmtiInterface_1 gJvmtiInterface; -extern EventHandler gEventHandler; +class ObjectTagTable; // A structure that is a jvmtiEnv with additional information for the runtime. struct ArtJvmTiEnv : public jvmtiEnv { @@ -60,10 +59,10 @@ struct ArtJvmTiEnv : public jvmtiEnv { EventMasks event_masks; std::unique_ptr event_callbacks; - explicit ArtJvmTiEnv(art::JavaVMExt* runtime) - : art_vm(runtime), local_data(nullptr), capabilities() { - functions = &gJvmtiInterface; - } + // Tagging is specific to the jvmtiEnv. + std::unique_ptr object_tag_table; + + ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler); static ArtJvmTiEnv* AsArtJvmTiEnv(jvmtiEnv* env) { return art::down_cast(env); diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc index 7cc7a631a..c4d20c007 100644 --- a/runtime/openjdkjvmti/ti_redefine.cc +++ b/runtime/openjdkjvmti/ti_redefine.cc @@ -303,6 +303,7 @@ Redefiner::ClassRedefinition::~ClassRedefinition() { } jvmtiError Redefiner::RedefineClasses(ArtJvmTiEnv* env, + EventHandler* event_handler, art::Runtime* runtime, art::Thread* self, jint class_count, @@ -350,6 +351,7 @@ jvmtiError Redefiner::RedefineClasses(ArtJvmTiEnv* env, } // Call all the transformation events. jvmtiError res = Transformer::RetransformClassesDirect(env, + event_handler, self, &def_vector); if (res != OK) { diff --git a/runtime/openjdkjvmti/ti_redefine.h b/runtime/openjdkjvmti/ti_redefine.h index 65ee2912e..4e6d05f05 100644 --- a/runtime/openjdkjvmti/ti_redefine.h +++ b/runtime/openjdkjvmti/ti_redefine.h @@ -88,6 +88,7 @@ class Redefiner { // 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, + EventHandler* event_handler, art::Runtime* runtime, art::Thread* self, jint class_count, diff --git a/runtime/openjdkjvmti/transform.cc b/runtime/openjdkjvmti/transform.cc index 2fec631c0..36421b913 100644 --- a/runtime/openjdkjvmti/transform.cc +++ b/runtime/openjdkjvmti/transform.cc @@ -63,12 +63,13 @@ namespace openjdkjvmti { jvmtiError Transformer::RetransformClassesDirect( ArtJvmTiEnv* env, + EventHandler* event_handler, art::Thread* self, /*in-out*/std::vector* definitions) { for (ArtClassDefinition& def : *definitions) { jint new_len = -1; unsigned char* new_data = nullptr; - gEventHandler.DispatchEvent( + event_handler->DispatchEvent( self, GetJniEnv(env), def.klass, @@ -85,6 +86,7 @@ jvmtiError Transformer::RetransformClassesDirect( } jvmtiError Transformer::RetransformClasses(ArtJvmTiEnv* env, + EventHandler* event_handler, art::Runtime* runtime, art::Thread* self, jint class_count, @@ -114,7 +116,7 @@ jvmtiError Transformer::RetransformClasses(ArtJvmTiEnv* env, } definitions.push_back(std::move(def)); } - res = RetransformClassesDirect(env, self, &definitions); + res = RetransformClassesDirect(env, event_handler, self, &definitions); if (res != OK) { return res; } diff --git a/runtime/openjdkjvmti/transform.h b/runtime/openjdkjvmti/transform.h index 65f2ae135..c6a36e8e2 100644 --- a/runtime/openjdkjvmti/transform.h +++ b/runtime/openjdkjvmti/transform.h @@ -42,14 +42,20 @@ namespace openjdkjvmti { +class EventHandler; + 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* definitions); + ArtJvmTiEnv* env, + EventHandler* event_handler, + art::Thread* self, + /*in-out*/std::vector* definitions); static jvmtiError RetransformClasses(ArtJvmTiEnv* env, + EventHandler* event_handler, art::Runtime* runtime, art::Thread* self, jint class_count, diff --git a/test/903-hello-tagging/expected.txt b/test/903-hello-tagging/expected.txt index 872b79b51..acfdbd810 100644 --- a/test/903-hello-tagging/expected.txt +++ b/test/903-hello-tagging/expected.txt @@ -8,3 +8,4 @@ [, , , , , , , , , , , , , , , , , ] 18 [<1;0>, <2;0>, <3;0>, <4;0>, <5;0>, <6;0>, <7;0>, <8;0>, <9;0>, <11;0>, <12;0>, <13;0>, <14;0>, <15;0>, <16;0>, <17;0>, <18;0>, <19;0>] +[100, 101, 102, 103, 104, 105, 106, 107, 108, 109] diff --git a/test/903-hello-tagging/src/Main.java b/test/903-hello-tagging/src/Main.java index 2f0365a92..48896b236 100644 --- a/test/903-hello-tagging/src/Main.java +++ b/test/903-hello-tagging/src/Main.java @@ -22,6 +22,7 @@ public class Main { public static void main(String[] args) { doTest(); testGetTaggedObjects(); + testTags(); } public static void doTest() { @@ -35,6 +36,12 @@ public class Main { } } + public static void testTags() { + Object o = new Object(); + long[] res = testTagsInDifferentEnvs(o, 100, 10); + System.out.println(Arrays.toString(res)); + } + private static WeakReference test() { Object o1 = new Object(); setTag(o1, 1); @@ -166,4 +173,5 @@ public class Main { private static native long getTag(Object o); private static native Object[] getTaggedObjects(long[] searchTags, boolean returnObjects, boolean returnTags); + private static native long[] testTagsInDifferentEnvs(Object o, long baseTag, int n); } diff --git a/test/903-hello-tagging/tagging.cc b/test/903-hello-tagging/tagging.cc index f74c1fc2e..6177263cd 100644 --- a/test/903-hello-tagging/tagging.cc +++ b/test/903-hello-tagging/tagging.cc @@ -139,6 +139,62 @@ extern "C" JNIEXPORT jobjectArray JNICALL Java_Main_getTaggedObjects(JNIEnv* env return resultArray; } +static jvmtiEnv* CreateJvmtiEnv(JNIEnv* env) { + JavaVM* jvm; + CHECK_EQ(0, env->GetJavaVM(&jvm)); + + jvmtiEnv* new_jvmti_env; + CHECK_EQ(0, jvm->GetEnv(reinterpret_cast(&new_jvmti_env), JVMTI_VERSION_1_0)); + + jvmtiCapabilities capa; + memset(&capa, 0, sizeof(jvmtiCapabilities)); + capa.can_tag_objects = 1; + jvmtiError error = new_jvmti_env->AddCapabilities(&capa); + CHECK_EQ(JVMTI_ERROR_NONE, error); + + return new_jvmti_env; +} + +static void SetTag(jvmtiEnv* env, jobject obj, jlong tag) { + jvmtiError ret = env->SetTag(obj, tag); + CHECK_EQ(JVMTI_ERROR_NONE, ret); +} + +static jlong GetTag(jvmtiEnv* env, jobject obj) { + jlong tag; + jvmtiError ret = env->GetTag(obj, &tag); + CHECK_EQ(JVMTI_ERROR_NONE, ret); + return tag; +} + +extern "C" JNIEXPORT jlongArray JNICALL Java_Main_testTagsInDifferentEnvs( + JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jobject obj, jlong base_tag, jint count) { + std::unique_ptr envs = std::unique_ptr(new jvmtiEnv*[count]); + envs[0] = jvmti_env; + for (int32_t i = 1; i != count; ++i) { + envs[i] = CreateJvmtiEnv(env); + } + + for (int32_t i = 0; i != count; ++i) { + SetTag(envs[i], obj, base_tag + i); + } + std::unique_ptr vals = std::unique_ptr(new jlong[count]); + for (int32_t i = 0; i != count; ++i) { + vals[i] = GetTag(envs[i], obj); + } + + for (int32_t i = 1; i != count; ++i) { + CHECK_EQ(JVMTI_ERROR_NONE, envs[i]->DisposeEnvironment()); + } + + jlongArray res = env->NewLongArray(count); + if (res == nullptr) { + return nullptr; + } + env->SetLongArrayRegion(res, 0, count, vals.get()); + return res; +} + } // namespace Test903HelloTagging } // namespace art -- 2.11.0