summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJukka Jylanki <jujjyl@gmail.com>2022-11-22 12:07:16 +0200
committerIvan Maidanski <ivmai@mail.ru>2022-11-24 00:08:07 +0300
commit840bbcf603bc75e0b2da21ea9cbd84d1d63f14cf (patch)
tree43f4de57a2a2e920cdba5f4bc47ad9eff8fa9310
parent421d2612e45bdc8305a220ee06f93461ed979d6d (diff)
downloadbdwgc-840bbcf603bc75e0b2da21ea9cbd84d1d63f14cf.tar.gz
Make Emscripten Asyncify feature optional
Issue #506 (bdwgc). "-sASYNCIFY" is a relatively rarely used feature of Emscripten, most developers do not use it, and it does not scale well to moderate-to-large codebases. It incurs a heavy impact to code size and performance, and carries other correctness problems that developers must then adhere to regarding event loop message ordering. This commit provides new option in cmake (-Denable_emscripten_asyncify) and configure (--enable-emscripten-asyncify) scripts to turn on Emscripten Asyncify feature on demand. * CMakeLists.txt (enable_emscripten_asyncify): New option (off by default). * CMakeLists.txt (EMSCRIPTEN): Define using check_c_source_compiles. * CMakeLists.txt [EMSCRIPTEN && enable_emscripten_asyncify] (EMSCRIPTEN_ASYNCIFY): Define C macro. * CMakeLists.txt [EMSCRIPTEN && enable_emscripten_asyncify] (CMAKE_EXE_LINKER_FLAGS): Append "-sASYNCIFY" and "-sASYNCIFY_STACK_SIZE=128000". * configure.ac (emscripten): Remove quotes for the error directive message. * configure.ac [emscripten] (gc_cflags): Move comment and assignment down (to be after reporting result for emscripten). * configure.ac (emscripten-asyncify): New AC_ARG_ENABLE option; add comment. * configure.ac [enable_emscripten_asyncify && emscripten] (gc_cflags): Add -D EMSCRIPTEN_ASYNCIFY; remove space after "-s". * configure.ac [emscripten] (gc_cflags): Append "-sASYNCIFY" and "-sASYNCIFY_STACK_SIZE=128000" only if enable_emscripten_asyncify. * doc/README.macros (EMSCRIPTEN_ASYNCIFY): Document. * os_dep.c [!ECOS && !NOSYS && !SYMBIAN && EMSCRIPTEN]: Make USE_EMSCRIPTEN_SCAN_STACK has effect only if EMSCRIPTEN_ASYNCIFY. * os_dep.c [THREADS && EMSCRIPTEN]: Include emscripten.h only if EMSCRIPTEN_ASYNCIFY. * os_dep.c [THREADS && EMSCRIPTEN] (scan_regs_cb, GC_default_push_other_roots): Define as a function only if EMSCRIPTEN_ASYNCIFY; update comment. Co-authored-by: Ivan Maidanski <ivmai@mail.ru>
-rw-r--r--CMakeLists.txt17
-rw-r--r--configure.ac20
-rw-r--r--doc/README.macros6
-rw-r--r--os_dep.c9
4 files changed, 40 insertions, 12 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7917be50..8567e374 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -89,6 +89,7 @@ option(enable_single_obj_compilation "Compile all libgc source files into single
option(disable_single_obj_compilation "Compile each libgc source file independently" OFF)
option(enable_handle_fork "Attempt to ensure a usable collector after fork()" ON)
option(disable_handle_fork "Prohibit installation of pthread_atfork() handlers" OFF)
+option(enable_emscripten_asyncify "Use Emscripten asyncify feature" OFF)
option(install_headers "Install header and pkg-config metadata files" ON)
option(with_libatomic_ops "Use an external libatomic_ops" OFF)
option(without_libatomic_ops "Use atomic_ops.h in libatomic_ops/src" OFF)
@@ -546,6 +547,22 @@ if (HAVE_DLADDR)
add_definitions("-DHAVE_DLADDR")
endif()
+# Check for emscripten; use asyncify feature if requested.
+check_c_source_compiles("
+#ifndef __EMSCRIPTEN__\n
+# error This is not Emscripten\n
+#endif\n
+int main(void) { return 0; }"
+ EMSCRIPTEN)
+if (EMSCRIPTEN AND enable_emscripten_asyncify)
+ # Use this option if your program is targeting -sASYNCIFY. The latter is
+ # required to scan the stack, ASYNCIFY_STACK_SIZE is probably needed for
+ # gctest only.
+ add_definitions("-DEMSCRIPTEN_ASYNCIFY")
+ set(CMAKE_EXE_LINKER_FLAGS
+ "${CMAKE_EXE_LINKER_FLAGS} -sASYNCIFY -sASYNCIFY_STACK_SIZE=128000")
+endif()
+
add_library(gc ${SRC})
target_link_libraries(gc
PRIVATE ${ATOMIC_OPS_LIBS_CMAKE} ${THREADDLLIBS_LIST})
diff --git a/configure.ac b/configure.ac
index 03e14b8e..4e9e32e4 100644
--- a/configure.ac
+++ b/configure.ac
@@ -86,17 +86,23 @@ esac
AC_MSG_CHECKING([for emscripten])
AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
-# ifdef __EMSCRIPTEN__
-# error "this is emscripten"
+# ifndef __EMSCRIPTEN__
+# error This is not Emscripten
# endif
- ]])], [emscripten=no], [emscripten=yes])
-# Note -s ASYNCIFY is required to scan the stack, ASYNCIFY_STACK_SIZE is
-# probably needed for gctest only.
-AS_IF([test "x$emscripten" = "xyes"],
- [gc_cflags="${gc_cflags} -s ASYNCIFY -s ASYNCIFY_STACK_SIZE=128000"])
+ ]])], [emscripten=yes], [emscripten=no])
AM_CONDITIONAL(EMSCRIPTEN, test x$emscripten = xyes)
AC_MSG_RESULT([$emscripten])
+AC_ARG_ENABLE(emscripten-asyncify,
+ [AS_HELP_STRING([--enable-emscripten-asyncify],
+ [use Emscripten asyncify feature])])
+# Use this option if your program is targeting -sASYNCIFY. The latter is
+# required to scan the stack, ASYNCIFY_STACK_SIZE is probably needed for
+# gctest only.
+AS_IF([test "${emscripten}" = yes -a "${enable_emscripten_asyncify}" = yes],
+ [gc_cflags="${gc_cflags} -DEMSCRIPTEN_ASYNCIFY"
+ gc_cflags="${gc_cflags} -sASYNCIFY -sASYNCIFY_STACK_SIZE=128000"])
+
GC_CFLAGS=${gc_cflags}
AC_SUBST(GC_CFLAGS)
diff --git a/doc/README.macros b/doc/README.macros
index 8aee5722..8fb6a76f 100644
--- a/doc/README.macros
+++ b/doc/README.macros
@@ -606,3 +606,9 @@ USE_GET_STACKBASE_FOR_MAIN (Linux only) Use pthread_attr_getstack() instead
of __libc_stack_end (or instead of any hard-coded value) for getting the
primordial thread stack bottom (useful if the client modifies the program's
address space).
+
+EMSCRIPTEN_ASYNCIFY (Emscripten only) Use Asyncify feature. Note this is
+ a relatively rarely used feature of Emscripten, most developers do not use
+ it, and it does not scale well to moderate-to-large code bases. But the
+ feature is needed to pass gctest, at least. Requires -sASYNCIFY linker
+ flag.
diff --git a/os_dep.c b/os_dep.c
index 2fd63e0e..8e140836 100644
--- a/os_dep.c
+++ b/os_dep.c
@@ -1242,7 +1242,7 @@ GC_INNER size_t GC_page_size = 0;
# define GET_MAIN_STACKBASE_SPECIAL
#elif defined(EMSCRIPTEN)
-# ifdef USE_EMSCRIPTEN_SCAN_STACK
+# if defined(USE_EMSCRIPTEN_SCAN_STACK) && defined(EMSCRIPTEN_ASYNCIFY)
/* According to the documentation, emscripten_scan_stack() is only */
/* guaranteed to be available when building with ASYNCIFY. */
# include <emscripten.h>
@@ -1260,7 +1260,7 @@ GC_INNER size_t GC_page_size = 0;
ptr_t GC_get_main_stack_base(void)
{
-# ifdef USE_EMSCRIPTEN_SCAN_STACK
+# if defined(USE_EMSCRIPTEN_SCAN_STACK) && defined(EMSCRIPTEN_ASYNCIFY)
emscripten_scan_stack(scan_stack_cb);
return (ptr_t)emscripten_stack_base;
# else
@@ -2814,7 +2814,7 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
/* thread stacks. */
#ifndef THREADS
-# ifdef EMSCRIPTEN
+# if defined(EMSCRIPTEN) && defined(EMSCRIPTEN_ASYNCIFY)
# include <emscripten.h>
static void scan_regs_cb(void *begin, void *end)
@@ -2824,8 +2824,7 @@ GC_INNER void GC_unmap_gap(ptr_t start1, size_t bytes1, ptr_t start2,
STATIC void GC_CALLBACK GC_default_push_other_roots(void)
{
- /* This needs "-s ASYNCIFY -s ASYNCIFY_STACK_SIZE=128000" */
- /* but hopefully the latter is only required for gctest. */
+ /* Note: this needs -sASYNCIFY linker flag. */
emscripten_scan_registers(scan_regs_cb);
}