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
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 77ca9ce..450b6b6 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 @@
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 @@
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 @@
art::ScopedObjectAccess soa(jni_env);
art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(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 @@
art::ScopedObjectAccess soa(jni_env);
art::ObjPtr<art::mirror::Object> obj = soa.Decode<art::mirror::Object>(object);
- gObjectTagTable.Set(obj.Ptr(), tag);
+ ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table->Set(obj.Ptr(), tag);
return ERR(NONE);
}
@@ -403,12 +402,12 @@
}
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
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 99139a1..2ff3a47 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 @@
EventMasks event_masks;
std::unique_ptr<jvmtiEventCallbacks> 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<ObjectTagTable> object_tag_table;
+
+ ArtJvmTiEnv(art::JavaVMExt* runtime, EventHandler* event_handler);
static ArtJvmTiEnv* AsArtJvmTiEnv(jvmtiEnv* env) {
return art::down_cast<ArtJvmTiEnv*>(env);
diff --git a/runtime/openjdkjvmti/ti_redefine.cc b/runtime/openjdkjvmti/ti_redefine.cc
index 7cc7a63..c4d20c0 100644
--- a/runtime/openjdkjvmti/ti_redefine.cc
+++ b/runtime/openjdkjvmti/ti_redefine.cc
@@ -303,6 +303,7 @@
}
jvmtiError Redefiner::RedefineClasses(ArtJvmTiEnv* env,
+ EventHandler* event_handler,
art::Runtime* runtime,
art::Thread* self,
jint class_count,
@@ -350,6 +351,7 @@
}
// 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 65ee291..4e6d05f 100644
--- a/runtime/openjdkjvmti/ti_redefine.h
+++ b/runtime/openjdkjvmti/ti_redefine.h
@@ -88,6 +88,7 @@
// 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 2fec631..36421b9 100644
--- a/runtime/openjdkjvmti/transform.cc
+++ b/runtime/openjdkjvmti/transform.cc
@@ -63,12 +63,13 @@
jvmtiError Transformer::RetransformClassesDirect(
ArtJvmTiEnv* env,
+ EventHandler* event_handler,
art::Thread* self,
/*in-out*/std::vector<ArtClassDefinition>* definitions) {
for (ArtClassDefinition& def : *definitions) {
jint new_len = -1;
unsigned char* new_data = nullptr;
- gEventHandler.DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
+ event_handler->DispatchEvent<ArtJvmtiEvent::kClassFileLoadHookRetransformable>(
self,
GetJniEnv(env),
def.klass,
@@ -85,6 +86,7 @@
}
jvmtiError Transformer::RetransformClasses(ArtJvmTiEnv* env,
+ EventHandler* event_handler,
art::Runtime* runtime,
art::Thread* self,
jint class_count,
@@ -114,7 +116,7 @@
}
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 65f2ae1..c6a36e8 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<ArtClassDefinition>* definitions);
+ ArtJvmTiEnv* env,
+ EventHandler* event_handler,
+ art::Thread* self,
+ /*in-out*/std::vector<ArtClassDefinition>* 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 872b79b..acfdbd8 100644
--- a/test/903-hello-tagging/expected.txt
+++ b/test/903-hello-tagging/expected.txt
@@ -8,3 +8,4 @@
[<null;1>, <null;1>, <null;2>, <null;2>, <null;3>, <null;3>, <null;4>, <null;4>, <null;5>, <null;5>, <null;6>, <null;6>, <null;7>, <null;7>, <null;8>, <null;8>, <null;9>, <null;9>]
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 2f0365a..48896b2 100644
--- a/test/903-hello-tagging/src/Main.java
+++ b/test/903-hello-tagging/src/Main.java
@@ -22,6 +22,7 @@
public static void main(String[] args) {
doTest();
testGetTaggedObjects();
+ testTags();
}
public static void doTest() {
@@ -35,6 +36,12 @@
}
}
+ public static void testTags() {
+ Object o = new Object();
+ long[] res = testTagsInDifferentEnvs(o, 100, 10);
+ System.out.println(Arrays.toString(res));
+ }
+
private static WeakReference<Object> test() {
Object o1 = new Object();
setTag(o1, 1);
@@ -166,4 +173,5 @@
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 f74c1fc..6177263 100644
--- a/test/903-hello-tagging/tagging.cc
+++ b/test/903-hello-tagging/tagging.cc
@@ -139,6 +139,62 @@
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<void**>(&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<jvmtiEnv*[]> envs = std::unique_ptr<jvmtiEnv*[]>(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<jlong[]> vals = std::unique_ptr<jlong[]>(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