From 9b54eecbee7329543e5016cec1574831bfb788c2 Mon Sep 17 00:00:00 2001 From: Cheng Shao <terrorjack@type.dance> Date: Mon, 3 Mar 2025 10:47:05 +0000 Subject: [PATCH] wasm: add error message to WouldBlockException This commit attaches an error message to WouldBlockException, for now the error message consists of the JS async import code snippet that thunk is trying to block for. This is useful for debugging synchronous callbacks that accidentally call an async JS function. --- compiler/GHC/HsToCore/Foreign/Wasm.hs | 3 ++- .../ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs | 6 +++--- libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs | 4 ++-- testsuite/tests/jsffi/jsffisleep.hs | 4 ++-- testsuite/tests/jsffi/jsffisleep.stdout | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/GHC/HsToCore/Foreign/Wasm.hs b/compiler/GHC/HsToCore/Foreign/Wasm.hs index 34464557cf9..580a446d866 100644 --- a/compiler/GHC/HsToCore/Foreign/Wasm.hs +++ b/compiler/GHC/HsToCore/Foreign/Wasm.hs @@ -318,6 +318,7 @@ dsWasmJSStaticImport fn_id co js_src' mUnitId sync = do importCStub Sync cfun_name (map scaledThing arg_tys) res_ty js_src ) Async -> do + err_msg <- mkStringExpr $ js_src io_tycon <- dsLookupTyCon ioTyConName jsval_ty <- mkTyConTy @@ -363,7 +364,7 @@ dsWasmJSStaticImport fn_id co js_src' mUnitId sync = do [ Type res_ty, mkApps (Var blockPromise_id) - [Type res_ty, Var promise_id, Var msgPromise_id] + [Type res_ty, err_msg, Var promise_id, Var msgPromise_id] ] ] ) diff --git a/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs b/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs index 62109a47959..8fd6e6875d9 100644 --- a/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs +++ b/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Imports.hs @@ -79,9 +79,9 @@ filled is generated via raiseJSException. -} -stg_blockPromise :: JSVal -> (JSVal -> StablePtr Any -> IO ()) -> r -stg_blockPromise p msg_p = unsafeDupablePerformIO $ IO $ \s0 -> - case stg_jsffi_check (unsafeCoerce# $ toException WouldBlockException) s0 of +stg_blockPromise :: String -> JSVal -> (JSVal -> StablePtr Any -> IO ()) -> r +stg_blockPromise err_msg p msg_p = unsafeDupablePerformIO $ IO $ \s0 -> + case stg_jsffi_check (unsafeCoerce# $ toException $ WouldBlockException err_msg) s0 of (# s1 #) -> case myThreadId# s1 of (# s2, tso #) -> case makeStablePtr# tso s2 of (# s3, sp #) -> diff --git a/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs b/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs index 39800ee383c..b2cc19b9f5e 100644 --- a/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs +++ b/libraries/ghc-internal/src/GHC/Internal/Wasm/Prim/Types.hs @@ -139,8 +139,8 @@ foreign import javascript unsafe "`${$1.stack ? $1.stack : $1}`" instance Exception JSException -data WouldBlockException - = WouldBlockException +newtype WouldBlockException + = WouldBlockException String deriving (Show) instance Exception WouldBlockException diff --git a/testsuite/tests/jsffi/jsffisleep.hs b/testsuite/tests/jsffi/jsffisleep.hs index 8e9c6852643..f312f8e9ea3 100644 --- a/testsuite/tests/jsffi/jsffisleep.hs +++ b/testsuite/tests/jsffi/jsffisleep.hs @@ -20,8 +20,8 @@ foreign export ccall "testWouldBlock" -- non-main exports in C FFI. In JSFFI, it's always done automatically -- for every export though. testWouldBlock :: IO () -testWouldBlock = catch (threadDelay 1000000) $ \WouldBlockException -> do - print WouldBlockException +testWouldBlock = catch (threadDelay 1000000) $ \(WouldBlockException err) -> do + print $ WouldBlockException err flushStdHandles foreign export javascript "testLazySleep" diff --git a/testsuite/tests/jsffi/jsffisleep.stdout b/testsuite/tests/jsffi/jsffisleep.stdout index 6aa5bcb432d..59a7f084e1b 100644 --- a/testsuite/tests/jsffi/jsffisleep.stdout +++ b/testsuite/tests/jsffi/jsffisleep.stdout @@ -1,4 +1,4 @@ -WouldBlockException +WouldBlockException "new Promise(res => setTimeout(res, $1 / 1000))" zzzzzzz i sleep Left thread killed -- GitLab