diff a/test/hotspot/jtreg/serviceability/jvmti/vthread/StopThreadTest/StopThreadTest.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/StopThreadTest/StopThreadTest.java
--- a/test/hotspot/jtreg/serviceability/jvmti/vthread/StopThreadTest/StopThreadTest.java
+++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/StopThreadTest/StopThreadTest.java
@@ -23,25 +23,29 @@
 
 /*
  * @test id=default
  * @summary Verifies JVMTI StopThread support for virtual threads.
  * @requires vm.continuations
+ * @library /test/lib
  * @run main/othervm/native -agentlib:StopThreadTest StopThreadTest
  */
 
 /*
  * @test id=no-vmcontinuations
  * @summary Verifies JVMTI StopThread support for bound virtual threads.
- * @run main/othervm/native -agentlib:StopThreadTest -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations StopThreadTest
+ * @library /test/lib
+ * @run main/othervm/native -agentlib:StopThreadTest -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations -DboundVThread=true StopThreadTest
  */
 
 /*
  * @test id=platform
  * @summary Verifies JVMTI StopThread support for platform threads.
+ * @library /test/lib
  * @run main/othervm/native -agentlib:StopThreadTest StopThreadTest platform
  */
 
+import jdk.test.lib.Platform;
 import java.lang.AssertionError;
 
 /*
  *     The test exercises the JVMTI function: StopThread(jthread).
  *     The test creates a new virtual or platform thread.
@@ -51,11 +55,13 @@
  *      - method C() that forces agent to send AssertionError exception to its own thread
  *     All cases are using JVMTI StopThread to send an AssertionError object.
  */
 public class StopThreadTest {
     private static final String agentLib = "StopThreadTest";
+    static final boolean isBoundVThread = Boolean.getBoolean("boundVThread");
     static final int JVMTI_ERROR_NONE = 0;
+    static final int JVMTI_ERROR_OPAQUE_FRAME = 32;
     static final int THREAD_NOT_SUSPENDED = 13;
     static final int PASSED = 0;
     static final int FAILED = 2;
 
     static void log(String str) { System.out.println(str); }
@@ -102,11 +108,11 @@
             if (is_virtual) {
                 testTaskThread = Thread.ofVirtual().name("TestTaskThread").start(testTask);
             } else {
                 testTaskThread = Thread.ofPlatform().name("TestTaskThread").start(testTask);
             }
-            TestTask.ensureAtPointA();
+            TestTask.ensureAtPointA(testTaskThread);
 
             if (is_virtual) { // this check is for virtual target thread only
                 log("\nMain #A.1: unsuspended");
                 retCode = stopThread(testTaskThread);
                 if (retCode != THREAD_NOT_SUSPENDED) {
@@ -117,14 +123,17 @@
             }
 
             log("\nMain #A.2: suspended");
             suspendThread(testTaskThread);
             retCode = stopThread(testTaskThread);
-            if (retCode != JVMTI_ERROR_NONE) {
-                throwFailed("Main #A.2: expected JVMTI_ERROR_NONE instead of: " + retCode);
+            int expectedRetCode = (is_virtual && !isBoundVThread && (Platform.isX64() || Platform.isAArch64())) ? JVMTI_ERROR_OPAQUE_FRAME : JVMTI_ERROR_NONE;
+            String expectedRetCodeName = (is_virtual && !isBoundVThread && (Platform.isX64() || Platform.isAArch64())) ?
+                "JVMTI_ERROR_OPAQUE_FRAME" : "JVMTI_ERROR_NONE";
+            if (retCode != expectedRetCode) {
+                throwFailed("Main #A.2: expected " + expectedRetCodeName + " instead of: " + retCode);
             } else {
-                log("Main #A.2: got expected JVMTI_ERROR_NONE");
+                log("Main #A.2: got expected " + expectedRetCodeName);
             }
             resumeThread(testTaskThread);
         }
         log("\nMain #B: method B() must be blocked in a breakpoint event handler");
         {
@@ -177,12 +186,13 @@
             } catch (InterruptedException e) {
                 throw new RuntimeException("Interruption in TestTask.sleep: \n\t" + e);
             }
         }
 
-        static void ensureAtPointA() {
-            while (!atPointA) {
+        static void ensureAtPointA(Thread vt) {
+            // wait while the thread state is not the expected one
+            while (vt.getState() != Thread.State.BLOCKED) {
                 sleep(1);
             }
         }
 
         // Ensure thread is finished.
@@ -201,11 +211,14 @@
             } catch (AssertionError ex) {
                 log("TestTask.run: caught expected AssertionError from method A()");
                 seenExceptionFromA = true;
             }
             Thread.interrupted();
-            if (!seenExceptionFromA) {
+            if (!seenExceptionFromA
+                && !(is_virtual
+                     && !isBoundVThread
+                     && (Platform.isX64() || (Platform.isAArch64())) )) {
                 StopThreadTest.setFailed("TestTask.run: expected AssertionError from method A()");
             }
             sleep(1); // to cause yield
 
             boolean seenExceptionFromB = false;
@@ -239,11 +252,10 @@
         // StopThread is used to send an AssertionError object two times:
         //  - when not suspended: THREAD_NOT_SUSPENDED is expected
         //  - when suspended: JVMTI_ERROR_NONE is expected
         static void A() {
             log("TestTask.A: started");
-            atPointA = true;
             synchronized (lock) {
             }
             log("TestTask.A: finished");
         }
 
