diff --git a/Makefile b/Makefile index b96ba3358..37c2bead6 100644 --- a/Makefile +++ b/Makefile @@ -21,6 +21,8 @@ WASI_SNAPSHOT ?= preview1 MALLOC_IMPL ?= dlmalloc # yes or no BUILD_LIBC_TOP_HALF ?= yes +# Build setjmp/longjmp support. yes or no +BUILD_SJLJ ?= no # The directory where we will store intermediate artifacts. OBJDIR ?= build/$(TARGET_TRIPLE) # The directory where we store files and tools for generating WASI Preview 2 bindings @@ -309,6 +311,11 @@ LIBC_TOP_HALF_MUSL_SOURCES += \ ) endif +ifeq ($(BUILD_SJLJ),yes) +LIBC_TOP_HALF_MUSL_SOURCES += \ + $(LIBC_TOP_HALF_MUSL_SRC_DIR)/setjmp/wasm32/rt.c +endif + MUSL_PRINTSCAN_SOURCES = \ $(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal/floatscan.c \ $(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdio/vfprintf.c \ @@ -320,6 +327,8 @@ BULK_MEMORY_SOURCES = \ $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memcpy.c \ $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memmove.c \ $(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memset.c +SJLJ_SOURCES = \ + $(LIBC_TOP_HALF_MUSL_SRC_DIR)/setjmp/wasm32/rt.c LIBC_TOP_HALF_HEADERS_PRIVATE = $(LIBC_TOP_HALF_DIR)/headers/private LIBC_TOP_HALF_SOURCES = $(LIBC_TOP_HALF_DIR)/sources LIBC_TOP_HALF_ALL_SOURCES = \ @@ -402,6 +411,7 @@ MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES)) MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS)) MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS)) BULK_MEMORY_OBJS = $(call objs,$(BULK_MEMORY_SOURCES)) +SJLJ_OBJS = $(call objs,$(SJLJ_SOURCES)) LIBWASI_EMULATED_MMAN_OBJS = $(call objs,$(LIBWASI_EMULATED_MMAN_SOURCES)) LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS = $(call objs,$(LIBWASI_EMULATED_PROCESS_CLOCKS_SOURCES)) LIBWASI_EMULATED_GETPID_OBJS = $(call objs,$(LIBWASI_EMULATED_GETPID_SOURCES)) @@ -473,7 +483,6 @@ MUSL_OMIT_HEADERS += \ "netdb.h" \ "resolv.h" \ "pty.h" \ - "setjmp.h" \ "ulimit.h" \ "sys/xattr.h" \ "wordexp.h" \ @@ -510,6 +519,7 @@ LIBWASI_EMULATED_SIGNAL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_SIGN LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS)) LIBDL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBDL_OBJS)) BULK_MEMORY_SO_OBJS = $(patsubst %.o,%.pic.o,$(BULK_MEMORY_OBJS)) +SJLJ_SO_OBJS = $(patsubst %.o,%.pic.o,$(SJLJ_OBJS)) DLMALLOC_SO_OBJS = $(patsubst %.o,%.pic.o,$(DLMALLOC_OBJS)) LIBC_BOTTOM_HALF_ALL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBC_BOTTOM_HALF_ALL_OBJS)) LIBC_TOP_HALF_ALL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBC_TOP_HALF_ALL_OBJS)) @@ -524,6 +534,7 @@ PIC_OBJS = \ $(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS) \ $(LIBDL_SO_OBJS) \ $(BULK_MEMORY_SO_OBJS) \ + $(SJLJ_SO_OBJS) \ $(DLMALLOC_SO_OBJS) \ $(LIBC_BOTTOM_HALF_ALL_SO_OBJS) \ $(LIBC_TOP_HALF_ALL_SO_OBJS) \ @@ -597,6 +608,9 @@ $(BULK_MEMORY_OBJS) $(BULK_MEMORY_SO_OBJS): CFLAGS += \ $(BULK_MEMORY_OBJS) $(BULK_MEMORY_SO_OBJS): CFLAGS += \ -DBULK_MEMORY_THRESHOLD=$(BULK_MEMORY_THRESHOLD) +$(SJLJ_OBJS) $(SJLJ_SO_OBJS): CFLAGS += \ + -mllvm -wasm-enable-sjlj + $(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS): CFLAGS += \ -D_WASI_EMULATED_SIGNAL diff --git a/expected/wasm32-wasi-preview2/include-all.c b/expected/wasm32-wasi-preview2/include-all.c index 3de5cf010..fdb126ada 100644 --- a/expected/wasm32-wasi-preview2/include-all.c +++ b/expected/wasm32-wasi-preview2/include-all.c @@ -117,6 +117,7 @@ #include #include #include +#include #include #include #include diff --git a/expected/wasm32-wasi-preview2/predefined-macros.txt b/expected/wasm32-wasi-preview2/predefined-macros.txt index 77b1db05b..cba852cc1 100644 --- a/expected/wasm32-wasi-preview2/predefined-macros.txt +++ b/expected/wasm32-wasi-preview2/predefined-macros.txt @@ -2412,6 +2412,7 @@ #define _SC_XOPEN_XPG4 100 #define _SEARCH_H #define _SEMAPHORE_H +#define _SETJMP_H #define _SIZE_T #define _STDALIGN_H #define _STDBOOL_H diff --git a/expected/wasm32-wasi-threads/include-all.c b/expected/wasm32-wasi-threads/include-all.c index d9536e09f..a19b7ffbc 100644 --- a/expected/wasm32-wasi-threads/include-all.c +++ b/expected/wasm32-wasi-threads/include-all.c @@ -118,6 +118,7 @@ #include #include #include +#include #include #include #include diff --git a/expected/wasm32-wasi-threads/predefined-macros.txt b/expected/wasm32-wasi-threads/predefined-macros.txt index ec33b417f..8cec24c21 100644 --- a/expected/wasm32-wasi-threads/predefined-macros.txt +++ b/expected/wasm32-wasi-threads/predefined-macros.txt @@ -2352,6 +2352,7 @@ #define _SC_XOPEN_XPG4 100 #define _SEARCH_H #define _SEMAPHORE_H +#define _SETJMP_H #define _SIZE_T #define _STDALIGN_H #define _STDBOOL_H diff --git a/expected/wasm32-wasi/include-all.c b/expected/wasm32-wasi/include-all.c index 1040097ba..ad3fe449d 100644 --- a/expected/wasm32-wasi/include-all.c +++ b/expected/wasm32-wasi/include-all.c @@ -117,6 +117,7 @@ #include #include #include +#include #include #include #include diff --git a/expected/wasm32-wasi/predefined-macros.txt b/expected/wasm32-wasi/predefined-macros.txt index 2d21ab08e..bcbaa932a 100644 --- a/expected/wasm32-wasi/predefined-macros.txt +++ b/expected/wasm32-wasi/predefined-macros.txt @@ -2315,6 +2315,7 @@ #define _SC_XOPEN_XPG4 100 #define _SEARCH_H #define _SEMAPHORE_H +#define _SETJMP_H #define _SIZE_T #define _STDALIGN_H #define _STDBOOL_H diff --git a/libc-top-half/musl/arch/wasm32/bits/setjmp.h b/libc-top-half/musl/arch/wasm32/bits/setjmp.h new file mode 100644 index 000000000..aae8de683 --- /dev/null +++ b/libc-top-half/musl/arch/wasm32/bits/setjmp.h @@ -0,0 +1,2 @@ +/* note: right now, only the first word is actually used */ +typedef unsigned long __jmp_buf[8]; diff --git a/libc-top-half/musl/include/setjmp.h b/libc-top-half/musl/include/setjmp.h index f505f8e4f..33c486116 100644 --- a/libc-top-half/musl/include/setjmp.h +++ b/libc-top-half/musl/include/setjmp.h @@ -7,7 +7,8 @@ extern "C" { #include -#ifdef __wasilibc_unmodified_upstream /* WASI has no setjmp */ +/* WASI has no setjmp */ +#if defined(__wasilibc_unmodified_upstream) || defined(__wasm_exception_handling__) #include typedef struct __jmp_buf_tag { diff --git a/libc-top-half/musl/src/setjmp/wasm32/rt.c b/libc-top-half/musl/src/setjmp/wasm32/rt.c new file mode 100644 index 000000000..1ced420e4 --- /dev/null +++ b/libc-top-half/musl/src/setjmp/wasm32/rt.c @@ -0,0 +1,90 @@ +/* + * https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp + */ + +#include +#include + +struct entry { + uint32_t id; + uint32_t label; +}; + +static _Thread_local struct state { + uint32_t id; + uint32_t size; + struct arg { + void *env; + int val; + } arg; +} g_state; + +/* + * table is allocated at the entry of functions which call setjmp. + * + * table = malloc(40); + * size = 4; + * *(int *)table = 0; + */ +_Static_assert(sizeof(struct entry) * (4 + 1) <= 40, "entry size"); + +void * +saveSetjmp(void *env, uint32_t label, void *table, uint32_t size) +{ + struct state *state = &g_state; + struct entry *e = table; + uint32_t i; + for (i = 0; i < size; i++) { + if (e[i].id == 0) { + uint32_t id = ++state->id; + *(uint32_t *)env = id; + e[i].id = id; + e[i].label = label; + /* + * note: only the first word is zero-initialized + * by the caller. + */ + e[i + 1].id = 0; + goto done; + } + } + size *= 2; + void *p = realloc(table, sizeof(*e) * (size + 1)); + if (p == NULL) { + __builtin_trap(); + } + table = p; +done: + state->size = size; + return table; +} + +uint32_t +testSetjmp(unsigned int id, void *table, uint32_t size) +{ + struct entry *e = table; + uint32_t i; + for (i = 0; i < size; i++) { + if (e[i].id == id) { + return e[i].label; + } + } + return 0; +} + +uint32_t +getTempRet0() +{ + struct state *state = &g_state; + return state->size; +} + +void +__wasm_longjmp(void *env, int val) +{ + struct state *state = &g_state; + struct arg *arg = &state->arg; + arg->env = env; + arg->val = val; + __builtin_wasm_throw(1, arg); +}