8214572: [Graal] nsk/jvmti/unit/ForceEarlyReturn/earlyretbase should not suspend the thread when the top frame executes JVMCI code
authordtitov
Tue, 04 Dec 2018 21:13:45 -0800
changeset 52828 f6005102c6ef
parent 52827 5261951acd41
child 52829 af52abc1f61e
8214572: [Graal] nsk/jvmti/unit/ForceEarlyReturn/earlyretbase should not suspend the thread when the top frame executes JVMCI code Reviewed-by: sspitsyn, dholmes, jcbeyler
test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase.java
test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp
test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.cpp
test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.h
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase.java	Tue Dec 04 17:18:11 2018 -0800
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase.java	Tue Dec 04 21:13:45 2018 -0800
@@ -54,8 +54,7 @@
         }
     }
 
-    native static int doForceEarlyReturn(Class targCls,
-                          Thread earlyretThr, long valToRet);
+    native static int doForceEarlyReturn(Thread earlyretThr, long valToRet);
     native static int suspThread(earlyretThread earlyretThr);
     native static int resThread(earlyretThread earlyretThr);
     native static int check();
@@ -96,8 +95,7 @@
         out.println("Forcing early return...");
 
         // force return from a top frame of the child thread
-        retCode = doForceEarlyReturn(earlyretThread.class,
-                                     earlyretThr, JAVA_BIRTH_YEAR);
+        retCode = doForceEarlyReturn(earlyretThr, JAVA_BIRTH_YEAR);
         earlyretDone = true;
         earlyretThr.letItGo();
         if (retCode != Consts.TEST_PASSED) {
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp	Tue Dec 04 17:18:11 2018 -0800
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/ForceEarlyReturn/earlyretbase/earlyretbase.cpp	Tue Dec 04 21:13:45 2018 -0800
@@ -78,22 +78,29 @@
 JNIEXPORT jint JNICALL
 Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_suspThread(JNIEnv *env,
         jclass cls, jobject earlyretThr) {
-    jvmtiError err;
 
     if (!caps.can_force_early_return || !caps.can_suspend) {
         return PASSED;
     }
 
-    printf(">>>>>>>> Invoke SuspendThread()\n");
-    err = jvmti->SuspendThread(earlyretThr);
-    if (err != JVMTI_ERROR_NONE) {
-        printf("%s: Failed to call SuspendThread(): error=%d: %s\n",
-            __FILE__, err, TranslateError(err));
-        return JNI_ERR;
+    jclass clazz = env->GetObjectClass(earlyretThr);
+    if (clazz == NULL) {
+        printf("Cannot get class of thread object\n");
+        RETURN_FAILED;
     }
-    printf("<<<<<<<< SuspendThread() is successfully done\n");
-    fflush(0);
-    return PASSED;
+
+    midActiveMethod = env->GetMethodID(clazz, name_exp, sig_exp);
+    if (midActiveMethod == NULL) {
+        printf("Cannot find Method ID for method %s\n", name_exp);
+        RETURN_FAILED;
+    }
+
+    int result = suspendThreadAtMethod(jvmti, cls, earlyretThr, midActiveMethod);
+    if( result == NSK_TRUE) {
+        return PASSED;
+    } else {
+        RETURN_FAILED;
+    }
 }
 
 JNIEXPORT jint JNICALL
@@ -119,7 +126,7 @@
 
 JNIEXPORT jint JNICALL
 Java_nsk_jvmti_unit_ForceEarlyReturn_earlyretbase_doForceEarlyReturn(JNIEnv *env,
-        jclass cls, jclass targCls, jthread earlyretThr, jlong valToRet) {
+        jclass cls, jthread earlyretThr, jlong valToRet) {
     jvmtiError err;
 
     if (!caps.can_force_early_return || !caps.can_suspend) {
@@ -160,14 +167,6 @@
     }
     printf(">>>>>>>> Invoke ForceEarlyReturn()\n");
 
-    printf("Before call to GetMethodID(%s, %s)\n", name_exp, sig_exp);
-    midActiveMethod = env->GetMethodID(targCls, name_exp, sig_exp);
-    if (midActiveMethod == NULL) {
-        printf("Cannot find Method ID for method %s\n", name_exp);
-        RETURN_FAILED;
-    }
-    printf("After call to GetMethodID(%s, %s)\n", name_exp, sig_exp);
-
     err = jvmti->ForceEarlyReturnLong(earlyretThr, valToRet);
     if (err != JVMTI_ERROR_NONE) {
         printf("TEST FAILED: the function ForceEarlyReturn()"
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.cpp	Tue Dec 04 17:18:11 2018 -0800
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.cpp	Tue Dec 04 21:13:45 2018 -0800
@@ -633,6 +633,69 @@
     return 1;
 }
 
+#define SLEEP_DELAY 10L
+
+int suspendThreadAtMethod(jvmtiEnv *jvmti, jclass cls, jobject thread, jmethodID testMethod) {
+    printf(">>>>>>>> Invoke SuspendThread()\n");
+
+    jvmtiError err = jvmti->SuspendThread(thread);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("%s: Failed to call SuspendThread(): error=%d: %s\n",
+               __FILE__, err, TranslateError(err));
+        return NSK_FALSE;
+    }
+
+    int result = NSK_TRUE;
+    jmethodID method = NULL;
+    jlocation loc;
+
+    // We need to ensure that the thread is suspended at the right place when the top
+    // frame belongs to the test rather than to incidental Java code (classloading,
+    // JVMCI, etc). Below we do resume/suspend in the loop until the target method
+    // is executed in the top frame or the loop counter exceeds the limit.
+    for (int i = 0; i < 10; i++) {
+        err = jvmti->GetFrameLocation(thread, 0, &method, &loc);
+        if (err != JVMTI_ERROR_NONE) {
+            printf("(GetFrameLocation) unexpected error: %s (%d)\n",
+                   TranslateError(err), err);
+            result = NSK_FALSE;
+            break;
+        }
+
+        char *name, *sig, *generic;
+        jvmti->GetMethodName(method, &name, &sig, &generic);
+        printf(">>> Attempt %d to suspend the thread. Top frame: \"%s%s\"\n",
+               i, name, sig);
+        if (method == testMethod) break;
+
+        err = jvmti->ResumeThread(thread);
+        if (err != JVMTI_ERROR_NONE) {
+            printf("(ResumeThread) unexpected error: %s (%d)\n",
+                   TranslateError(err), err);
+            result = NSK_FALSE;
+        }
+
+        mssleep(SLEEP_DELAY);
+
+        err = jvmti->SuspendThread(thread);
+        if (err != JVMTI_ERROR_NONE) {
+            printf("(SuspendThread) unexpected error: %s (%d)\n",
+                   TranslateError(err), err);
+            result = NSK_FALSE;
+        }
+    }
+    if(method == testMethod) {
+        printf("<<<<<<<< SuspendThread() is successfully done\n");
+    } else {
+        char *name, *sig, *generic;
+        jvmti->GetMethodName(testMethod, &name, &sig, &generic);
+        printf("Failed in the suspendThread: was not able to suspend thread "
+               "with required method \"%s%s\" on the top\n", name, sig);
+        result = NSK_FALSE;
+    }
+    return result;
+}
+
 jint createRawMonitor(jvmtiEnv *env, const char *name, jrawMonitorID *monitor) {
     jvmtiError error = env->CreateRawMonitor(name, monitor);
     if (!NSK_JVMTI_VERIFY(error)) {
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.h	Tue Dec 04 17:18:11 2018 -0800
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jvmti/jvmti_tools.h	Tue Dec 04 21:13:45 2018 -0800
@@ -371,6 +371,12 @@
 
 int isThreadExpected(jvmtiEnv *jvmti, jthread thread);
 
+/**
+* This method makes the thread to be suspended at the right place when the top frame
+* belongs to the test rather than to incidental Java code (classloading, JVMCI, etc).
+*/
+int suspendThreadAtMethod(jvmtiEnv *jvmti, jclass cls, jobject thread, jmethodID method);
+
 jint createRawMonitor(jvmtiEnv *env, const char *name, jrawMonitorID *monitor);
 
 void exitOnError(jvmtiError error);