You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2026/03/01 02:39:30 UTC

(groovy) 02/02: GROOVY-9381: Phase 10 — PR review fixes, package refactoring, coverage

This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY-9381_2
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit 13916c3500f8b06fd5f260b67ae08f9986bbe3b1
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Mar 1 11:34:35 2026 +0900

    GROOVY-9381: Phase 10 — PR review fixes, package refactoring, coverage
    
    Address all 12 review comments from PR #2386:
    - Fix Javadocs: AsyncASTTransformation, Async annotation, GroovyPromise.cancel()
    - Add AwaitableAdapterRegistry.unregister() + register() returning AutoCloseable
    - Add AwaitableAdapterRegistry.setBlockingExecutor() to avoid pool starvation
    - Fix containsYieldReturn/containsYieldReturnCalls to check owner type
    - Use collision-safe synthetic names: $__asyncGen__, $__asyncStream__N
    - Reduce Thread.sleep times in cancellation tests (10s → 100ms)
    - Add @AfterEach cleanup in AsyncFrameworkIntegrationTest
    
    Package refactoring — separate user-facing from internal APIs:
    - Move GroovyPromise to org.apache.groovy.runtime.async (internal)
    - Move AsyncStreamGenerator to org.apache.groovy.runtime.async (internal)
    - Create org.apache.groovy.runtime.async.AsyncSupport (compiler support)
    - Create groovy.concurrent.AsyncUtils (user-facing API facade)
    - Retain groovy.transform.AsyncUtils as deprecated backward-compat facade
    - Update AstBuilder/AsyncASTTransformation to reference AsyncSupport
    - Migrate all test imports to new package locations
    
    Coverage improvements:
    - Add 18 new tests covering AwaitableAdapterRegistry (unregister,
      AutoCloseable, setBlockingExecutor, Iterator streams, error paths),
      AsyncStreamGenerator (error propagation, multiple yields),
      AsyncUtils (null await, CompletionStage, plain Future, deepUnwrap),
      backward compatibility facade, and AsyncStream.empty()
    
    All 376 async tests + 180 project tasks pass.
    
    Co-authored-by: Copilot <22...@users.noreply.github.com>
---
 src/main/java/groovy/concurrent/AsyncUtils.java    | 194 +++++++++
 src/main/java/groovy/concurrent/Awaitable.java     |   6 +-
 .../java/groovy/concurrent/AwaitableAdapter.java   |   2 +-
 .../concurrent/AwaitableAdapterRegistry.java       |  44 +-
 src/main/java/groovy/transform/Async.java          |  49 ++-
 src/main/java/groovy/transform/AsyncUtils.java     | 473 ++-------------------
 .../apache/groovy/parser/antlr4/AstBuilder.java    |  37 +-
 .../runtime/async}/AsyncStreamGenerator.java       |   8 +-
 .../apache/groovy/runtime/async/AsyncSupport.java} | 137 +-----
 .../groovy/runtime/async}/GroovyPromise.java       |  19 +-
 .../groovy/transform/AsyncASTTransformation.java   |  44 +-
 .../groovy/transform/AsyncAwaitSyntaxTest.groovy   |   8 +-
 .../groovy/transform/AsyncClosureLambdaTest.groovy |  90 ++--
 .../transform/AsyncExceptionHandlingTest.groovy    |  88 ++--
 .../transform/AsyncFrameworkIntegrationTest.groovy |   6 +-
 .../groovy/transform/AsyncTransformTest.groovy     | 335 ++++++++++++++-
 .../groovy/transform/AsyncVirtualThreadTest.groovy | 114 ++---
 17 files changed, 870 insertions(+), 784 deletions(-)

diff --git a/src/main/java/groovy/concurrent/AsyncUtils.java b/src/main/java/groovy/concurrent/AsyncUtils.java
new file mode 100644
index 0000000000..f4231ac25a
--- /dev/null
+++ b/src/main/java/groovy/concurrent/AsyncUtils.java
@@ -0,0 +1,194 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ */
+package groovy.concurrent;
+
+import groovy.lang.Closure;
+import org.apache.groovy.runtime.async.AsyncSupport;
+
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Future;
+
+/**
+ * User-facing API for Groovy's {@code async}/{@code await} language feature.
+ * <p>
+ * Provides methods for awaiting async results, creating async computations,
+ * and configuring the async executor. Inside {@code async} methods, the
+ * {@code await expr} expression is compiled to call the internal runtime
+ * support directly, but users may also call these methods explicitly:
+ * <pre>
+ * import static groovy.concurrent.AsyncUtils.*
+ *
+ * def future = async {
+ *     def result = await someAsyncCall()
+ *     return result * 2
+ * }
+ * </pre>
+ *
+ * @see groovy.transform.Async
+ * @see Awaitable
+ * @see AwaitableAdapterRegistry
+ * @since 6.0.0
+ */
+public class AsyncUtils {
+
+    private AsyncUtils() { }
+
+    // ---- await overloads ------------------------------------------------
+
+    /**
+     * Awaits the result of an {@link Awaitable}.
+     * <p>
+     * Exception handling follows the same principle as C# and JavaScript:
+     * the <em>original</em> exception is rethrown transparently, even if it
+     * is a checked exception.
+     */
+    public static <T> T await(Awaitable<T> awaitable) {
+        return AsyncSupport.await(awaitable);
+    }
+
+    /**
+     * Awaits the result of a {@link CompletableFuture}.
+     */
+    public static <T> T await(CompletableFuture<T> future) {
+        return AsyncSupport.await(future);
+    }
+
+    /**
+     * Awaits the result of a {@link CompletionStage}.
+     */
+    public static <T> T await(CompletionStage<T> stage) {
+        return AsyncSupport.await(stage);
+    }
+
+    /**
+     * Awaits the result of a {@link Future}.
+     */
+    public static <T> T await(Future<T> future) {
+        return AsyncSupport.await(future);
+    }
+
+    /**
+     * Awaits an arbitrary object by adapting it to {@link Awaitable} via the
+     * {@link AwaitableAdapterRegistry}.
+     */
+    public static <T> T await(Object source) {
+        return AsyncSupport.await(source);
+    }
+
+    // ---- async ----------------------------------------------------------
+
+    /**
+     * Executes the given closure asynchronously using the default executor,
+     * returning an {@link Awaitable}.
+     */
+    public static <T> Awaitable<T> async(Closure<T> closure) {
+        return AsyncSupport.async(closure);
+    }
+
+    // ---- awaitAll / awaitAny / awaitAllSettled ---------------------------
+
+    /**
+     * Waits for all given awaitables and returns their results as a list.
+     * Analogous to JavaScript's {@code Promise.all()}.
+     */
+    public static List<Object> awaitAll(Object... awaitables) {
+        return AsyncSupport.awaitAll(awaitables);
+    }
+
+    /**
+     * Waits for any one of the given awaitables and returns its result.
+     * Analogous to JavaScript's {@code Promise.race()}.
+     */
+    public static Object awaitAny(Object... awaitables) {
+        return AsyncSupport.awaitAny(awaitables);
+    }
+
+    /**
+     * Waits for all given awaitables and returns a list of {@link AwaitResult}
+     * objects. Analogous to JavaScript's {@code Promise.allSettled()}.
+     */
+    public static List<AwaitResult<Object>> awaitAllSettled(Object... awaitables) {
+        return AsyncSupport.awaitAllSettled(awaitables);
+    }
+
+    // ---- for-await support ----------------------------------------------
+
+    /**
+     * Converts an arbitrary source to an {@link AsyncStream} via the adapter
+     * registry. Useful for manual iteration with {@code for await} loops.
+     * Returns an empty stream for {@code null} input.
+     */
+    public static <T> AsyncStream<T> toAsyncStream(Object source) {
+        return AsyncSupport.toAsyncStream(source);
+    }
+
+    // ---- async execution ------------------------------------------------
+
+    /**
+     * Executes the given closure asynchronously on the specified executor,
+     * returning an {@link Awaitable}.
+     */
+    public static <T> Awaitable<T> executeAsync(Closure<T> closure, Executor executor) {
+        return AsyncSupport.executeAsync(closure, executor);
+    }
+
+    /**
+     * Void variant of {@link #executeAsync(Closure, Executor)} for void methods.
+     */
+    public static Awaitable<Void> executeAsyncVoid(Closure<?> closure, Executor executor) {
+        return AsyncSupport.executeAsyncVoid(closure, executor);
+    }
+
+    // ---- exception utilities --------------------------------------------
+
+    /**
+     * Deeply unwraps nested exception wrapper layers to find the original exception.
+     */
+    public static Throwable deepUnwrap(Throwable t) {
+        return AsyncSupport.deepUnwrap(t);
+    }
+
+    // ---- executor configuration -----------------------------------------
+
+    /**
+     * Returns {@code true} if the running JVM supports virtual threads (JDK 21+).
+     */
+    public static boolean isVirtualThreadsAvailable() {
+        return AsyncSupport.isVirtualThreadsAvailable();
+    }
+
+    /**
+     * Returns the current executor used for async operations.
+     */
+    public static Executor getExecutor() {
+        return AsyncSupport.getExecutor();
+    }
+
+    /**
+     * Sets the executor to use for async operations. Pass {@code null}
+     * to reset to the default (virtual thread executor on JDK 21+,
+     * {@code ForkJoinPool.commonPool()} otherwise).
+     */
+    public static void setExecutor(Executor executor) {
+        AsyncSupport.setExecutor(executor);
+    }
+}
diff --git a/src/main/java/groovy/concurrent/Awaitable.java b/src/main/java/groovy/concurrent/Awaitable.java
index c429ae2cdd..6e5dffd3b2 100644
--- a/src/main/java/groovy/concurrent/Awaitable.java
+++ b/src/main/java/groovy/concurrent/Awaitable.java
@@ -18,6 +18,8 @@
  */
 package groovy.concurrent;
 
+import org.apache.groovy.runtime.async.GroovyPromise;
+
 import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ExecutionException;
@@ -35,11 +37,11 @@ import java.util.function.Function;
  * etc.) can integrate by registering an {@link AwaitableAdapter} via
  * {@link AwaitableAdapterRegistry}.
  * <p>
- * The default implementation, {@link GroovyPromise}, delegates to
+ * The default implementation, {@link org.apache.groovy.runtime.async.GroovyPromise GroovyPromise}, delegates to
  * {@link CompletableFuture} but users never need to depend on that detail.
  *
  * @param <T> the result type
- * @see GroovyPromise
+ * @see org.apache.groovy.runtime.async.GroovyPromise
  * @see AwaitableAdapter
  * @since 6.0.0
  */
diff --git a/src/main/java/groovy/concurrent/AwaitableAdapter.java b/src/main/java/groovy/concurrent/AwaitableAdapter.java
index 5a1d52da54..961ddbf5a7 100644
--- a/src/main/java/groovy/concurrent/AwaitableAdapter.java
+++ b/src/main/java/groovy/concurrent/AwaitableAdapter.java
@@ -35,7 +35,7 @@ package groovy.concurrent;
  *     }
  *     public &lt;T&gt; Awaitable&lt;T&gt; toAwaitable(Object source) {
  *         Single&lt;T&gt; single = (Single&lt;T&gt;) source;
- *         return new GroovyPromise&lt;&gt;(single.toCompletionStage().toCompletableFuture());
+ *         return new org.apache.groovy.runtime.async.GroovyPromise&lt;&gt;(single.toCompletionStage().toCompletableFuture());
  *     }
  *     // ... supportsAsyncStream / toAsyncStream for Observable, Flowable, etc.
  * }
diff --git a/src/main/java/groovy/concurrent/AwaitableAdapterRegistry.java b/src/main/java/groovy/concurrent/AwaitableAdapterRegistry.java
index 16968853b5..0f8751b8a8 100644
--- a/src/main/java/groovy/concurrent/AwaitableAdapterRegistry.java
+++ b/src/main/java/groovy/concurrent/AwaitableAdapterRegistry.java
@@ -18,12 +18,15 @@
  */
 package groovy.concurrent;
 
+import org.apache.groovy.runtime.async.GroovyPromise;
+
 import java.util.Iterator;
 import java.util.List;
 import java.util.ServiceLoader;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.Executor;
 import java.util.concurrent.Future;
 
 /**
@@ -43,6 +46,13 @@ public class AwaitableAdapterRegistry {
 
     private static final List<AwaitableAdapter> ADAPTERS = new CopyOnWriteArrayList<>();
 
+    /**
+     * Optional executor supplier for blocking Future adaptation, to avoid
+     * starving the common pool. Defaults to null; when set, the provided
+     * executor is used instead of {@code CompletableFuture.runAsync}'s default.
+     */
+    private static volatile Executor blockingExecutor;
+
     static {
         // SPI-discovered adapters
         for (AwaitableAdapter adapter : ServiceLoader.load(AwaitableAdapter.class)) {
@@ -56,9 +66,34 @@ public class AwaitableAdapterRegistry {
 
     /**
      * Registers an adapter with higher priority than existing ones.
+     *
+     * @return an {@link AutoCloseable} that, when closed, removes this adapter
+     *         from the registry. Useful for test isolation.
      */
-    public static void register(AwaitableAdapter adapter) {
+    public static AutoCloseable register(AwaitableAdapter adapter) {
         ADAPTERS.add(0, adapter);
+        return () -> ADAPTERS.remove(adapter);
+    }
+
+    /**
+     * Removes the given adapter from the registry.
+     *
+     * @return {@code true} if the adapter was found and removed
+     */
+    public static boolean unregister(AwaitableAdapter adapter) {
+        return ADAPTERS.remove(adapter);
+    }
+
+    /**
+     * Sets the executor used for blocking {@link Future#get()} adaptation.
+     * When non-null, this executor is used instead of the default
+     * {@code ForkJoinPool.commonPool()} to avoid pool starvation when
+     * adapting blocking futures.
+     *
+     * @param executor the executor to use, or {@code null} to use the default
+     */
+    public static void setBlockingExecutor(Executor executor) {
+        blockingExecutor = executor;
     }
 
     /**
@@ -129,7 +164,12 @@ public class AwaitableAdapterRegistry {
                 if (future.isDone()) {
                     completeFrom(cf, future);
                 } else {
-                    CompletableFuture.runAsync(() -> completeFrom(cf, future));
+                    Executor exec = blockingExecutor;
+                    if (exec != null) {
+                        CompletableFuture.runAsync(() -> completeFrom(cf, future), exec);
+                    } else {
+                        CompletableFuture.runAsync(() -> completeFrom(cf, future));
+                    }
                 }
                 return new GroovyPromise<>(cf);
             }
diff --git a/src/main/java/groovy/transform/Async.java b/src/main/java/groovy/transform/Async.java
index f8b0d509b4..e3e13c0403 100644
--- a/src/main/java/groovy/transform/Async.java
+++ b/src/main/java/groovy/transform/Async.java
@@ -27,14 +27,16 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Method annotation to make a method execute asynchronously and return a
- * {@link java.util.concurrent.CompletableFuture CompletableFuture}.
+ * Method annotation to make a method execute asynchronously and return an
+ * {@link groovy.concurrent.Awaitable Awaitable}.
  * <p>
  * When applied to a method, the {@code @Async} transformation will:
  * <ul>
- *   <li>Change the method's return type to {@code CompletableFuture<T>} (where {@code T} is the original return type)</li>
- *   <li>Wrap the method body to execute asynchronously via {@code CompletableFuture.supplyAsync()}</li>
- *   <li>Transform any {@code await(future)} calls within the method to use {@link AsyncUtils#await}</li>
+ *   <li>Change the method's return type to {@code Awaitable<T>} (where {@code T} is the original return type)</li>
+ *   <li>Execute the method body asynchronously via {@link org.apache.groovy.runtime.async.AsyncSupport#executeAsync AsyncSupport.executeAsync}</li>
+ *   <li>Transform any {@code await(future)} calls within the method to use {@link groovy.concurrent.AsyncUtils#await AsyncUtils.await}</li>
+ *   <li>For generator methods containing {@code yield return}, return
+ *       {@link groovy.concurrent.AsyncStream AsyncStream<T>} instead</li>
  * </ul>
  * <p>
  * The {@code await(future)} pattern inside an {@code @Async} method blocks the async thread until the
@@ -44,7 +46,7 @@ import java.lang.annotation.Target;
  * <em>Example usage:</em>
  * <pre>
  * import groovy.transform.Async
- * import java.util.concurrent.CompletableFuture
+ * import groovy.concurrent.Awaitable
  *
  * class DataService {
  *
@@ -55,35 +57,36 @@ import java.lang.annotation.Target;
  *         return [profile: profile, orders: orders]
  *     }
  *
- *     CompletableFuture&lt;Map&gt; fetchProfile(long id) {
- *         CompletableFuture.supplyAsync { [name: "User$id"] }
+ *     {@code @}Async
+ *     Awaitable&lt;Map&gt; fetchProfile(long id) {
+ *         return [name: "User$id"]
  *     }
  *
- *     CompletableFuture&lt;List&gt; fetchOrders(long id) {
- *         CompletableFuture.supplyAsync { ["order1", "order2"] }
+ *     {@code @}Async
+ *     Awaitable&lt;List&gt; fetchOrders(long id) {
+ *         return ["order1", "order2"]
  *     }
  * }
  *
  * def service = new DataService()
- * def future = service.fetchUser(1)       // returns CompletableFuture
- * def result = future.get()               // blocks until complete
+ * def awaitable = service.fetchUser(1)    // returns Awaitable
+ * def result = awaitable.get()            // blocks until complete
  * assert result.profile.name == 'User1'
  * assert result.orders.size() == 2
  * </pre>
  * <p>
- * For ad-hoc async execution without annotating a method, use {@link AsyncUtils#async}:
+ * For ad-hoc async execution without annotating a method, use the {@code async} keyword:
  * <pre>
- * import static groovy.transform.AsyncUtils.*
- *
- * def future = async {
- *     def data = await(fetchFromRemote())
+ * def awaitable = async {
+ *     def data = await fetchFromRemote()
  *     return process(data)
  * }
- * def result = future.get()
+ * def result = awaitable.get()
  * </pre>
  * <p>
- * <b>Custom Executor:</b> By default, tasks run on the {@code ForkJoinPool.commonPool()}.
- * You can specify a custom executor by providing the name of a field in the class:
+ * <b>Custom Executor:</b> By default, tasks run on virtual threads (JDK 21+) or
+ * the {@code ForkJoinPool.commonPool()} (JDK &lt; 21). You can specify a custom
+ * executor by providing the name of a field in the class:
  * <pre>
  * class MyService {
  *     private final Executor myExecutor = Executors.newFixedThreadPool(10)
@@ -99,10 +102,12 @@ import java.lang.annotation.Target;
  * <ul>
  *   <li>Cannot be applied to abstract methods</li>
  *   <li>Cannot be applied to constructors</li>
- *   <li>Cannot be applied to methods that already return {@code CompletableFuture}</li>
+ *   <li>Cannot be applied to methods that already return {@code Awaitable}</li>
  * </ul>
  *
- * @see AsyncUtils
+ * @see groovy.concurrent.AsyncUtils
+ * @see groovy.concurrent.Awaitable
+ * @see groovy.concurrent.AsyncStream
  * @since 6.0.0
  */
 @Documented
diff --git a/src/main/java/groovy/transform/AsyncUtils.java b/src/main/java/groovy/transform/AsyncUtils.java
index 45845f9b09..94c1d92801 100644
--- a/src/main/java/groovy/transform/AsyncUtils.java
+++ b/src/main/java/groovy/transform/AsyncUtils.java
@@ -19,506 +19,105 @@
 package groovy.transform;
 
 import groovy.concurrent.AsyncStream;
-import groovy.concurrent.AsyncStreamGenerator;
 import groovy.concurrent.Awaitable;
-import groovy.concurrent.AwaitableAdapterRegistry;
 import groovy.concurrent.AwaitResult;
-import groovy.concurrent.GroovyPromise;
 import groovy.lang.Closure;
+import org.apache.groovy.runtime.async.AsyncSupport;
 
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles;
-import java.lang.invoke.MethodType;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.UndeclaredThrowableException;
-import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.CancellationException;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
 import java.util.concurrent.CompletionStage;
-import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.Future;
 
 /**
- * Runtime support for the {@code async}/{@code await} language feature and the
- * {@link Async} annotation.
+ * Backward-compatible facade for the async/await runtime support.
  * <p>
- * All overloads of {@code await()} go through the {@link AwaitableAdapterRegistry}
- * so that third-party async types (RxJava {@code Single}, Reactor {@code Mono},
- * etc.) are supported transparently once an adapter is registered.
- * <p>
- * Inside {@code async} methods, the {@code await expr} expression and
- * {@code await(future)} calls are compiled to {@code AsyncUtils.await(expr)}.
- * <p>
- * Standalone usage:
- * <pre>
- * import static groovy.transform.AsyncUtils.*
- *
- * def future = async {
- *     def result = await someAsyncCall()
- *     return result * 2
- * }
- * </pre>
+ * New code should use {@link groovy.concurrent.AsyncUtils} instead.
+ * This class delegates all calls to {@link AsyncSupport}.
  *
- * @see Async
- * @see Awaitable
- * @see AwaitableAdapterRegistry
+ * @deprecated Use {@link groovy.concurrent.AsyncUtils} instead.
+ * @see groovy.concurrent.AsyncUtils
  * @since 6.0.0
  */
+@Deprecated
 public class AsyncUtils {
 
-    /**
-     * {@code true} if the running JVM supports virtual threads (JDK 21+).
-     * Detected once at class-load time via {@link MethodHandle} reflection.
-     */
-    private static final boolean VIRTUAL_THREADS_AVAILABLE;
-
-    private static final Executor VIRTUAL_THREAD_EXECUTOR;
-
-    static {
-        Executor vtExecutor = null;
-        boolean vtAvailable = false;
-        try {
-            MethodHandle mh = MethodHandles.lookup().findStatic(
-                    Executors.class, "newVirtualThreadPerTaskExecutor",
-                    MethodType.methodType(ExecutorService.class));
-            vtExecutor = (Executor) mh.invoke();
-            vtAvailable = true;
-        } catch (Throwable ignored) {
-            // JDK < 21 — virtual threads not available
-        }
-        VIRTUAL_THREAD_EXECUTOR = vtExecutor;
-        VIRTUAL_THREADS_AVAILABLE = vtAvailable;
-    }
-
-    private static volatile Executor defaultExecutor =
-            VIRTUAL_THREADS_AVAILABLE ? VIRTUAL_THREAD_EXECUTOR : ForkJoinPool.commonPool();
-
     private AsyncUtils() { }
 
-    // ---- await overloads ------------------------------------------------
-
-    /**
-     * Awaits the result of an {@link Awaitable}.
-     * <p>
-     * Exception handling follows the same principle as C# and
-     * JavaScript: the <em>original</em> exception is rethrown transparently,
-     * even if it is a checked exception. Wrapper layers
-     * ({@link ExecutionException}, {@link CompletionException}) are fully
-     * stripped so that {@code try/catch} blocks around {@code await} work
-     * with the actual exception type.
-     */
     public static <T> T await(Awaitable<T> awaitable) {
-        try {
-            return awaitable.get();
-        } catch (ExecutionException e) {
-            throw rethrowUnwrapped(e);
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new CancellationException("Interrupted while awaiting");
-        }
+        return AsyncSupport.await(awaitable);
     }
 
-    /**
-     * Awaits the result of a {@link CompletableFuture}.
-     */
     public static <T> T await(CompletableFuture<T> future) {
-        try {
-            return future.join();
-        } catch (CompletionException e) {
-            throw rethrowUnwrapped(e);
-        } catch (CancellationException e) {
-            throw e;
-        }
+        return AsyncSupport.await(future);
     }
 
-    /**
-     * Awaits the result of a {@link CompletionStage}.
-     */
     public static <T> T await(CompletionStage<T> stage) {
-        return await(stage.toCompletableFuture());
+        return AsyncSupport.await(stage);
     }
 
-    /**
-     * Awaits the result of a {@link Future}.
-     */
     public static <T> T await(Future<T> future) {
-        if (future instanceof CompletableFuture<T> cf) {
-            return await(cf);
-        }
-        try {
-            return future.get();
-        } catch (ExecutionException e) {
-            throw rethrowUnwrapped(e);
-        } catch (CancellationException e) {
-            throw e;
-        } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new CancellationException("Interrupted while awaiting future");
-        }
+        return AsyncSupport.await(future);
     }
 
-    /**
-     * Awaits an arbitrary object by adapting it to {@link Awaitable} via the
-     * {@link AwaitableAdapterRegistry}. This is the fallback overload called
-     * by the {@code await} expression when the type is not statically known.
-     */
-    @SuppressWarnings("unchecked")
     public static <T> T await(Object source) {
-        if (source == null) return null;
-        if (source instanceof Awaitable) return await((Awaitable<T>) source);
-        if (source instanceof CompletableFuture) return await((CompletableFuture<T>) source);
-        if (source instanceof CompletionStage) return await((CompletionStage<T>) source);
-        if (source instanceof Future) return await((Future<T>) source);
-        return await(AwaitableAdapterRegistry.<T>toAwaitable(source));
+        return AsyncSupport.await(source);
     }
 
-    // ---- async ----------------------------------------------------------
-
-    /**
-     * Executes the given closure asynchronously on the specified executor,
-     * returning an {@link Awaitable}. This is the <b>unified entry point</b>
-     * used by both the AST transformation ({@code @Async} methods) and the
-     * runtime ({@code async} closures/lambdas).
-     * <p>
-     * Exceptions thrown inside the closure are wrapped in
-     * {@link CompletionException} (via {@link #wrapForFuture}) so that the
-     * {@code await} methods can unwrap them transparently.
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> Awaitable<T> executeAsync(Closure<T> closure, Executor executor) {
-        return GroovyPromise.of(CompletableFuture.supplyAsync(() -> {
-            try {
-                return closure.call();
-            } catch (Throwable t) {
-                throw wrapForFuture(t);
-            }
-        }, executor));
-    }
-
-    /**
-     * Void variant of {@link #executeAsync(Closure, Executor)} for
-     * {@code @Async void} methods.
-     */
-    public static Awaitable<Void> executeAsyncVoid(Closure<?> closure, Executor executor) {
-        return GroovyPromise.of(CompletableFuture.runAsync(() -> {
-            try {
-                closure.call();
-            } catch (Throwable t) {
-                throw wrapForFuture(t);
-            }
-        }, executor));
-    }
-
-    /**
-     * Executes the given closure asynchronously using the default executor,
-     * returning an {@link Awaitable}.
-     */
-    @SuppressWarnings("unchecked")
     public static <T> Awaitable<T> async(Closure<T> closure) {
-        return executeAsync(closure, defaultExecutor);
-    }
-
-    /**
-     * Wraps a closure so that calling it executes the body asynchronously
-     * and returns an {@link Awaitable}. This is used by the {@code async}
-     * keyword on closures/lambdas that have parameters:
-     * <pre>
-     *   def asyncAdd = async { x, y -&gt; x + y }
-     *   def result = await asyncAdd(1, 2) // Awaitable&lt;Integer&gt;
-     * </pre>
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> Closure<Awaitable<T>> wrapAsync(Closure<T> closure) {
-        return new Closure<Awaitable<T>>(closure.getOwner(), closure.getThisObject()) {
-            @SuppressWarnings("unused")
-            public Awaitable<T> doCall(Object... args) {
-                return GroovyPromise.of(CompletableFuture.supplyAsync(() -> {
-                    try {
-                        return closure.call(args);
-                    } catch (Throwable t) {
-                        throw wrapForFuture(t);
-                    }
-                }, defaultExecutor));
-            }
-        };
+        return AsyncSupport.async(closure);
     }
 
-    /**
-     * Wraps a generator closure (containing {@code yield return}) so that
-     * calling it returns an {@link groovy.concurrent.AsyncStream}. This is
-     * used by the {@code async} keyword on closures/lambdas with parameters
-     * that contain yield return statements:
-     * <pre>
-     *   def range = async { n -&gt; for (i in 1..n) { yield return i } }
-     *   for await (item in range(5)) { println item }
-     * </pre>
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> Closure<AsyncStream<T>> wrapAsyncGenerator(Closure<?> closure) {
-        return new Closure<AsyncStream<T>>(closure.getOwner(), closure.getThisObject()) {
-            @SuppressWarnings("unused")
-            public AsyncStream<T> doCall(Object... args) {
-                AsyncStreamGenerator<T> gen = new AsyncStreamGenerator<>();
-                CompletableFuture.runAsync(() -> {
-                    try {
-                        Object[] allArgs = new Object[args.length + 1];
-                        allArgs[0] = gen;
-                        System.arraycopy(args, 0, allArgs, 1, args.length);
-                        closure.call(allArgs);
-                        gen.complete();
-                    } catch (Throwable t) {
-                        gen.error(t);
-                    }
-                }, defaultExecutor);
-                return gen;
-            }
-        };
-    }
-
-    // ---- awaitAll / awaitAny / awaitAllSettled ---------------------------
-
-    /**
-     * Waits for all given awaitables and returns their results as a list.
-     * Analogous to JavaScript's {@code Promise.all()}.
-     * <p>
-     * If any awaitable fails, the <em>first</em> encountered exception is
-     * rethrown transparently (unwrapped).
-     */
-    @SuppressWarnings("unchecked")
     public static List<Object> awaitAll(Object... awaitables) {
-        CompletableFuture<?>[] futures = new CompletableFuture[awaitables.length];
-        for (int i = 0; i < awaitables.length; i++) {
-            futures[i] = toCompletableFuture(awaitables[i]);
-        }
-        try {
-            CompletableFuture.allOf(futures).join();
-        } catch (CompletionException e) {
-            throw rethrowUnwrapped(e);
-        }
-        List<Object> results = new ArrayList<>(futures.length);
-        for (CompletableFuture<?> f : futures) {
-            results.add(f.join());
-        }
-        return results;
+        return AsyncSupport.awaitAll(awaitables);
     }
 
-    /**
-     * Waits for any one of the given awaitables and returns its result.
-     * Analogous to JavaScript's {@code Promise.race()}.
-     */
-    @SuppressWarnings("unchecked")
     public static Object awaitAny(Object... awaitables) {
-        CompletableFuture<?>[] futures = new CompletableFuture[awaitables.length];
-        for (int i = 0; i < awaitables.length; i++) {
-            futures[i] = toCompletableFuture(awaitables[i]);
-        }
-        try {
-            return CompletableFuture.anyOf(futures).join();
-        } catch (CompletionException e) {
-            throw rethrowUnwrapped(e);
-        }
+        return AsyncSupport.awaitAny(awaitables);
     }
 
-    /**
-     * Waits for all given awaitables and returns a list of {@link AwaitResult}
-     * objects, each recording either a success value or a failure exception.
-     * Analogous to JavaScript's {@code Promise.allSettled()}.
-     * <p>
-     * Unlike {@link #awaitAll}, this method never throws — all failures are
-     * captured in the returned list so the caller can handle them individually.
-     */
-    @SuppressWarnings("unchecked")
     public static List<AwaitResult<Object>> awaitAllSettled(Object... awaitables) {
-        CompletableFuture<?>[] futures = new CompletableFuture[awaitables.length];
-        for (int i = 0; i < awaitables.length; i++) {
-            futures[i] = toCompletableFuture(awaitables[i]);
-        }
-        // Wait for all to settle (allSettled = allOf on handle'd futures)
-        CompletableFuture.allOf(
-            java.util.Arrays.stream(futures)
-                .map(f -> f.handle((v, t) -> null))
-                .toArray(CompletableFuture[]::new)
-        ).join();
-
-        List<AwaitResult<Object>> results = new ArrayList<>(futures.length);
-        for (CompletableFuture<?> f : futures) {
-            try {
-                results.add(AwaitResult.success(f.join()));
-            } catch (CompletionException e) {
-                results.add(AwaitResult.failure(deepUnwrap(e)));
-            } catch (CancellationException e) {
-                results.add(AwaitResult.failure(e));
-            }
-        }
-        return results;
-    }
-
-    private static CompletableFuture<?> toCompletableFuture(Object source) {
-        if (source instanceof CompletableFuture<?> cf) return cf;
-        if (source instanceof Awaitable<?> a) return a.toCompletableFuture();
-        if (source instanceof CompletionStage<?> cs) return cs.toCompletableFuture();
-        return AwaitableAdapterRegistry.toAwaitable(source).toCompletableFuture();
-    }
-
-    // ---- for-await support ----------------------------------------------
-
-    /**
-     * Converts an arbitrary source to an {@link AsyncStream} via the adapter
-     * registry. Used by the {@code for await} statement's generated code.
-     * <p>
-     * Returns an empty stream for {@code null} input, following Groovy's
-     * null-safe iteration convention.
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> AsyncStream<T> toAsyncStream(Object source) {
-        if (source == null) return AsyncStream.empty();
-        if (source instanceof AsyncStream) return (AsyncStream<T>) source;
-        return AwaitableAdapterRegistry.toAsyncStream(source);
+        return AsyncSupport.awaitAllSettled(awaitables);
     }
 
-    // ---- yield return / async generator ----------------------------------
-
-    /**
-     * Safety overload: if {@code yield return} is used outside an async generator
-     * context (where the compiler hasn't injected {@code $asyncGen}), this 1-arg
-     * overload will be called, producing a clear error message.
-     */
-    public static void yieldReturn(Object value) {
-        throw new IllegalStateException(
-                "yield return can only be used inside an async generator method or closure");
+    public static boolean isVirtualThreadsAvailable() {
+        return AsyncSupport.isVirtualThreadsAvailable();
     }
 
-    /**
-     * Called by the generated code for {@code yield return expr} statements.
-     * Delivers the value to the consumer via the given
-     * {@link AsyncStreamGenerator}.
-     * <p>
-     * The generator is passed explicitly as a synthetic {@code $asyncGen}
-     * parameter injected into the generator closure by the compiler — no
-     * {@link ThreadLocal} is needed.
-     *
-     * @param generator the {@link AsyncStreamGenerator} instance
-     * @param value     the value to yield
-     * @throws IllegalStateException if generator is null (programming error)
-     */
-    public static void yieldReturn(Object generator, Object value) {
-        if (generator == null) {
-            throw new IllegalStateException("yield return used outside of an async generator context");
-        }
-        ((AsyncStreamGenerator<?>) generator).yield(value);
+    public static Executor getExecutor() {
+        return AsyncSupport.getExecutor();
     }
 
-    /**
-     * Creates an {@link AsyncStream} from a generator closure. The closure
-     * receives the {@link AsyncStreamGenerator} as its first argument and
-     * may use {@code yield return} statements to produce elements.
-     * <p>
-     * This method is called by the AST transformation for {@code async}
-     * methods and closures that contain {@code yield return} statements.
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> AsyncStream<T> generateAsyncStream(Closure<?> body) {
-        AsyncStreamGenerator<T> gen = new AsyncStreamGenerator<>();
-        CompletableFuture.runAsync(() -> {
-            try {
-                body.call(gen);
-                gen.complete();
-            } catch (Throwable t) {
-                gen.error(t);
-            }
-        }, defaultExecutor);
-        return gen;
+    public static void setExecutor(Executor executor) {
+        AsyncSupport.setExecutor(executor);
     }
 
-    // ---- executor configuration -----------------------------------------
-
-    /**
-     * Returns {@code true} if the running JVM supports virtual threads (JDK 21+).
-     */
-    public static boolean isVirtualThreadsAvailable() {
-        return VIRTUAL_THREADS_AVAILABLE;
+    public static <T> AsyncStream<T> toAsyncStream(Object source) {
+        return AsyncSupport.toAsyncStream(source);
     }
 
-    public static Executor getExecutor() {
-        return defaultExecutor;
+    public static <T> Awaitable<T> executeAsync(Closure<T> closure, Executor executor) {
+        return AsyncSupport.executeAsync(closure, executor);
     }
 
-    public static void setExecutor(Executor executor) {
-        defaultExecutor = executor != null
-                ? executor
-                : (VIRTUAL_THREADS_AVAILABLE ? VIRTUAL_THREAD_EXECUTOR : ForkJoinPool.commonPool());
+    public static Awaitable<Void> executeAsyncVoid(Closure<?> closure, Executor executor) {
+        return AsyncSupport.executeAsyncVoid(closure, executor);
     }
 
-    // ---- internal -------------------------------------------------------
-
-    /**
-     * Deeply unwraps nested exception wrapper layers to find the original
-     * user exception. Handles:
-     * <ul>
-     *   <li>{@link CompletionException} — from {@code CompletableFuture.join()}</li>
-     *   <li>{@link ExecutionException} — from {@code Future.get()}</li>
-     *   <li>{@link UndeclaredThrowableException} — from Groovy's closure-to-SAM
-     *       proxy when the closure throws a checked exception</li>
-     *   <li>{@link InvocationTargetException} — from reflection-based invocations</li>
-     * </ul>
-     * This handles arbitrary nesting depth that can occur when async operations
-     * are composed through multiple framework layers.
-     */
-    static Throwable deepUnwrap(Throwable t) {
-        Throwable cause = t;
-        while (cause.getCause() != null
-                && (cause instanceof CompletionException
-                    || cause instanceof ExecutionException
-                    || cause instanceof UndeclaredThrowableException
-                    || cause instanceof InvocationTargetException)) {
-            cause = cause.getCause();
-        }
-        return cause;
+    public static <T> AsyncStream<T> generateAsyncStream(Closure<?> body) {
+        return AsyncSupport.generateAsyncStream(body);
     }
 
-    /**
-     * Unwraps and rethrows the original exception transparently using the
-     * "sneaky throw" technique. This is the key to exception transparency:
-     * checked exceptions are rethrown without wrapping, exactly as C#
-     * and JavaScript handle {@code await} failures.
-     * <p>
-     * {@code try { await expr } catch (IOException e) { ... }} works correctly
-     * because the original {@code IOException} is thrown as-is, not wrapped in
-     * {@code RuntimeException}.
-     */
-    private static RuntimeException rethrowUnwrapped(Throwable wrapper) {
-        Throwable cause = deepUnwrap(wrapper);
-        if (cause instanceof Error err) throw err;
-        throw sneakyThrow(cause);
+    public static void yieldReturn(Object value) {
+        AsyncSupport.yieldReturn(value);
     }
 
-    /**
-     * Rethrows a checked exception without wrapping it, using an unchecked
-     * cast trick. The JVM does not actually enforce checked-exception
-     * declarations at the bytecode level — this is a compile-time-only
-     * constraint. This technique is well-established (used by Lombok
-     * runtime, etc.) and is safe.
-     */
-    @SuppressWarnings("unchecked")
-    private static <T extends Throwable> RuntimeException sneakyThrow(Throwable t) throws T {
-        throw (T) t;
+    public static void yieldReturn(Object generator, Object value) {
+        AsyncSupport.yieldReturn(generator, value);
     }
 
-    /**
-     * Wraps a throwable for storage in a {@link CompletableFuture}. Unlike
-     * the old approach of wrapping checked exceptions in {@code RuntimeException},
-     * this uses {@link CompletionException} which is the expected wrapper type
-     * for {@code CompletableFuture} and is always unwrapped by our
-     * {@code await} methods.
-     */
-    private static CompletionException wrapForFuture(Throwable t) {
-        if (t instanceof CompletionException ce) return ce;
-        return new CompletionException(t);
+    public static Throwable deepUnwrap(Throwable t) {
+        return AsyncSupport.deepUnwrap(t);
     }
 }
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 6ff4cca025..3b17636848 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -491,19 +491,20 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         Expression source = (Expression) this.visit(enhCtrl.expression());
         Statement loopBody = this.unpackStatement((Statement) this.visit(ctx.statement()));
 
-        ClassNode asyncUtilsType = ClassHelper.make("groovy.transform.AsyncUtils");
+        ClassNode asyncUtilsType = ClassHelper.make("org.apache.groovy.runtime.async.AsyncSupport");
+        String streamVar = "$__asyncStream__" + (asyncStreamCounter++);
 
-        // def $asyncStream = AsyncUtils.toAsyncStream(source)
+        // def $__asyncStream__N = AsyncUtils.toAsyncStream(source)
         Expression toStreamCall = callX(asyncUtilsType, "toAsyncStream", new ArgumentListExpression(source));
-        ExpressionStatement streamDecl = new ExpressionStatement(declX(varX("$asyncStream"), toStreamCall));
+        ExpressionStatement streamDecl = new ExpressionStatement(declX(varX(streamVar), toStreamCall));
 
-        // while (AsyncUtils.await($asyncStream.moveNext()))
-        Expression moveNextCall = callX(varX("$asyncStream"), "moveNext");
+        // while (AsyncUtils.await($__asyncStream__N.moveNext()))
+        Expression moveNextCall = callX(varX(streamVar), "moveNext");
         Expression awaitCall = callX(asyncUtilsType, "await", new ArgumentListExpression(moveNextCall));
         BooleanExpression condition = new BooleanExpression(awaitCall);
 
-        // def <varName> = $asyncStream.getCurrent()
-        Expression getCurrentCall = callX(varX("$asyncStream"), "getCurrent");
+        // def <varName> = $__asyncStream__N.getCurrent()
+        Expression getCurrentCall = callX(varX(streamVar), "getCurrent");
         ExpressionStatement getItemStmt = new ExpressionStatement(declX(varX(varName, varType), getCurrentCall));
 
         BlockStatement whileBody = block(getItemStmt, loopBody);
@@ -908,7 +909,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     public ExpressionStatement visitYieldReturnStmtAlt(final YieldReturnStmtAltContext ctx) {
         Expression expr = (Expression) this.visit(ctx.expression());
         Expression yieldCall = callX(
-                ClassHelper.make("groovy.transform.AsyncUtils"), "yieldReturn",
+                ClassHelper.make("org.apache.groovy.runtime.async.AsyncSupport"), "yieldReturn",
                 new ArgumentListExpression(expr));
         return configureAST(new ExpressionStatement(yieldCall), ctx);
     }
@@ -2935,7 +2936,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     public Expression visitAwaitExprAlt(final AwaitExprAltContext ctx) {
         Expression expr = (Expression) this.visit(ctx.expression());
         return configureAST(
-                callX(ClassHelper.make("groovy.transform.AsyncUtils"), "await",
+                callX(ClassHelper.make("org.apache.groovy.runtime.async.AsyncSupport"), "await",
                         new ArgumentListExpression(expr)),
                 ctx);
     }
@@ -2946,10 +2947,10 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         boolean hasUserParams = closure.getParameters() != null && closure.getParameters().length > 0;
         boolean hasYieldReturn = containsYieldReturnCalls(closure);
 
-        ClassNode asyncUtils = ClassHelper.make("groovy.transform.AsyncUtils");
+        ClassNode asyncUtils = ClassHelper.make("org.apache.groovy.runtime.async.AsyncSupport");
         if (hasYieldReturn) {
-            // Inject synthetic $asyncGen as first parameter — rebuild closure
-            Parameter genParam = new Parameter(ClassHelper.DYNAMIC_TYPE, "$asyncGen");
+            // Inject synthetic $__asyncGen__ as first parameter — rebuild closure
+            Parameter genParam = new Parameter(ClassHelper.DYNAMIC_TYPE, "$__asyncGen__");
             Parameter[] existingParams = closure.getParameters();
             Parameter[] newParams;
             if (hasUserParams) {
@@ -2962,7 +2963,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
             ClosureExpression genClosure = new ClosureExpression(newParams, closure.getCode());
             genClosure.setVariableScope(closure.getVariableScope());
             genClosure.setSourcePosition(closure);
-            // Transform yieldReturn(expr) → yieldReturn($asyncGen, expr)
+            // Transform yieldReturn(expr) → yieldReturn($__asyncGen__, expr)
             injectGenParamIntoYieldReturnCalls(genClosure.getCode(), genParam);
             String method = hasUserParams ? "wrapAsyncGenerator" : "generateAsyncStream";
             return configureAST(callX(asyncUtils, method, new ArgumentListExpression(genClosure)), ctx);
@@ -2974,7 +2975,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
 
     /**
      * Walks statement tree and transforms {@code AsyncUtils.yieldReturn(expr)} calls to
-     * {@code AsyncUtils.yieldReturn($asyncGen, expr)}, injecting the generator parameter
+     * {@code AsyncUtils.yieldReturn($__asyncGen__, expr)}, injecting the generator parameter
      * as the first argument. Does not descend into nested closures.
      */
     private static void injectGenParamIntoYieldReturnCalls(Statement code, Parameter genParam) {
@@ -2984,8 +2985,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
                 Expression expr = stmt.getExpression();
                 if (expr instanceof org.codehaus.groovy.ast.expr.StaticMethodCallExpression smce
                         && "yieldReturn".equals(smce.getMethod())
-                        && "groovy.transform.AsyncUtils".equals(smce.getOwnerType().getName())) {
-                    VariableExpression genRef = varX("$asyncGen");
+                        && "org.apache.groovy.runtime.async.AsyncSupport".equals(smce.getOwnerType().getName())) {
+                    VariableExpression genRef = varX("$__asyncGen__");
                     genRef.setAccessedVariable(genParam);
                     ArgumentListExpression newArgs = new ArgumentListExpression();
                     newArgs.addExpression(genRef);
@@ -3018,7 +3019,8 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
         closure.getCode().visit(new CodeVisitorSupport() {
             @Override
             public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
-                if ("yieldReturn".equals(call.getMethod())) {
+                if ("yieldReturn".equals(call.getMethod())
+                        && "org.apache.groovy.runtime.async.AsyncSupport".equals(call.getOwnerType().getName())) {
                     found[0] = true;
                 }
                 super.visitStaticMethodCallExpression(call);
@@ -4877,6 +4879,7 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
     private final GroovyLangParser parser;
     private final GroovydocManager groovydocManager;
     private final TryWithResourcesASTTransformation tryWithResourcesASTTransformation;
+    private int asyncStreamCounter;
 
     private final List<ClassNode> classNodeList = new ArrayList<>();
     private final Deque<ClassNode> classNodeStack = new ArrayDeque<>();
diff --git a/src/main/java/groovy/concurrent/AsyncStreamGenerator.java b/src/main/java/org/apache/groovy/runtime/async/AsyncStreamGenerator.java
similarity index 94%
rename from src/main/java/groovy/concurrent/AsyncStreamGenerator.java
rename to src/main/java/org/apache/groovy/runtime/async/AsyncStreamGenerator.java
index 17a19c975d..3bac2d95ca 100644
--- a/src/main/java/groovy/concurrent/AsyncStreamGenerator.java
+++ b/src/main/java/org/apache/groovy/runtime/async/AsyncStreamGenerator.java
@@ -16,7 +16,10 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy.concurrent;
+package org.apache.groovy.runtime.async;
+
+import groovy.concurrent.AsyncStream;
+import groovy.concurrent.Awaitable;
 
 import java.util.concurrent.SynchronousQueue;
 
@@ -33,6 +36,9 @@ import java.util.concurrent.SynchronousQueue;
  * the producer thread blocks at each {@code yield return} until the
  * consumer has consumed the previous element (mirroring C#'s async
  * iterator suspension semantics).
+ * <p>
+ * This class is an internal implementation detail and should not be referenced
+ * directly by user code.
  *
  * @param <T> the element type
  * @since 6.0.0
diff --git a/src/main/java/groovy/transform/AsyncUtils.java b/src/main/java/org/apache/groovy/runtime/async/AsyncSupport.java
similarity index 72%
copy from src/main/java/groovy/transform/AsyncUtils.java
copy to src/main/java/org/apache/groovy/runtime/async/AsyncSupport.java
index 45845f9b09..cefa981c2b 100644
--- a/src/main/java/groovy/transform/AsyncUtils.java
+++ b/src/main/java/org/apache/groovy/runtime/async/AsyncSupport.java
@@ -16,14 +16,12 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy.transform;
+package org.apache.groovy.runtime.async;
 
 import groovy.concurrent.AsyncStream;
-import groovy.concurrent.AsyncStreamGenerator;
 import groovy.concurrent.Awaitable;
 import groovy.concurrent.AwaitableAdapterRegistry;
 import groovy.concurrent.AwaitResult;
-import groovy.concurrent.GroovyPromise;
 import groovy.lang.Closure;
 
 import java.lang.invoke.MethodHandle;
@@ -45,36 +43,25 @@ import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.Future;
 
 /**
- * Runtime support for the {@code async}/{@code await} language feature and the
- * {@link Async} annotation.
+ * Internal runtime support for the {@code async}/{@code await} language feature
+ * and the {@link groovy.transform.Async} annotation.
+ * <p>
+ * This class contains the actual implementation that is called by compiler-generated
+ * code. User code should use {@link groovy.concurrent.AsyncUtils} instead.
  * <p>
  * All overloads of {@code await()} go through the {@link AwaitableAdapterRegistry}
  * so that third-party async types (RxJava {@code Single}, Reactor {@code Mono},
  * etc.) are supported transparently once an adapter is registered.
- * <p>
- * Inside {@code async} methods, the {@code await expr} expression and
- * {@code await(future)} calls are compiled to {@code AsyncUtils.await(expr)}.
- * <p>
- * Standalone usage:
- * <pre>
- * import static groovy.transform.AsyncUtils.*
- *
- * def future = async {
- *     def result = await someAsyncCall()
- *     return result * 2
- * }
- * </pre>
  *
- * @see Async
+ * @see groovy.concurrent.AsyncUtils
+ * @see groovy.transform.Async
  * @see Awaitable
- * @see AwaitableAdapterRegistry
  * @since 6.0.0
  */
-public class AsyncUtils {
+public class AsyncSupport {
 
     /**
      * {@code true} if the running JVM supports virtual threads (JDK 21+).
-     * Detected once at class-load time via {@link MethodHandle} reflection.
      */
     private static final boolean VIRTUAL_THREADS_AVAILABLE;
 
@@ -99,19 +86,12 @@ public class AsyncUtils {
     private static volatile Executor defaultExecutor =
             VIRTUAL_THREADS_AVAILABLE ? VIRTUAL_THREAD_EXECUTOR : ForkJoinPool.commonPool();
 
-    private AsyncUtils() { }
+    private AsyncSupport() { }
 
     // ---- await overloads ------------------------------------------------
 
     /**
      * Awaits the result of an {@link Awaitable}.
-     * <p>
-     * Exception handling follows the same principle as C# and
-     * JavaScript: the <em>original</em> exception is rethrown transparently,
-     * even if it is a checked exception. Wrapper layers
-     * ({@link ExecutionException}, {@link CompletionException}) are fully
-     * stripped so that {@code try/catch} blocks around {@code await} work
-     * with the actual exception type.
      */
     public static <T> T await(Awaitable<T> awaitable) {
         try {
@@ -182,13 +162,7 @@ public class AsyncUtils {
 
     /**
      * Executes the given closure asynchronously on the specified executor,
-     * returning an {@link Awaitable}. This is the <b>unified entry point</b>
-     * used by both the AST transformation ({@code @Async} methods) and the
-     * runtime ({@code async} closures/lambdas).
-     * <p>
-     * Exceptions thrown inside the closure are wrapped in
-     * {@link CompletionException} (via {@link #wrapForFuture}) so that the
-     * {@code await} methods can unwrap them transparently.
+     * returning an {@link Awaitable}. Used by {@code @Async} methods.
      */
     @SuppressWarnings("unchecked")
     public static <T> Awaitable<T> executeAsync(Closure<T> closure, Executor executor) {
@@ -226,12 +200,7 @@ public class AsyncUtils {
 
     /**
      * Wraps a closure so that calling it executes the body asynchronously
-     * and returns an {@link Awaitable}. This is used by the {@code async}
-     * keyword on closures/lambdas that have parameters:
-     * <pre>
-     *   def asyncAdd = async { x, y -&gt; x + y }
-     *   def result = await asyncAdd(1, 2) // Awaitable&lt;Integer&gt;
-     * </pre>
+     * and returns an {@link Awaitable}.
      */
     @SuppressWarnings("unchecked")
     public static <T> Closure<Awaitable<T>> wrapAsync(Closure<T> closure) {
@@ -251,13 +220,7 @@ public class AsyncUtils {
 
     /**
      * Wraps a generator closure (containing {@code yield return}) so that
-     * calling it returns an {@link groovy.concurrent.AsyncStream}. This is
-     * used by the {@code async} keyword on closures/lambdas with parameters
-     * that contain yield return statements:
-     * <pre>
-     *   def range = async { n -&gt; for (i in 1..n) { yield return i } }
-     *   for await (item in range(5)) { println item }
-     * </pre>
+     * calling it returns an {@link AsyncStream}.
      */
     @SuppressWarnings("unchecked")
     public static <T> Closure<AsyncStream<T>> wrapAsyncGenerator(Closure<?> closure) {
@@ -286,9 +249,6 @@ public class AsyncUtils {
     /**
      * Waits for all given awaitables and returns their results as a list.
      * Analogous to JavaScript's {@code Promise.all()}.
-     * <p>
-     * If any awaitable fails, the <em>first</em> encountered exception is
-     * rethrown transparently (unwrapped).
      */
     @SuppressWarnings("unchecked")
     public static List<Object> awaitAll(Object... awaitables) {
@@ -327,11 +287,7 @@ public class AsyncUtils {
 
     /**
      * Waits for all given awaitables and returns a list of {@link AwaitResult}
-     * objects, each recording either a success value or a failure exception.
-     * Analogous to JavaScript's {@code Promise.allSettled()}.
-     * <p>
-     * Unlike {@link #awaitAll}, this method never throws — all failures are
-     * captured in the returned list so the caller can handle them individually.
+     * objects. Analogous to JavaScript's {@code Promise.allSettled()}.
      */
     @SuppressWarnings("unchecked")
     public static List<AwaitResult<Object>> awaitAllSettled(Object... awaitables) {
@@ -339,7 +295,6 @@ public class AsyncUtils {
         for (int i = 0; i < awaitables.length; i++) {
             futures[i] = toCompletableFuture(awaitables[i]);
         }
-        // Wait for all to settle (allSettled = allOf on handle'd futures)
         CompletableFuture.allOf(
             java.util.Arrays.stream(futures)
                 .map(f -> f.handle((v, t) -> null))
@@ -371,9 +326,7 @@ public class AsyncUtils {
     /**
      * Converts an arbitrary source to an {@link AsyncStream} via the adapter
      * registry. Used by the {@code for await} statement's generated code.
-     * <p>
-     * Returns an empty stream for {@code null} input, following Groovy's
-     * null-safe iteration convention.
+     * Returns an empty stream for {@code null} input.
      */
     @SuppressWarnings("unchecked")
     public static <T> AsyncStream<T> toAsyncStream(Object source) {
@@ -386,8 +339,7 @@ public class AsyncUtils {
 
     /**
      * Safety overload: if {@code yield return} is used outside an async generator
-     * context (where the compiler hasn't injected {@code $asyncGen}), this 1-arg
-     * overload will be called, producing a clear error message.
+     * context, this 1-arg overload produces a clear error message.
      */
     public static void yieldReturn(Object value) {
         throw new IllegalStateException(
@@ -396,16 +348,9 @@ public class AsyncUtils {
 
     /**
      * Called by the generated code for {@code yield return expr} statements.
-     * Delivers the value to the consumer via the given
-     * {@link AsyncStreamGenerator}.
-     * <p>
-     * The generator is passed explicitly as a synthetic {@code $asyncGen}
-     * parameter injected into the generator closure by the compiler — no
-     * {@link ThreadLocal} is needed.
      *
      * @param generator the {@link AsyncStreamGenerator} instance
      * @param value     the value to yield
-     * @throws IllegalStateException if generator is null (programming error)
      */
     public static void yieldReturn(Object generator, Object value) {
         if (generator == null) {
@@ -415,12 +360,7 @@ public class AsyncUtils {
     }
 
     /**
-     * Creates an {@link AsyncStream} from a generator closure. The closure
-     * receives the {@link AsyncStreamGenerator} as its first argument and
-     * may use {@code yield return} statements to produce elements.
-     * <p>
-     * This method is called by the AST transformation for {@code async}
-     * methods and closures that contain {@code yield return} statements.
+     * Creates an {@link AsyncStream} from a generator closure.
      */
     @SuppressWarnings("unchecked")
     public static <T> AsyncStream<T> generateAsyncStream(Closure<?> body) {
@@ -458,19 +398,9 @@ public class AsyncUtils {
     // ---- internal -------------------------------------------------------
 
     /**
-     * Deeply unwraps nested exception wrapper layers to find the original
-     * user exception. Handles:
-     * <ul>
-     *   <li>{@link CompletionException} — from {@code CompletableFuture.join()}</li>
-     *   <li>{@link ExecutionException} — from {@code Future.get()}</li>
-     *   <li>{@link UndeclaredThrowableException} — from Groovy's closure-to-SAM
-     *       proxy when the closure throws a checked exception</li>
-     *   <li>{@link InvocationTargetException} — from reflection-based invocations</li>
-     * </ul>
-     * This handles arbitrary nesting depth that can occur when async operations
-     * are composed through multiple framework layers.
+     * Deeply unwraps nested exception wrapper layers to find the original exception.
      */
-    static Throwable deepUnwrap(Throwable t) {
+    public static Throwable deepUnwrap(Throwable t) {
         Throwable cause = t;
         while (cause.getCause() != null
                 && (cause instanceof CompletionException
@@ -483,41 +413,20 @@ public class AsyncUtils {
     }
 
     /**
-     * Unwraps and rethrows the original exception transparently using the
-     * "sneaky throw" technique. This is the key to exception transparency:
-     * checked exceptions are rethrown without wrapping, exactly as C#
-     * and JavaScript handle {@code await} failures.
-     * <p>
-     * {@code try { await expr } catch (IOException e) { ... }} works correctly
-     * because the original {@code IOException} is thrown as-is, not wrapped in
-     * {@code RuntimeException}.
+     * Unwraps and rethrows the original exception transparently.
      */
-    private static RuntimeException rethrowUnwrapped(Throwable wrapper) {
+    static RuntimeException rethrowUnwrapped(Throwable wrapper) {
         Throwable cause = deepUnwrap(wrapper);
         if (cause instanceof Error err) throw err;
         throw sneakyThrow(cause);
     }
 
-    /**
-     * Rethrows a checked exception without wrapping it, using an unchecked
-     * cast trick. The JVM does not actually enforce checked-exception
-     * declarations at the bytecode level — this is a compile-time-only
-     * constraint. This technique is well-established (used by Lombok
-     * runtime, etc.) and is safe.
-     */
     @SuppressWarnings("unchecked")
-    private static <T extends Throwable> RuntimeException sneakyThrow(Throwable t) throws T {
+    static <T extends Throwable> RuntimeException sneakyThrow(Throwable t) throws T {
         throw (T) t;
     }
 
-    /**
-     * Wraps a throwable for storage in a {@link CompletableFuture}. Unlike
-     * the old approach of wrapping checked exceptions in {@code RuntimeException},
-     * this uses {@link CompletionException} which is the expected wrapper type
-     * for {@code CompletableFuture} and is always unwrapped by our
-     * {@code await} methods.
-     */
-    private static CompletionException wrapForFuture(Throwable t) {
+    static CompletionException wrapForFuture(Throwable t) {
         if (t instanceof CompletionException ce) return ce;
         return new CompletionException(t);
     }
diff --git a/src/main/java/groovy/concurrent/GroovyPromise.java b/src/main/java/org/apache/groovy/runtime/async/GroovyPromise.java
similarity index 83%
rename from src/main/java/groovy/concurrent/GroovyPromise.java
rename to src/main/java/org/apache/groovy/runtime/async/GroovyPromise.java
index ba96003ef3..8bb173291a 100644
--- a/src/main/java/groovy/concurrent/GroovyPromise.java
+++ b/src/main/java/org/apache/groovy/runtime/async/GroovyPromise.java
@@ -16,7 +16,9 @@
  *  specific language governing permissions and limitations
  *  under the License.
  */
-package groovy.concurrent;
+package org.apache.groovy.runtime.async;
+
+import groovy.concurrent.Awaitable;
 
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
@@ -33,6 +35,9 @@ import java.util.function.Function;
  * all operations to an underlying {@code CompletableFuture} while keeping the
  * public API limited to the {@code Awaitable} contract, thereby decoupling
  * user code from JDK-specific async APIs.
+ * <p>
+ * This class is an internal implementation detail and should not be referenced
+ * directly by user code. Use the {@link Awaitable} interface instead.
  *
  * @param <T> the result type
  * @see Awaitable
@@ -68,6 +73,18 @@ public class GroovyPromise<T> implements Awaitable<T> {
         return future.isDone();
     }
 
+    /**
+     * Attempts to cancel this computation. Delegates to
+     * {@link CompletableFuture#cancel(boolean) CompletableFuture.cancel(true)}.
+     * <p>
+     * <b>Note:</b> {@code CompletableFuture} cancellation sets the future's state
+     * to cancelled but does <em>not</em> reliably interrupt the underlying thread.
+     * Async work already in progress may continue running in the background.
+     * For cooperative cancellation, check {@link Thread#isInterrupted()} in
+     * long-running async bodies.
+     *
+     * @return {@code true} if the future was successfully cancelled
+     */
     @Override
     public boolean cancel() {
         return future.cancel(true);
diff --git a/src/main/java/org/codehaus/groovy/transform/AsyncASTTransformation.java b/src/main/java/org/codehaus/groovy/transform/AsyncASTTransformation.java
index 89c4bad4e1..5af6fe321d 100644
--- a/src/main/java/org/codehaus/groovy/transform/AsyncASTTransformation.java
+++ b/src/main/java/org/codehaus/groovy/transform/AsyncASTTransformation.java
@@ -21,7 +21,7 @@ package org.codehaus.groovy.transform;
 import groovy.concurrent.AsyncStream;
 import groovy.concurrent.Awaitable;
 import groovy.transform.Async;
-import groovy.transform.AsyncUtils;
+import org.apache.groovy.runtime.async.AsyncSupport;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
@@ -61,9 +61,12 @@ import static org.codehaus.groovy.ast.tools.GenericsUtils.makeClassSafeWithGener
  * Transforms the annotated method so that:
  * <ol>
  *   <li>{@code await(expr)} calls are redirected to {@link AsyncUtils#await}</li>
- *   <li>The method body is wrapped in {@code GroovyPromise.of(CompletableFuture.supplyAsync(...))}
- *       (or {@code runAsync} for void methods)</li>
- *   <li>The return type becomes {@link Awaitable}{@code <T>}</li>
+ *   <li>The method body is executed asynchronously via {@link AsyncUtils#executeAsync}
+ *       (or {@link AsyncUtils#executeAsyncVoid} for {@code void} methods)</li>
+ *   <li>Generator methods (containing {@code yield return}) are transformed to use
+ *       {@link AsyncUtils#generateAsyncStream}, returning an {@link AsyncStream}{@code <T>}</li>
+ *   <li>The return type becomes {@link Awaitable}{@code <T>} (or {@link AsyncStream}{@code <T>}
+ *       for generators)</li>
  * </ol>
  *
  * @since 6.0.0
@@ -76,7 +79,7 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
     private static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
     private static final ClassNode AWAITABLE_TYPE = ClassHelper.make(Awaitable.class);
     private static final ClassNode ASYNC_STREAM_TYPE = ClassHelper.make(AsyncStream.class);
-    private static final ClassNode ASYNC_UTILS_TYPE = ClassHelper.make(AsyncUtils.class);
+    private static final ClassNode ASYNC_UTILS_TYPE = ClassHelper.make(AsyncSupport.class);
 
     @Override
     public void visit(ASTNode[] nodes, SourceUnit source) {
@@ -128,18 +131,18 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
             executorExpr = callX(ASYNC_UTILS_TYPE, "getExecutor", new org.codehaus.groovy.ast.expr.ArgumentListExpression());
         }
 
-        // Step 1: Transform await() method calls to AsyncUtils.await()
+        // Step 1: Transform await() method calls to AsyncSupport.await()
         new AwaitCallTransformer(source).visitMethod(mNode);
 
-        // Step 2: Check if body contains yield return (AsyncUtils.yieldReturn) calls
+        // Step 2: Check if body contains yield return (AsyncSupport.yieldReturn) calls
         Statement transformedBody = mNode.getCode();
         boolean hasYieldReturn = containsYieldReturn(transformedBody, source);
 
         Parameter[] closureParams;
         if (hasYieldReturn) {
-            // Generator: inject $asyncGen as closure parameter so yield return
+            // Generator: inject $__asyncGen__ as closure parameter so yield return
             // can reference it directly — no ThreadLocal needed
-            closureParams = new Parameter[]{ new Parameter(ClassHelper.DYNAMIC_TYPE, "$asyncGen") };
+            closureParams = new Parameter[]{ new Parameter(ClassHelper.DYNAMIC_TYPE, "$__asyncGen__") };
         } else {
             closureParams = Parameter.EMPTY_ARRAY;
         }
@@ -152,10 +155,10 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
         closure.setVariableScope(closureScope);
 
         if (hasYieldReturn) {
-            // Transform yieldReturn(expr) → yieldReturn($asyncGen, expr) in closure body
+            // Transform yieldReturn(expr) → yieldReturn($__asyncGen__, expr) in closure body
             injectGenParamIntoYieldReturnCalls(transformedBody, closureParams[0]);
 
-            // Async generator: wrap body in AsyncUtils.generateAsyncStream { ... }
+            // Async generator: wrap body in AsyncSupport.generateAsyncStream { ... }
             Expression genCall = callX(ASYNC_UTILS_TYPE, "generateAsyncStream", args(closure));
             mNode.setCode(block(returnS(genCall)));
 
@@ -171,7 +174,7 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
             ClassNode streamReturnType = makeClassSafeWithGenerics(ASYNC_STREAM_TYPE, new GenericsType(innerType));
             mNode.setReturnType(streamReturnType);
         } else {
-            // Regular async: delegate to AsyncUtils.executeAsync/executeAsyncVoid
+            // Regular async: delegate to AsyncSupport.executeAsync/executeAsyncVoid
             // This ensures identical exception handling with async closures/lambdas
             boolean isVoid = ClassHelper.isPrimitiveVoid(originalReturnType);
             Expression asyncCall;
@@ -197,8 +200,8 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
     }
 
     /**
-     * Walks statement tree and transforms {@code AsyncUtils.yieldReturn(expr)} calls to
-     * {@code AsyncUtils.yieldReturn($asyncGen, expr)}, injecting the generator parameter
+     * Walks statement tree and transforms {@code AsyncSupport.yieldReturn(expr)} calls to
+     * {@code AsyncSupport.yieldReturn($__asyncGen__, expr)}, injecting the generator parameter
      * as the first argument. Does not descend into nested closures.
      */
     private static void injectGenParamIntoYieldReturnCalls(Statement code, Parameter genParam) {
@@ -208,8 +211,8 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
                 Expression expr = stmt.getExpression();
                 if (expr instanceof StaticMethodCallExpression smce
                         && "yieldReturn".equals(smce.getMethod())
-                        && "groovy.transform.AsyncUtils".equals(smce.getOwnerType().getName())) {
-                    VariableExpression genRef = varX("$asyncGen");
+                        && "org.apache.groovy.runtime.async.AsyncSupport".equals(smce.getOwnerType().getName())) {
+                    VariableExpression genRef = varX("$__asyncGen__");
                     genRef.setAccessedVariable(genParam);
                     ArgumentListExpression newArgs = new ArgumentListExpression();
                     newArgs.addExpression(genRef);
@@ -234,7 +237,7 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
 
     /**
      * Checks whether the given statement tree contains any
-     * {@code AsyncUtils.yieldReturn()} calls, indicating this is
+     * {@code AsyncSupport.yieldReturn()} calls, indicating this is
      * an async generator method (returns {@link AsyncStream}).
      */
     private static boolean containsYieldReturn(Statement body, SourceUnit source) {
@@ -247,7 +250,8 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
             public void visitExpressionStatement(ExpressionStatement stmt) {
                 Expression expr = stmt.getExpression();
                 if (expr instanceof StaticMethodCallExpression smce
-                        && "yieldReturn".equals(smce.getMethod())) {
+                        && "yieldReturn".equals(smce.getMethod())
+                        && "org.apache.groovy.runtime.async.AsyncSupport".equals(smce.getOwnerType().getName())) {
                     found[0] = true;
                 }
                 super.visitExpressionStatement(stmt);
@@ -264,9 +268,9 @@ public class AsyncASTTransformation extends AbstractASTTransformation {
 
     /**
      * Walks the method body and transforms {@code await(expr)} method calls
-     * into {@code AsyncUtils.await(expr)} static calls.  With the new grammar
+     * into {@code AsyncSupport.await(expr)} static calls.  With the new grammar
      * ({@code await expr}), most calls are already compiled to
-     * {@code AsyncUtils.await()} by the parser; this transformer handles the
+     * {@code AsyncSupport.await()} by the parser; this transformer handles the
      * legacy {@code await(expr)} call-style for backward compatibility.
      */
     private static class AwaitCallTransformer extends ClassCodeExpressionTransformer {
diff --git a/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy
index 1589a96051..beb09c1a83 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncAwaitSyntaxTest.groovy
@@ -54,7 +54,7 @@ class AsyncAwaitSyntaxTest {
                 async greet() { "hello" }
             }
             def r = new Svc().greet()
-            assert r instanceof Awaitable // its default implementation is `groovy.concurrent.GroovyPromise`
+            assert r instanceof Awaitable // its default implementation is `org.apache.groovy.runtime.async.GroovyPromise`
             assert r.get() == "hello"
         '''
     }
@@ -1317,12 +1317,12 @@ class AsyncAwaitSyntaxTest {
                 }
             }
 
-            groovy.transform.AsyncUtils.setExecutor(Svc.executor)
+            groovy.concurrent.AsyncUtils.setExecutor(Svc.executor)
             try {
                 def name = new Svc().threadInfo().get()
                 assert name.contains("pool")
             } finally {
-                groovy.transform.AsyncUtils.setExecutor(null)
+                groovy.concurrent.AsyncUtils.setExecutor(null)
                 Svc.executor.shutdown()
             }
         '''
@@ -2098,7 +2098,7 @@ class AsyncAwaitSyntaxTest {
         assertScript '''
             // yield return outside async method should fail at runtime
             try {
-                groovy.transform.AsyncUtils.yieldReturn("oops")
+                org.apache.groovy.runtime.async.AsyncSupport.yieldReturn("oops")
                 assert false : "expected exception"
             } catch (IllegalStateException e) {
                 assert e.message.contains("yield return")
diff --git a/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy
index 7a717cb20b..80b9faa7ad 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncClosureLambdaTest.groovy
@@ -44,7 +44,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureImmediateExecution() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def result = async { 42 }
@@ -56,7 +56,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithExplicitEmptyParams() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def result = async { -> "hello" }
@@ -68,7 +68,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureRunsOnSeparateThread() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def mainThread = Thread.currentThread().name
             def awaitable = async { Thread.currentThread().name }
@@ -80,7 +80,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithComputation() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def awaitable = async {
                 def sum = 0
@@ -95,7 +95,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureWithAwaitInside() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def fetchValue() { return 10 }
@@ -111,7 +111,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testMultipleAsyncClosuresParallel() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def a = async { Thread.sleep(50); 1 }
             def b = async { Thread.sleep(50); 2 }
@@ -125,7 +125,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureAssignedToVariable() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def task = async { 100 + 200 }
@@ -139,7 +139,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureReturnsNull() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def result = async { null }
             assert await(result) == null
@@ -153,7 +153,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithParams() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncAdd = async { x, y -> x + y }
             def result = asyncAdd(10, 20)
@@ -164,7 +164,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithSingleParam() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncDouble = async { n -> n * 2 }
             assert await(asyncDouble(21)) == 42
@@ -174,7 +174,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithParamsCalledMultipleTimes() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncSquare = async { n -> n * n }
             def r1 = await(asyncSquare(3))
@@ -201,7 +201,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithParamsAndStringOps() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncConcat = async { a, b, sep -> "${a}${sep}${b}" }
             assert await(asyncConcat("hello", "world", " ")) == "hello world"
@@ -211,7 +211,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosurePassedAsArgument() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def applyAsync(fn, x) {
                 return await(fn(x))
@@ -225,7 +225,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureStoredInCollection() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def ops = [
                 add: async { a, b -> a + b },
@@ -246,7 +246,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncLambdaWithSingleParam() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncDouble = async (n) -> { n * 2 }
             assert await(asyncDouble(21)) == 42
@@ -256,7 +256,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncLambdaWithMultipleParams() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncAdd = async (a, b) -> { a + b }
             assert await(asyncAdd(10, 32)) == 42
@@ -266,7 +266,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncLambdaWithSingleExpression() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncInc = async (n) -> n + 1
             assert await(asyncInc(41)) == 42
@@ -287,7 +287,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncLambdaCalledMultipleTimes() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def factorial = async (n) -> {
                 def result = 1
@@ -308,7 +308,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureGeneratorImmediate() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.AsyncStream
 
             def stream = async {
@@ -330,7 +330,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureGeneratorWithForAwait() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def collect() {
@@ -354,7 +354,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureGeneratorWithParams() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def collect() {
@@ -378,7 +378,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureGeneratorWithParamsCalledMultipleTimes() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def test() {
@@ -408,7 +408,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncLambdaGeneratorWithForAwait() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def collect() {
@@ -436,7 +436,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureExceptionTransparency() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def caller() {
@@ -457,7 +457,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureWithParamsExceptionTransparency() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def caller() {
@@ -481,7 +481,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncLambdaExceptionHandling() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def caller() {
@@ -502,7 +502,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureGeneratorExceptionPropagation() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def caller() {
@@ -533,7 +533,7 @@ final class AsyncClosureLambdaTest {
     void testAwaitAsyncClosureInAsyncMethod() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def compute() {
@@ -550,7 +550,7 @@ final class AsyncClosureLambdaTest {
     void testAwaitAsyncClosureWithParamsInAsyncMethod() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def compute() {
@@ -567,7 +567,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosuresComposed() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def pipeline() {
@@ -592,7 +592,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithListResult() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def task = async { [1, 2, 3].collect { it * it } }
             assert await(task) == [1, 4, 9]
@@ -602,7 +602,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithMapResult() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def task = async { [name: "Groovy", version: 6] }
             def result = await(task)
@@ -614,7 +614,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithStringInterpolation() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def greet = async { name -> "Hello, ${name}!" }
             assert await(greet("World")) == "Hello, World!"
@@ -628,7 +628,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAwaitAllWithAsyncClosures() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def results = awaitAll(
                 async { 1 },
@@ -642,7 +642,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAwaitAnyWithAsyncClosures() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def result = awaitAny(
                 async { Thread.sleep(100); "slow" },
@@ -656,7 +656,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAwaitAllSettledWithAsyncClosures() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def results = awaitAllSettled(
                 async { 42 },
@@ -676,7 +676,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureCapturingOuterVariable() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def x = 100
             def task = async { x + 1 }
@@ -687,7 +687,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithParamCapturingOuter() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def base = 1000
             def asyncAdd = async { n -> base + n }
@@ -698,7 +698,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testNestedAsyncClosures() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def outer = async {
                 def inner = async { 42 }
@@ -711,7 +711,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureInLoopBody() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def tasks = (1..5).collect { n -> async { n * n } }
             def results = awaitAll(tasks as Object[])
@@ -722,7 +722,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithMethodCallChaining() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def task = async { "hello world" }
@@ -735,7 +735,7 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureWithExceptionally() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def task = async { throw new RuntimeException("boom") }
             def recovered = task.exceptionally { err -> "recovered: ${err.message}" }
@@ -747,7 +747,7 @@ final class AsyncClosureLambdaTest {
     void testAsyncClosureGeneratorFactoryPattern() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             @Async
             def collect() {
@@ -775,10 +775,10 @@ final class AsyncClosureLambdaTest {
     @Test
     void testAsyncClosureCancellation() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CancellationException
 
-            def task = async { Thread.sleep(10_000); 42 }
+            def task = async { Thread.sleep(100); 42 }
             task.cancel()
             assert task.isCancelled()
             assert task.isCompletedExceptionally()
diff --git a/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy
index e63783ee73..bb941dd403 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncExceptionHandlingTest.groovy
@@ -48,7 +48,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitIOExceptionTransparency() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async fetchData() {
                 throw new java.io.IOException("disk failure")
@@ -71,7 +71,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitSQLExceptionTransparency() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async queryDb() {
                 throw new java.sql.SQLException("connection refused", "08001")
@@ -94,7 +94,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitCustomCheckedExceptionTransparency() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class BusinessException extends Exception {
                 int code
@@ -125,7 +125,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitRuntimeExceptionTransparency() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async badOp() {
                 throw new IllegalArgumentException("bad arg")
@@ -148,7 +148,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitErrorPropagation() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async oom() {
                 throw new OutOfMemoryError("test OOM")
@@ -175,7 +175,7 @@ final class AsyncExceptionHandlingTest {
     void testDeepUnwrapCompletionException() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletableFuture
             import java.util.concurrent.CompletionException
 
@@ -201,7 +201,7 @@ final class AsyncExceptionHandlingTest {
     void testDeepUnwrapExecutionException() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletableFuture
             import java.util.concurrent.CompletionException
             import java.util.concurrent.ExecutionException
@@ -234,11 +234,11 @@ final class AsyncExceptionHandlingTest {
     void testCancelAwaitable() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CancellationException
 
             async slowTask() {
-                Thread.sleep(10_000)
+                Thread.sleep(100)
                 return 42
             }
 
@@ -266,7 +266,7 @@ final class AsyncExceptionHandlingTest {
     void testCancelAlreadyCompletedIsNoOp() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def result = Awaitable.of(42)
@@ -298,7 +298,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllWithFailureThrowsOriginal() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async success() { return 1 }
 
@@ -321,7 +321,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllWithAwaitableObjects() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async a() { return 10 }
@@ -342,7 +342,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAnyWithFailure() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -362,7 +362,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAnyWithMixedSourceTypes() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
             import java.util.concurrent.CompletableFuture
 
@@ -386,7 +386,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllSettledMixedResults() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -415,7 +415,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllSettledAllSuccess() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -434,7 +434,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllSettledAllFailure() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -457,7 +457,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllSettledGetOrElse() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -476,7 +476,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllSettledNeverThrows() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -496,7 +496,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllSettledWithCancelledTask() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
             import java.util.concurrent.CancellationException
             import java.util.concurrent.CompletableFuture
@@ -526,7 +526,7 @@ final class AsyncExceptionHandlingTest {
     void testGeneratorCheckedExceptionPropagation() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async failingGenerator() {
                 yield return 1
@@ -554,7 +554,7 @@ final class AsyncExceptionHandlingTest {
     void testGeneratorRuntimeExceptionPropagation() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async failingGenerator() {
                 yield return "a"
@@ -585,7 +585,7 @@ final class AsyncExceptionHandlingTest {
     void testTryCatchFinallyInAsync() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async riskyOp() {
                 throw new java.io.IOException("test")
@@ -613,7 +613,7 @@ final class AsyncExceptionHandlingTest {
     void testMultipleCatchBlocks() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async throwIO() { throw new java.io.IOException("io") }
@@ -644,7 +644,7 @@ final class AsyncExceptionHandlingTest {
     void testNestedTryCatch() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async fail1() { throw new java.io.IOException("first") }
 
@@ -673,7 +673,7 @@ final class AsyncExceptionHandlingTest {
     void testFinallyRunsOnSuccess() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -699,7 +699,7 @@ final class AsyncExceptionHandlingTest {
     void testExceptionChainingThreeDeep() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async level3() {
                 throw new java.io.IOException("root cause")
@@ -730,7 +730,7 @@ final class AsyncExceptionHandlingTest {
     void testExceptionTransformAcrossMultipleAwaits() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async step1() {
                 throw new java.io.IOException("step1 failed")
@@ -766,7 +766,7 @@ final class AsyncExceptionHandlingTest {
     void testExceptionallyRecovery() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async failing() {
@@ -789,7 +789,7 @@ final class AsyncExceptionHandlingTest {
     void testExceptionallySeesUnwrappedCause() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
             import java.util.concurrent.CompletableFuture
             import java.util.concurrent.CompletionException
@@ -800,7 +800,7 @@ final class AsyncExceptionHandlingTest {
                 cf.completeExceptionally(
                     new CompletionException(new java.io.IOException("wrapped"))
                 )
-                def task = new groovy.concurrent.GroovyPromise(cf)
+                def task = new org.apache.groovy.runtime.async.GroovyPromise(cf)
                 def recovered = task.exceptionally { err ->
                     // Should receive the IOException, not CompletionException
                     return err.class.simpleName + ":" + err.message
@@ -820,7 +820,7 @@ final class AsyncExceptionHandlingTest {
     void testThenDoesNotRunOnFailure() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -845,7 +845,7 @@ final class AsyncExceptionHandlingTest {
     @Test
     void testDirectAsyncClosureExceptionHandling() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async caller() {
                 def task = async {
@@ -859,7 +859,7 @@ final class AsyncExceptionHandlingTest {
                 }
             }
 
-            assert groovy.transform.AsyncUtils.await(caller()) == "from closure"
+            assert groovy.concurrent.AsyncUtils.await(caller()) == "from closure"
         '''
     }
 
@@ -917,7 +917,7 @@ final class AsyncExceptionHandlingTest {
     void testInterruptedAwaitThrowsCancellation() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CancellationException
             import groovy.concurrent.Awaitable
 
@@ -950,7 +950,7 @@ final class AsyncExceptionHandlingTest {
     void testExceptionInForAwaitBody() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async generate() {
                 yield return 1
@@ -983,7 +983,7 @@ final class AsyncExceptionHandlingTest {
     void testRecoverAndContinue() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async fetchWithRetry() {
@@ -1003,7 +1003,7 @@ final class AsyncExceptionHandlingTest {
     @Test
     void testDeepUnwrapUtility() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletionException
             import java.util.concurrent.ExecutionException
 
@@ -1021,7 +1021,7 @@ final class AsyncExceptionHandlingTest {
     @Test
     void testDeepUnwrapStopsAtNonWrapper() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def ex = new IllegalArgumentException("not wrapped")
             assert deepUnwrap(ex).is(ex)
@@ -1031,7 +1031,7 @@ final class AsyncExceptionHandlingTest {
     @Test
     void testDeepUnwrapHandlesNullCause() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletionException
 
             // CompletionException with null cause
@@ -1049,7 +1049,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitAllSettledWithCompletableFutures() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletableFuture
 
             async caller() {
@@ -1076,7 +1076,7 @@ final class AsyncExceptionHandlingTest {
     void testExceptionWithNullMessage() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             async throwNull() {
                 throw new RuntimeException((String) null)
@@ -1104,7 +1104,7 @@ final class AsyncExceptionHandlingTest {
     void testSequentialAwaitsWithDifferentExceptions() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
@@ -1143,7 +1143,7 @@ final class AsyncExceptionHandlingTest {
     void testAwaitOnFailedAwaitable() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             async caller() {
diff --git a/src/test/groovy/org/codehaus/groovy/transform/AsyncFrameworkIntegrationTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/AsyncFrameworkIntegrationTest.groovy
index 9dd2824919..9813944e58 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncFrameworkIntegrationTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncFrameworkIntegrationTest.groovy
@@ -22,8 +22,8 @@ import groovy.concurrent.AsyncStream
 import groovy.concurrent.Awaitable
 import groovy.concurrent.AwaitableAdapter
 import groovy.concurrent.AwaitableAdapterRegistry
-import groovy.concurrent.GroovyPromise
-import static groovy.transform.AsyncUtils.*
+import org.apache.groovy.runtime.async.GroovyPromise
+import static groovy.concurrent.AsyncUtils.*
 import io.reactivex.rxjava3.core.Flowable
 import io.reactivex.rxjava3.core.Maybe
 import io.reactivex.rxjava3.core.Observable
@@ -62,6 +62,8 @@ class AsyncFrameworkIntegrationTest {
     @AfterEach
     void resetExecutor() {
         setExecutor(null)
+        if (rxJavaAdapter != null) AwaitableAdapterRegistry.unregister(rxJavaAdapter)
+        if (reactorAdapter != null) AwaitableAdapterRegistry.unregister(reactorAdapter)
     }
 
     // =====================================================================
diff --git a/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy
index b64248f330..c50ecd4809 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncTransformTest.groovy
@@ -28,11 +28,11 @@ import java.util.concurrent.Executors
 
 import static groovy.test.GroovyAssert.assertScript
 import static groovy.test.GroovyAssert.shouldFail
-import static groovy.transform.AsyncUtils.async
-import static groovy.transform.AsyncUtils.await
-import static groovy.transform.AsyncUtils.awaitAll
-import static groovy.transform.AsyncUtils.awaitAny
-import static groovy.transform.AsyncUtils.setExecutor
+import static groovy.concurrent.AsyncUtils.async
+import static groovy.concurrent.AsyncUtils.await
+import static groovy.concurrent.AsyncUtils.awaitAll
+import static groovy.concurrent.AsyncUtils.awaitAny
+import static groovy.concurrent.AsyncUtils.setExecutor
 
 /**
  * Tests for async/await: @Async annotation, async/await keywords,
@@ -691,7 +691,7 @@ class AsyncTransformTest {
     @Test
     void testAsyncClosureWithStaticImport() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletableFuture
 
             def future = async {
@@ -706,7 +706,7 @@ class AsyncTransformTest {
     @Test
     void testAsyncClosureExceptionHandling() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.ExecutionException
 
             def future = async {
@@ -830,7 +830,7 @@ class AsyncTransformTest {
     void testAsyncAwaitAllPattern() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletableFuture
 
             class Service {
@@ -1066,7 +1066,7 @@ class AsyncTransformTest {
     void testAwaitableInterface() {
         assertScript '''
             import groovy.concurrent.Awaitable
-            import groovy.concurrent.GroovyPromise
+            import org.apache.groovy.runtime.async.GroovyPromise
             import java.util.concurrent.CompletableFuture
 
             // Test Awaitable.of()
@@ -1089,7 +1089,7 @@ class AsyncTransformTest {
     void testGroovyPromiseThen() {
         assertScript '''
             import groovy.concurrent.Awaitable
-            import groovy.concurrent.GroovyPromise
+            import org.apache.groovy.runtime.async.GroovyPromise
             import java.util.concurrent.CompletableFuture
 
             def p = GroovyPromise.of(CompletableFuture.supplyAsync { 10 })
@@ -1102,7 +1102,7 @@ class AsyncTransformTest {
     void testGroovyPromiseThenCompose() {
         assertScript '''
             import groovy.concurrent.Awaitable
-            import groovy.concurrent.GroovyPromise
+            import org.apache.groovy.runtime.async.GroovyPromise
             import java.util.concurrent.CompletableFuture
 
             def p = GroovyPromise.of(CompletableFuture.supplyAsync { 5 })
@@ -1116,7 +1116,7 @@ class AsyncTransformTest {
     @Test
     void testGroovyPromiseExceptionally() {
         assertScript '''
-            import groovy.concurrent.GroovyPromise
+            import org.apache.groovy.runtime.async.GroovyPromise
             import java.util.concurrent.CompletableFuture
 
             def p = GroovyPromise.of(CompletableFuture.supplyAsync { throw new RuntimeException("fail") })
@@ -1128,7 +1128,7 @@ class AsyncTransformTest {
     @Test
     void testAwaitableToCompletableFuture() {
         assertScript '''
-            import groovy.concurrent.GroovyPromise
+            import org.apache.groovy.runtime.async.GroovyPromise
             import java.util.concurrent.CompletableFuture
 
             def p = GroovyPromise.of(CompletableFuture.completedFuture("interop"))
@@ -1170,7 +1170,7 @@ class AsyncTransformTest {
             import groovy.concurrent.Awaitable
             import groovy.concurrent.AwaitableAdapter
             import groovy.concurrent.AwaitableAdapterRegistry
-            import groovy.concurrent.GroovyPromise
+            import org.apache.groovy.runtime.async.GroovyPromise
             import java.util.concurrent.CompletableFuture
 
             // Simulate a custom async type
@@ -1199,7 +1199,7 @@ class AsyncTransformTest {
             import groovy.concurrent.Awaitable
             import groovy.concurrent.AwaitableAdapter
             import groovy.concurrent.AwaitableAdapterRegistry
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class Deferred {
                 final Object result
@@ -1396,4 +1396,309 @@ class AsyncTransformTest {
             assert svc.combined().get() == "annotation+keyword"
         '''
     }
+
+    // ==== Coverage improvement tests ====
+
+    @Test
+    void testAwaitableAdapterRegistryUnregister() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+
+            class FakePromise { String val }
+
+            def adapter = new AwaitableAdapter() {
+                boolean supportsAwaitable(Class<?> type) { FakePromise.isAssignableFrom(type) }
+                def <T> Awaitable<T> toAwaitable(Object source) { Awaitable.of(((FakePromise) source).val) }
+            }
+
+            AwaitableAdapterRegistry.register(adapter)
+            assert await(new FakePromise(val: "hello")) == "hello"
+
+            assert AwaitableAdapterRegistry.unregister(adapter)
+            assert !AwaitableAdapterRegistry.unregister(adapter) // already removed
+
+            try {
+                AwaitableAdapterRegistry.toAwaitable(new FakePromise(val: "x"))
+                assert false : "should have thrown"
+            } catch (IllegalArgumentException expected) {
+                assert expected.message.contains("No AwaitableAdapter")
+            }
+        '''
+    }
+
+    @Test
+    void testAwaitableAdapterRegistryRegisterReturnsAutoCloseable() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+
+            class Token { int id }
+
+            def handle = AwaitableAdapterRegistry.register(new AwaitableAdapter() {
+                boolean supportsAwaitable(Class<?> type) { Token.isAssignableFrom(type) }
+                def <T> Awaitable<T> toAwaitable(Object source) { Awaitable.of(((Token) source).id) }
+            })
+
+            assert await(new Token(id: 42)) == 42
+            handle.close() // unregister via AutoCloseable
+
+            try {
+                AwaitableAdapterRegistry.toAwaitable(new Token(id: 1))
+                assert false
+            } catch (IllegalArgumentException expected) { }
+        '''
+    }
+
+    @Test
+    void testAwaitableAdapterRegistrySetBlockingExecutor() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+            import java.util.concurrent.*
+
+            def customExecutor = Executors.newSingleThreadExecutor()
+            try {
+                AwaitableAdapterRegistry.setBlockingExecutor(customExecutor)
+                // Create a plain Future (not CompletableFuture) to exercise blocking path
+                def pool = Executors.newSingleThreadExecutor()
+                Future<String> future = pool.submit({ "from-blocking-future" } as Callable)
+                Thread.sleep(50) // let it complete
+                def result = await(future)
+                assert result == "from-blocking-future"
+                pool.shutdown()
+            } finally {
+                AwaitableAdapterRegistry.setBlockingExecutor(null)
+                customExecutor.shutdown()
+            }
+        '''
+    }
+
+    @Test
+    void testAwaitableAdapterRegistryToAsyncStreamWithIterator() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+
+            // Test with Iterator directly
+            def iter = [10, 20, 30].iterator()
+            AsyncStream stream = AwaitableAdapterRegistry.toAsyncStream(iter)
+            def results = []
+            while (await(stream.moveNext())) {
+                results << stream.getCurrent()
+            }
+            assert results == [10, 20, 30]
+        '''
+    }
+
+    @Test
+    void testAwaitableAdapterRegistryToAsyncStreamUnsupportedType() {
+        assertScript '''
+            import groovy.concurrent.*
+
+            try {
+                AwaitableAdapterRegistry.toAsyncStream("a string")
+                assert false : "should throw"
+            } catch (IllegalArgumentException expected) {
+                assert expected.message.contains("No AsyncStream adapter")
+            }
+        '''
+    }
+
+    @Test
+    void testAwaitableAdapterRegistryToAwaitableUnsupportedType() {
+        assertScript '''
+            import groovy.concurrent.*
+
+            try {
+                AwaitableAdapterRegistry.toAwaitable("plain string")
+                assert false : "should throw"
+            } catch (IllegalArgumentException expected) {
+                assert expected.message.contains("No AwaitableAdapter")
+            }
+        '''
+    }
+
+    @Test
+    void testAwaitableAdapterRegistryPlainFutureNotDone() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+            import java.util.concurrent.*
+
+            // Create a Future that completes with a delay (not done at adaptation time)
+            def pool = Executors.newSingleThreadExecutor()
+            Future<Integer> future = pool.submit({
+                Thread.sleep(50)
+                return 99
+            } as Callable)
+            // Future is NOT done yet at this point
+            def result = await(future)
+            assert result == 99
+            pool.shutdown()
+        '''
+    }
+
+    @Test
+    void testAwaitableAdapterRegistryPlainFutureDone() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+            import java.util.concurrent.*
+
+            // Create a Future that is already done
+            def pool = Executors.newSingleThreadExecutor()
+            Future<Integer> future = pool.submit({ 77 } as Callable)
+            Thread.sleep(100)
+            assert future.isDone()
+            def result = await(future)
+            assert result == 77
+            pool.shutdown()
+        '''
+    }
+
+    @Test
+    void testAsyncStreamGeneratorErrorPropagation() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+
+            @groovy.transform.Async
+            def failingGenerator() {
+                yield return "ok"
+                throw new IOException("generator failed")
+            }
+
+            def stream = failingGenerator()
+            assert await(stream.moveNext()) == true
+            assert stream.getCurrent() == "ok"
+
+            try {
+                await(stream.moveNext())
+                assert false : "should throw"
+            } catch (IOException expected) {
+                assert expected.message == "generator failed"
+            }
+        '''
+    }
+
+    @Test
+    void testAsyncStreamGeneratorMultipleYields() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+
+            @groovy.transform.Async
+            def counter() {
+                for (i in 1..5) {
+                    yield return i
+                }
+            }
+
+            def stream = counter()
+            def items = []
+            while (await(stream.moveNext())) {
+                items << stream.getCurrent()
+            }
+            assert items == [1, 2, 3, 4, 5]
+        '''
+    }
+
+    @Test
+    void testAsyncStreamEmpty() {
+        assertScript '''
+            import groovy.concurrent.*
+            import static groovy.concurrent.AsyncUtils.*
+
+            def stream = AsyncStream.empty()
+            assert await(stream.moveNext()) == false
+        '''
+    }
+
+    @Test
+    void testAwaitNullReturnsNull() {
+        assertScript '''
+            import static groovy.concurrent.AsyncUtils.*
+
+            def result = await((Object) null)
+            assert result == null
+        '''
+    }
+
+    @Test
+    void testAwaitCompletionStage() {
+        assertScript '''
+            import static groovy.concurrent.AsyncUtils.*
+            import java.util.concurrent.*
+
+            CompletionStage<String> stage = CompletableFuture.completedFuture("stage-value")
+            def result = await(stage)
+            assert result == "stage-value"
+        '''
+    }
+
+    @Test
+    void testAwaitPlainFutureViaObjectOverload() {
+        assertScript '''
+            import static groovy.concurrent.AsyncUtils.*
+            import java.util.concurrent.*
+
+            // Use Object overload which dispatches to Future overload
+            def pool = Executors.newSingleThreadExecutor()
+            Object future = pool.submit({ "future-obj" } as Callable)
+            def result = await(future)
+            assert result == "future-obj"
+            pool.shutdown()
+        '''
+    }
+
+    @Test
+    void testToAsyncStreamWithNullReturnsEmpty() {
+        assertScript '''
+            import static groovy.concurrent.AsyncUtils.*
+            import groovy.concurrent.AsyncStream
+
+            AsyncStream stream = toAsyncStream(null)
+            assert await(stream.moveNext()) == false
+        '''
+    }
+
+    @Test
+    void testDeepUnwrapWithNestedExceptions() {
+        assertScript '''
+            import static groovy.concurrent.AsyncUtils.*
+            import java.util.concurrent.*
+
+            def root = new IOException("root cause")
+            def l1 = new ExecutionException(root)
+            def l2 = new CompletionException(l1)
+            def l3 = new CompletionException(l2)
+
+            assert deepUnwrap(l3).is(root)
+            assert deepUnwrap(root).is(root)
+
+            // Non-wrapper exception is returned as-is
+            def re = new RuntimeException("direct")
+            assert deepUnwrap(re).is(re)
+        '''
+    }
+
+    @Test
+    void testBackwardCompatFacade() {
+        // Verify the deprecated groovy.transform.AsyncUtils still works
+        assertScript '''
+            import static groovy.transform.AsyncUtils.*
+
+            def result = await(async { 42 })
+            assert result == 42
+
+            def list = awaitAll(async { 1 }, async { 2 })
+            assert list == [1, 2]
+
+            def first = awaitAny(async { "fast" })
+            assert first == "fast"
+
+            setExecutor(null) // reset
+        '''
+    }
 }
diff --git a/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy b/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy
index 25930edd35..aa89583254 100644
--- a/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/transform/AsyncVirtualThreadTest.groovy
@@ -36,7 +36,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testVirtualThreadsAvailable() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             // JDK 21+ should have virtual threads
             def jdkVersion = Runtime.version().feature()
             if (jdkVersion >= 21) {
@@ -49,7 +49,7 @@ final class AsyncVirtualThreadTest {
     void testAsyncMethodRunsOnVirtualThread() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class VTService {
                 async checkThread() {
@@ -68,7 +68,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAsyncClosureRunsOnVirtualThread() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             if (isVirtualThreadsAvailable()) {
                 def awaitable = async { Thread.currentThread().isVirtual() }
@@ -80,7 +80,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAsyncLambdaRunsOnVirtualThread() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             if (isVirtualThreadsAvailable()) {
                 def asyncFn = async { x -> Thread.currentThread().isVirtual() }
@@ -94,7 +94,7 @@ final class AsyncVirtualThreadTest {
     void testForAwaitRunsOnVirtualThread() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.AsyncStream
 
             class VTGenerator {
@@ -119,7 +119,7 @@ final class AsyncVirtualThreadTest {
     void testHighConcurrencyWithVirtualThreads() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class HighConcurrency {
                 async compute(int n) {
@@ -145,7 +145,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testCustomExecutorOverride() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.Executors
             import java.util.concurrent.atomic.AtomicReference
 
@@ -172,7 +172,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testSetExecutorNullResetsToDefault() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.Executors
 
             def originalExecutor = getExecutor()
@@ -184,8 +184,8 @@ final class AsyncVirtualThreadTest {
             def restored = getExecutor()
             assert restored != null
             // Verify it works
-            def awaitable = groovy.transform.AsyncUtils.async { 42 }
-            assert groovy.transform.AsyncUtils.await(awaitable) == 42
+            def awaitable = groovy.concurrent.AsyncUtils.async { 42 }
+            assert groovy.concurrent.AsyncUtils.await(awaitable) == 42
             // Restore original
             setExecutor(originalExecutor)
         '''
@@ -195,7 +195,7 @@ final class AsyncVirtualThreadTest {
     void testAsyncMethodWithCustomExecutorField() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.Executor
             import java.util.concurrent.Executors
 
@@ -224,7 +224,7 @@ final class AsyncVirtualThreadTest {
     void testCheckedExceptionConsistencyAcrossAsyncMethods() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class ExcService {
                 async failWithChecked() {
@@ -245,7 +245,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testCheckedExceptionConsistencyAcrossClosures() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def awaitable = async { throw new java.io.IOException("closure error") }
             try {
@@ -260,7 +260,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testCheckedExceptionConsistencyAcrossLambdas() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def asyncFn = async { x -> throw new java.io.IOException("lambda error: ${x}") }
             try {
@@ -276,7 +276,7 @@ final class AsyncVirtualThreadTest {
     void testRuntimeExceptionConsistencyAllForms() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             // Form 1: async method
             class Svc {
@@ -305,7 +305,7 @@ final class AsyncVirtualThreadTest {
     void testErrorPropagationConsistencyAllForms() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class ErrorSvc {
                 async fail() { throw new StackOverflowError("method") }
@@ -332,7 +332,7 @@ final class AsyncVirtualThreadTest {
     void testYieldReturnConsistencyMethodVsClosure() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             // Form 1: async method with yield return
             class GenSvc {
@@ -368,7 +368,7 @@ final class AsyncVirtualThreadTest {
     void testYieldReturnExceptionConsistencyAllForms() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             // async method generator with error
             class FailGen {
@@ -409,7 +409,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testExecuteAsyncWithCustomExecutor() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.Executors
 
             def pool = Executors.newSingleThreadExecutor({ r ->
@@ -430,7 +430,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testExecuteAsyncVoidWithCustomExecutor() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.Executors
             import java.util.concurrent.atomic.AtomicBoolean
 
@@ -450,7 +450,7 @@ final class AsyncVirtualThreadTest {
     void testAsyncVoidMethodReturnsAwaitable() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
             import java.util.concurrent.atomic.AtomicInteger
 
@@ -476,7 +476,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitNull() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             def result = await((Object) null)
             assert result == null
         '''
@@ -485,7 +485,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitAlreadyCompletedAwaitable() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def awaitable = Awaitable.of(42)
@@ -498,7 +498,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitFailedAwaitable() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def awaitable = Awaitable.failed(new RuntimeException("pre-failed"))
@@ -515,8 +515,8 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitCancelledAwaitable() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
-            import groovy.concurrent.GroovyPromise
+            import static groovy.concurrent.AsyncUtils.*
+            import org.apache.groovy.runtime.async.GroovyPromise
             import java.util.concurrent.CompletableFuture
             import java.util.concurrent.CancellationException
 
@@ -536,7 +536,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAsyncWithReturnValue() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def awaitable = async { return "hello" }
             assert await(awaitable) == "hello"
@@ -546,7 +546,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAsyncWithNullReturnValue() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def awaitable = async { return null }
             assert await(awaitable) == null
@@ -556,7 +556,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testMultipleConcurrentAsyncGenerators() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def gen1 = async { for (int i = 0; i < 5; i++) { yield return "A${i}" } }
             def gen2 = async { for (int i = 0; i < 5; i++) { yield return "B${i}" } }
@@ -574,7 +574,7 @@ final class AsyncVirtualThreadTest {
     void testEmptyAsyncStream() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class EmptyGen {
                 async empty() {
@@ -595,7 +595,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitableCompositionWithThen() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def original = async { 10 }
@@ -608,7 +608,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitableCompositionWithThenCompose() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def first = async { 5 }
@@ -621,7 +621,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitableExceptionally() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def failing = async { throw new RuntimeException("oops") }
@@ -634,7 +634,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitWithCompletionStage() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletableFuture
             import java.util.concurrent.CompletionStage
 
@@ -647,7 +647,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitWithFuture() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.Executors
             import java.util.concurrent.Future
 
@@ -662,7 +662,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitAllWithMixedTypes() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
             import java.util.concurrent.CompletableFuture
 
@@ -678,7 +678,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitAnyReturnsFirst() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             def fast = Awaitable.of("fast")
@@ -692,7 +692,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitAllSettledMixed() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def success = async { "ok" }
             def failure = async { throw new RuntimeException("fail") }
@@ -710,7 +710,7 @@ final class AsyncVirtualThreadTest {
     void testAsyncMethodWithPrimitiveReturnType() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class PrimService {
                 @Async
@@ -733,7 +733,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testDeepUnwrapNestedExceptions() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletionException
             import java.util.concurrent.ExecutionException
 
@@ -759,7 +759,7 @@ final class AsyncVirtualThreadTest {
     void testAsyncWithNestedAwait() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class NestedService {
                 async inner(int v) { return v * 2 }
@@ -779,7 +779,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAsyncClosureWithNestedAwait() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             def inner = async { x -> x + 1 }
             def outer = async {
@@ -795,7 +795,7 @@ final class AsyncVirtualThreadTest {
     void testParallelAwaitInAsyncMethod() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.CompletableFuture
 
             class ParallelService {
@@ -826,7 +826,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testToAsyncStreamConversion() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.AsyncStream
             import groovy.concurrent.Awaitable
             import groovy.concurrent.AwaitableAdapter
@@ -866,7 +866,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAwaitObjectDispatchesToCorrectOverload() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
             import java.util.concurrent.CompletableFuture
 
@@ -885,7 +885,7 @@ final class AsyncVirtualThreadTest {
     void testAsyncMethodWithParameters() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class ParamService {
                 async add(int a, int b) {
@@ -907,7 +907,7 @@ final class AsyncVirtualThreadTest {
     void testAsyncChainedMethods() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             class Pipeline {
@@ -934,7 +934,7 @@ final class AsyncVirtualThreadTest {
     void testAwaitSyntaxWithBinaryOperations() {
         assertScript '''
             import groovy.transform.Async
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.Awaitable
 
             class MathService {
@@ -954,7 +954,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testAsyncClosureWithoutYieldReturnIsNotGenerator() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             // Closure with no yield return produces an Awaitable (not AsyncStream)
             def result = async { 42 }
@@ -968,7 +968,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testGroovyPromiseToString() {
         assertScript '''
-            import groovy.concurrent.GroovyPromise
+            import org.apache.groovy.runtime.async.GroovyPromise
             import groovy.concurrent.Awaitable
             import java.util.concurrent.CompletableFuture
 
@@ -987,8 +987,8 @@ final class AsyncVirtualThreadTest {
     @Test
     void testGroovyPromiseGetWithTimeout() {
         assertScript '''
-            import groovy.concurrent.GroovyPromise
-            import static groovy.transform.AsyncUtils.*
+            import org.apache.groovy.runtime.async.GroovyPromise
+            import static groovy.concurrent.AsyncUtils.*
             import java.util.concurrent.TimeUnit
             import java.util.concurrent.TimeoutException
 
@@ -1007,7 +1007,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testForAwaitNullSkipsLoop() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class Gen {
                 async static test() {
@@ -1025,7 +1025,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testForAwaitNullWithExistingItems() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             class Gen {
                 async static test() {
@@ -1049,7 +1049,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testForAwaitEmptyStream() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
             import groovy.concurrent.AsyncStream
 
             class Gen {
@@ -1070,7 +1070,7 @@ final class AsyncVirtualThreadTest {
     @Test
     void testYieldReturnNoThreadLocal() {
         assertScript '''
-            import static groovy.transform.AsyncUtils.*
+            import static groovy.concurrent.AsyncUtils.*
 
             // Verify that yield return works without ThreadLocal
             // by running many concurrent generators simultaneously
@@ -1105,7 +1105,7 @@ final class AsyncVirtualThreadTest {
         assertScript '''
             // yield return outside async context should fail at runtime
             try {
-                groovy.transform.AsyncUtils.yieldReturn("oops")
+                org.apache.groovy.runtime.async.AsyncSupport.yieldReturn("oops")
                 assert false : "expected exception"
             } catch (IllegalStateException e) {
                 assert e.message.contains("yield return")