Fix lock order for jvmti kTaggingLockLevel
Add test for duplicate env free order.
Bug: 36648696
Test: ./test.py --host
Change-Id: I76fc8187b29f5e66cc29674320e887dbc508fe19
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 038aeb3..2414b5f 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -62,10 +62,11 @@
kJdwpAdbStateLock,
kJdwpSocketLock,
kRegionSpaceRegionLock,
+ kMarkSweepMarkStackLock,
kRosAllocGlobalLock,
kRosAllocBracketLock,
kRosAllocBulkFreeLock,
- kMarkSweepMarkStackLock,
+ kTaggingLockLevel,
kTransactionLogLock,
kJniFunctionTableLock,
kJniWeakGlobalsLock,
diff --git a/runtime/openjdkjvmti/jvmti_weak_table.h b/runtime/openjdkjvmti/jvmti_weak_table.h
index ae36122..eeea75a 100644
--- a/runtime/openjdkjvmti/jvmti_weak_table.h
+++ b/runtime/openjdkjvmti/jvmti_weak_table.h
@@ -53,7 +53,7 @@
class JvmtiWeakTable : public art::gc::SystemWeakHolder {
public:
JvmtiWeakTable()
- : art::gc::SystemWeakHolder(kTaggingLockLevel),
+ : art::gc::SystemWeakHolder(art::kTaggingLockLevel),
update_since_last_sweep_(false) {
}
@@ -200,10 +200,6 @@
}
};
- // The tag table is used when visiting roots. So it needs to have a low lock level.
- static constexpr art::LockLevel kTaggingLockLevel =
- static_cast<art::LockLevel>(art::LockLevel::kAbortLock + 1);
-
std::unordered_map<art::GcRoot<art::mirror::Object>,
T,
HashGcRoot,
diff --git a/test/905-object-free/expected.txt b/test/905-object-free/expected.txt
index 436ca11..6594ad8 100644
--- a/test/905-object-free/expected.txt
+++ b/test/905-object-free/expected.txt
@@ -10,3 +10,4 @@
---
[]
---
+Free counts 1000000 1000000
diff --git a/test/905-object-free/src/Main.java b/test/905-object-free/src/Main.java
index e41e378..67811c2 100644
--- a/test/905-object-free/src/Main.java
+++ b/test/905-object-free/src/Main.java
@@ -33,6 +33,9 @@
enableFreeTracking(false);
run(l);
+
+ enableFreeTracking(true);
+ stress();
}
private static void run(ArrayList<Object> l) {
@@ -62,6 +65,25 @@
System.out.println("---");
}
+ private static void stress() {
+ getCollectedTags(0);
+ getCollectedTags(1);
+ for (int i = 0; i <= 1000000; ++i) {
+ Object obj = new Object();
+ setTag(obj, i);
+ obj = null; // Clear vreg.
+ }
+ Runtime.getRuntime().gc();
+ long[] freedTags1 = getCollectedTags(0);
+ long[] freedTags2 = getCollectedTags(1);
+ System.out.println("Free counts " + freedTags1.length + " " + freedTags2.length);
+ for (int i = 0; i < freedTags1.length; ++i) {
+ if (freedTags1[i] != freedTags2[i]) {
+ System.out.println("Mismatched tags " + freedTags1[i] + " " + freedTags2[i]);
+ }
+ }
+ }
+
private static void allocate(ArrayList<Object> l, long tag) {
Object obj = new Object();
l.add(obj);
@@ -69,7 +91,7 @@
}
private static void getAndPrintTags() {
- long[] freedTags = getCollectedTags();
+ long[] freedTags = getCollectedTags(0);
Arrays.sort(freedTags);
System.out.println(Arrays.toString(freedTags));
}
@@ -77,5 +99,5 @@
private static native void setupObjectFreeCallback();
private static native void enableFreeTracking(boolean enable);
private static native void setTag(Object o, long tag);
- private static native long[] getCollectedTags();
+ private static native long[] getCollectedTags(int index);
}
diff --git a/test/905-object-free/tracking_free.cc b/test/905-object-free/tracking_free.cc
index 5eed472..3baac88 100644
--- a/test/905-object-free/tracking_free.cc
+++ b/test/905-object-free/tracking_free.cc
@@ -31,25 +31,42 @@
namespace art {
namespace Test905ObjectFree {
-static std::vector<jlong> collected_tags;
+static std::vector<jlong> collected_tags1;
+static std::vector<jlong> collected_tags2;
-static void JNICALL ObjectFree(jvmtiEnv* ti_env ATTRIBUTE_UNUSED, jlong tag) {
- collected_tags.push_back(tag);
+jvmtiEnv* jvmti_env2;
+
+static void JNICALL ObjectFree1(jvmtiEnv* ti_env, jlong tag) {
+ CHECK_EQ(ti_env, jvmti_env);
+ collected_tags1.push_back(tag);
+}
+
+static void JNICALL ObjectFree2(jvmtiEnv* ti_env, jlong tag) {
+ CHECK_EQ(ti_env, jvmti_env2);
+ collected_tags2.push_back(tag);
+}
+
+static void setupObjectFreeCallback(jvmtiEnv* env, jvmtiEventObjectFree callback) {
+ jvmtiEventCallbacks callbacks;
+ memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
+ callbacks.ObjectFree = callback;
+ jvmtiError ret = env->SetEventCallbacks(&callbacks, sizeof(callbacks));
+ if (ret != JVMTI_ERROR_NONE) {
+ char* err;
+ env->GetErrorName(ret, &err);
+ printf("Error setting callbacks: %s\n", err);
+ env->Deallocate(reinterpret_cast<unsigned char*>(err));
+ }
}
extern "C" JNIEXPORT void JNICALL Java_Main_setupObjectFreeCallback(
- JNIEnv* env ATTRIBUTE_UNUSED, jclass klass ATTRIBUTE_UNUSED) {
- jvmtiEventCallbacks callbacks;
- memset(&callbacks, 0, sizeof(jvmtiEventCallbacks));
- callbacks.ObjectFree = ObjectFree;
-
- jvmtiError ret = jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
- if (ret != JVMTI_ERROR_NONE) {
- char* err;
- jvmti_env->GetErrorName(ret, &err);
- printf("Error setting callbacks: %s\n", err);
- jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
- }
+ JNIEnv* env, jclass klass ATTRIBUTE_UNUSED) {
+ setupObjectFreeCallback(jvmti_env, ObjectFree1);
+ JavaVM* jvm = nullptr;
+ env->GetJavaVM(&jvm);
+ CHECK_EQ(jvm->GetEnv(reinterpret_cast<void**>(&jvmti_env2), JVMTI_VERSION_1_2), 0);
+ SetAllCapabilities(jvmti_env2);
+ setupObjectFreeCallback(jvmti_env2, ObjectFree2);
}
extern "C" JNIEXPORT void JNICALL Java_Main_enableFreeTracking(JNIEnv* env ATTRIBUTE_UNUSED,
@@ -65,17 +82,29 @@
printf("Error enabling/disabling object-free callbacks: %s\n", err);
jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(err));
}
+ ret = jvmti_env2->SetEventNotificationMode(
+ enable ? JVMTI_ENABLE : JVMTI_DISABLE,
+ JVMTI_EVENT_OBJECT_FREE,
+ nullptr);
+ if (ret != JVMTI_ERROR_NONE) {
+ char* err;
+ jvmti_env2->GetErrorName(ret, &err);
+ printf("Error enabling/disabling object-free callbacks: %s\n", err);
+ jvmti_env2->Deallocate(reinterpret_cast<unsigned char*>(err));
+ }
}
extern "C" JNIEXPORT jlongArray JNICALL Java_Main_getCollectedTags(JNIEnv* env,
- jclass klass ATTRIBUTE_UNUSED) {
- jlongArray ret = env->NewLongArray(collected_tags.size());
+ jclass klass ATTRIBUTE_UNUSED,
+ jint index) {
+ std::vector<jlong>& tags = (index == 0) ? collected_tags1 : collected_tags2;
+ jlongArray ret = env->NewLongArray(tags.size());
if (ret == nullptr) {
return ret;
}
- env->SetLongArrayRegion(ret, 0, collected_tags.size(), collected_tags.data());
- collected_tags.clear();
+ env->SetLongArrayRegion(ret, 0, tags.size(), tags.data());
+ tags.clear();
return ret;
}