[Git][ghc/ghc][wip/wasm-command-jsval] rts: fix wasm JSFFI initialization constructor code
Cheng Shao pushed to branch wip/wasm-command-jsval at Glasgow Haskell Compiler / GHC Commits: a256d3e3 by Cheng Shao at 2025-09-27T19:50:24+02:00 rts: fix wasm JSFFI initialization constructor code This commit fixes wasm JSFFI initialization constructor code so that the constructor is self-contained and avoids invoking a fake __main_argc_argv function. The previous approach of reusing __main_void logic in wasi-libc saves a tiny bit of code, at the expense of link-time trouble whenever GHC links a wasm module without -no-hs-main, in which case the driver-generated main function would clash with the definition here, resulting in a linker error. It's simply better to avoid messing with the main function, and it would additionally allow linking wasm32-wasi command modules that does make use of synchronous JSFFI. - - - - - 1 changed file: - rts/wasm/JSFFI.c Changes: ===================================== rts/wasm/JSFFI.c ===================================== @@ -5,6 +5,8 @@ #include "Threads.h" #include "sm/Sanity.h" +#include <sysexits.h> + #if defined(__wasm_reference_types__) extern HsBool rts_JSFFI_flag; @@ -12,21 +14,8 @@ extern HsStablePtr rts_threadDelay_impl; extern StgClosure ghczminternal_GHCziInternalziWasmziPrimziImports_raiseJSException_closure; extern StgClosure ghczminternal_GHCziInternalziWasmziPrimziConcziInternal_threadDelay_closure; -int __main_void(void); - -int __main_argc_argv(int, char*[]); - -int __main_argc_argv(int argc, char *argv[]) { - RtsConfig __conf = defaultRtsConfig; - __conf.rts_opts_enabled = RtsOptsAll; - __conf.rts_hs_main = false; - hs_init_ghc(&argc, &argv, __conf); - // See Note [threadDelay on wasm] for details. - rts_JSFFI_flag = HS_BOOL_TRUE; - getStablePtr((StgPtr)&ghczminternal_GHCziInternalziWasmziPrimziImports_raiseJSException_closure); - rts_threadDelay_impl = getStablePtr((StgPtr)&ghczminternal_GHCziInternalziWasmziPrimziConcziInternal_threadDelay_closure); - return 0; -} +__attribute__((__weak__)) +int __main_argc_argv(int argc, char *argv[]); // Note [JSFFI initialization] // ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -66,11 +55,69 @@ int __main_argc_argv(int argc, char *argv[]) { // by the GHC codegen, and priority 102 to the initialization logic // here to ensure hs_init_ghc() sees everything it needs to see. __attribute__((constructor(102))) static void __ghc_wasm_jsffi_init(void) { - // See - // https://gitlab.haskell.org/ghc/wasi-libc/-/blob/master/libc-bottom-half/sour... - // for its definition. It initializes some libc state, then calls - // __main_argc_argv defined above. - __main_void(); + // If linking static code without -no-hs-main, then the driver + // emitted main() is in charge of its own RTS initialization, so + // skip. +#if !defined(__PIC__) + if (__main_argc_argv) { + return; + } +#endif + + // Code below is mirrored from + // https://gitlab.haskell.org/haskell-wasm/wasi-libc/-/blob/master/libc-bottom-..., + // fetches argc/argv using wasi api + __wasi_errno_t err; + + // Get the sizes of the arrays we'll have to create to copy in the args. + size_t argv_buf_size; + size_t argc; + err = __wasi_args_sizes_get(&argc, &argv_buf_size); + if (err != __WASI_ERRNO_SUCCESS) { + _Exit(EX_OSERR); + } + + // Add 1 for the NULL pointer to mark the end, and check for overflow. + size_t num_ptrs = argc + 1; + if (num_ptrs == 0) { + _Exit(EX_SOFTWARE); + } + + // Allocate memory for storing the argument chars. + char *argv_buf = malloc(argv_buf_size); + if (argv_buf == NULL) { + _Exit(EX_SOFTWARE); + } + + // Allocate memory for the array of pointers. This uses `calloc` both to + // handle overflow and to initialize the NULL pointer at the end. + char **argv = calloc(num_ptrs, sizeof(char *)); + if (argv == NULL) { + free(argv_buf); + _Exit(EX_SOFTWARE); + } + + // Fill the argument chars, and the argv array with pointers into those chars. + // TODO: Remove the casts on `argv_ptrs` and `argv_buf` once the witx is + // updated with char8 support. + err = __wasi_args_get((uint8_t **)argv, (uint8_t *)argv_buf); + if (err != __WASI_ERRNO_SUCCESS) { + free(argv_buf); + free(argv); + _Exit(EX_OSERR); + } + + // Now that we have argc/argv, proceed to initialize the GHC RTS + RtsConfig __conf = defaultRtsConfig; + __conf.rts_opts_enabled = RtsOptsAll; + __conf.rts_hs_main = false; + hs_init_ghc((int *)&argc, &argv, __conf); + // See Note [threadDelay on wasm] for details. + rts_JSFFI_flag = HS_BOOL_TRUE; + getStablePtr(( + StgPtr)&ghczminternal_GHCziInternalziWasmziPrimziImports_raiseJSException_closure); + rts_threadDelay_impl = getStablePtr(( + StgPtr)&ghczminternal_GHCziInternalziWasmziPrimziConcziInternal_threadDelay_closure); } typedef __externref_t HsJSVal; View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a256d3e33afcc65cd4e0dd921e45e4e3... -- View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/a256d3e33afcc65cd4e0dd921e45e4e3... You're receiving this email because of your account on gitlab.haskell.org.
participants (1)
-
Cheng Shao (@TerrorJack)