Skip to content

Commit 06960f2

Browse files
committed
Experimental setjmp/longjmp support
Basically copy-and-paste from: https://github.com/yamt/garbage/tree/master/wasm/longjmp While it seems working well, it's disabled by default because: * It might be controversial if it's a good idea to use this emscripten API for WASI as well. * LLVM produces bytecode for an old version of the EH proposal. * The EH proposal is not widely implemeted in runtimes yet. Maybe it isn't a problem for libc.a. But for libc.so, it would be a disaster for runtimes w/o EH. Tested with `binaryen --translate-eh-old-to-new` and toywasm: * build wasi-libc with BUILD_SJLJ=yes * build your app with "-mllvm -wasm-enable-sjlj" * apply "wasm-opt --translate-eh-old-to-new" * run with "toywasm --wasi" Besides that, for libc.so, your embedder needs to provide "env:__c_longjmp".
1 parent cc62fa8 commit 06960f2

File tree

10 files changed

+115
-2
lines changed

10 files changed

+115
-2
lines changed

Makefile

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ WASI_SNAPSHOT ?= preview1
2121
MALLOC_IMPL ?= dlmalloc
2222
# yes or no
2323
BUILD_LIBC_TOP_HALF ?= yes
24+
# Build setjmp/longjmp support. yes or no
25+
BUILD_SJLJ ?= no
2426
# The directory where we will store intermediate artifacts.
2527
OBJDIR ?= build/$(TARGET_TRIPLE)
2628
# The directory where we store files and tools for generating WASI Preview 2 bindings
@@ -309,6 +311,11 @@ LIBC_TOP_HALF_MUSL_SOURCES += \
309311
)
310312
endif
311313

314+
ifeq ($(BUILD_SJLJ),yes)
315+
LIBC_TOP_HALF_MUSL_SOURCES += \
316+
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/setjmp/wasm32/rt.c
317+
endif
318+
312319
MUSL_PRINTSCAN_SOURCES = \
313320
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/internal/floatscan.c \
314321
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/stdio/vfprintf.c \
@@ -320,6 +327,8 @@ BULK_MEMORY_SOURCES = \
320327
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memcpy.c \
321328
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memmove.c \
322329
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/string/memset.c
330+
SJLJ_SOURCES = \
331+
$(LIBC_TOP_HALF_MUSL_SRC_DIR)/setjmp/wasm32/rt.c
323332
LIBC_TOP_HALF_HEADERS_PRIVATE = $(LIBC_TOP_HALF_DIR)/headers/private
324333
LIBC_TOP_HALF_SOURCES = $(LIBC_TOP_HALF_DIR)/sources
325334
LIBC_TOP_HALF_ALL_SOURCES = \
@@ -402,6 +411,7 @@ MUSL_PRINTSCAN_OBJS = $(call objs,$(MUSL_PRINTSCAN_SOURCES))
402411
MUSL_PRINTSCAN_LONG_DOUBLE_OBJS = $(patsubst %.o,%.long-double.o,$(MUSL_PRINTSCAN_OBJS))
403412
MUSL_PRINTSCAN_NO_FLOATING_POINT_OBJS = $(patsubst %.o,%.no-floating-point.o,$(MUSL_PRINTSCAN_OBJS))
404413
BULK_MEMORY_OBJS = $(call objs,$(BULK_MEMORY_SOURCES))
414+
SJLJ_OBJS = $(call objs,$(SJLJ_SOURCES))
405415
LIBWASI_EMULATED_MMAN_OBJS = $(call objs,$(LIBWASI_EMULATED_MMAN_SOURCES))
406416
LIBWASI_EMULATED_PROCESS_CLOCKS_OBJS = $(call objs,$(LIBWASI_EMULATED_PROCESS_CLOCKS_SOURCES))
407417
LIBWASI_EMULATED_GETPID_OBJS = $(call objs,$(LIBWASI_EMULATED_GETPID_SOURCES))
@@ -473,7 +483,6 @@ MUSL_OMIT_HEADERS += \
473483
"netdb.h" \
474484
"resolv.h" \
475485
"pty.h" \
476-
"setjmp.h" \
477486
"ulimit.h" \
478487
"sys/xattr.h" \
479488
"wordexp.h" \
@@ -510,6 +519,7 @@ LIBWASI_EMULATED_SIGNAL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_SIGN
510519
LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS))
511520
LIBDL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBDL_OBJS))
512521
BULK_MEMORY_SO_OBJS = $(patsubst %.o,%.pic.o,$(BULK_MEMORY_OBJS))
522+
SJLJ_SO_OBJS = $(patsubst %.o,%.pic.o,$(SJLJ_OBJS))
513523
DLMALLOC_SO_OBJS = $(patsubst %.o,%.pic.o,$(DLMALLOC_OBJS))
514524
LIBC_BOTTOM_HALF_ALL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBC_BOTTOM_HALF_ALL_OBJS))
515525
LIBC_TOP_HALF_ALL_SO_OBJS = $(patsubst %.o,%.pic.o,$(LIBC_TOP_HALF_ALL_OBJS))
@@ -524,6 +534,7 @@ PIC_OBJS = \
524534
$(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS) \
525535
$(LIBDL_SO_OBJS) \
526536
$(BULK_MEMORY_SO_OBJS) \
537+
$(SJLJ_SO_OBJS) \
527538
$(DLMALLOC_SO_OBJS) \
528539
$(LIBC_BOTTOM_HALF_ALL_SO_OBJS) \
529540
$(LIBC_TOP_HALF_ALL_SO_OBJS) \
@@ -597,6 +608,9 @@ $(BULK_MEMORY_OBJS) $(BULK_MEMORY_SO_OBJS): CFLAGS += \
597608
$(BULK_MEMORY_OBJS) $(BULK_MEMORY_SO_OBJS): CFLAGS += \
598609
-DBULK_MEMORY_THRESHOLD=$(BULK_MEMORY_THRESHOLD)
599610

611+
$(SJLJ_OBJS) $(SJLJ_SO_OBJS): CFLAGS += \
612+
-mllvm -wasm-enable-sjlj
613+
600614
$(LIBWASI_EMULATED_SIGNAL_MUSL_OBJS) $(LIBWASI_EMULATED_SIGNAL_MUSL_SO_OBJS): CFLAGS += \
601615
-D_WASI_EMULATED_SIGNAL
602616

expected/wasm32-wasi-preview2/include-all.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
#include <sched.h>
118118
#include <search.h>
119119
#include <semaphore.h>
120+
#include <setjmp.h>
120121
#include <stdalign.h>
121122
#include <stdbool.h>
122123
#include <stdc-predef.h>

expected/wasm32-wasi-preview2/predefined-macros.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,7 @@
24122412
#define _SC_XOPEN_XPG4 100
24132413
#define _SEARCH_H
24142414
#define _SEMAPHORE_H
2415+
#define _SETJMP_H
24152416
#define _SIZE_T
24162417
#define _STDALIGN_H
24172418
#define _STDBOOL_H

expected/wasm32-wasi-threads/include-all.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
#include <sched.h>
119119
#include <search.h>
120120
#include <semaphore.h>
121+
#include <setjmp.h>
121122
#include <stdalign.h>
122123
#include <stdbool.h>
123124
#include <stdc-predef.h>

expected/wasm32-wasi-threads/predefined-macros.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,6 +2352,7 @@
23522352
#define _SC_XOPEN_XPG4 100
23532353
#define _SEARCH_H
23542354
#define _SEMAPHORE_H
2355+
#define _SETJMP_H
23552356
#define _SIZE_T
23562357
#define _STDALIGN_H
23572358
#define _STDBOOL_H

expected/wasm32-wasi/include-all.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
#include <sched.h>
118118
#include <search.h>
119119
#include <semaphore.h>
120+
#include <setjmp.h>
120121
#include <stdalign.h>
121122
#include <stdbool.h>
122123
#include <stdc-predef.h>

expected/wasm32-wasi/predefined-macros.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,6 +2315,7 @@
23152315
#define _SC_XOPEN_XPG4 100
23162316
#define _SEARCH_H
23172317
#define _SEMAPHORE_H
2318+
#define _SETJMP_H
23182319
#define _SIZE_T
23192320
#define _STDALIGN_H
23202321
#define _STDBOOL_H
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/* note: right now, only the first word is actually used */
2+
typedef unsigned long __jmp_buf[8];

libc-top-half/musl/include/setjmp.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ extern "C" {
77

88
#include <features.h>
99

10-
#ifdef __wasilibc_unmodified_upstream /* WASI has no setjmp */
10+
/* WASI has no setjmp */
11+
#if defined(__wasilibc_unmodified_upstream) || defined(__wasm_exception_handling__)
1112
#include <bits/setjmp.h>
1213

1314
typedef struct __jmp_buf_tag {
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
3+
*/
4+
5+
#include <stdint.h>
6+
#include <stdlib.h>
7+
8+
struct entry {
9+
uint32_t id;
10+
uint32_t label;
11+
};
12+
13+
static _Thread_local struct state {
14+
uint32_t id;
15+
uint32_t size;
16+
struct arg {
17+
void *env;
18+
int val;
19+
} arg;
20+
} g_state;
21+
22+
/*
23+
* table is allocated at the entry of functions which call setjmp.
24+
*
25+
* table = malloc(40);
26+
* size = 4;
27+
* *(int *)table = 0;
28+
*/
29+
_Static_assert(sizeof(struct entry) * (4 + 1) <= 40, "entry size");
30+
31+
void *
32+
saveSetjmp(void *env, uint32_t label, void *table, uint32_t size)
33+
{
34+
struct state *state = &g_state;
35+
struct entry *e = table;
36+
uint32_t i;
37+
for (i = 0; i < size; i++) {
38+
if (e[i].id == 0) {
39+
uint32_t id = ++state->id;
40+
*(uint32_t *)env = id;
41+
e[i].id = id;
42+
e[i].label = label;
43+
/*
44+
* note: only the first word is zero-initialized
45+
* by the caller.
46+
*/
47+
e[i + 1].id = 0;
48+
goto done;
49+
}
50+
}
51+
size *= 2;
52+
void *p = realloc(table, sizeof(*e) * (size + 1));
53+
if (p == NULL) {
54+
__builtin_trap();
55+
}
56+
table = p;
57+
done:
58+
state->size = size;
59+
return table;
60+
}
61+
62+
uint32_t
63+
testSetjmp(unsigned int id, void *table, uint32_t size)
64+
{
65+
struct entry *e = table;
66+
uint32_t i;
67+
for (i = 0; i < size; i++) {
68+
if (e[i].id == id) {
69+
return e[i].label;
70+
}
71+
}
72+
return 0;
73+
}
74+
75+
uint32_t
76+
getTempRet0()
77+
{
78+
struct state *state = &g_state;
79+
return state->size;
80+
}
81+
82+
void
83+
__wasm_longjmp(void *env, int val)
84+
{
85+
struct state *state = &g_state;
86+
struct arg *arg = &state->arg;
87+
arg->env = env;
88+
arg->val = val;
89+
__builtin_wasm_throw(1, arg);
90+
}

0 commit comments

Comments
 (0)