Skip to content

Instantly share code, notes, and snippets.

@robbertvanginkel
Created January 4, 2023 16:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robbertvanginkel/5cb999d5b6fb094bd0d286c644617640 to your computer and use it in GitHub Desktop.
Save robbertvanginkel/5cb999d5b6fb094bd0d286c644617640 to your computer and use it in GitHub Desktop.
quickjs wasi wazero
From 58e4fc1373b6ee5d3810b7e4668762de87731b2f Mon Sep 17 00:00:00 2001
From: Robbert van Ginkel <rvanginkel@buf.build>
Date: Wed, 4 Jan 2023 11:05:15 -0500
Subject: [PATCH] Add wazero based build script
To build the quickjs interpreter, some js files need to be transformed into
quickjs bytecode using qjsc.
---
build.sh | 36 ++++++++++++++++++++++++++++++++++++
qjs.c | 4 ++--
qjsc.c | 2 +-
quickjs-libc.c | 50 ++++++++++++++++++++++++++++++++++++++++++++------
quickjs.c | 12 ++++++------
quickjs.h | 2 +-
6 files changed, 90 insertions(+), 16 deletions(-)
create mode 100644 build.sh
diff --git a/build.sh b/build.sh
new file mode 100644
index 0000000..463716a
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+
+set -euxo pipefail
+
+WASI_SDK_PATH="${WASI_SDK_PATH:-/opt/wasi-sdk}"
+
+SHARED_FILES=(libunicode cutils libbf libregexp quickjs quickjs-libc)
+
+"$WASI_SDK_PATH/bin/clang" \
+ "--sysroot=$WASI_SDK_PATH/share/wasi-sysroot" \
+ -c "${SHARED_FILES[@]/%/.c}" qjsc.c \
+ -DCONFIG_VERSION='"wasi"' \
+ -DCONFIG_BIGNUM=y \
+ -D_WASI_EMULATED_SIGNAL \
+ -D_WASI_EMULATED_GETPID \
+ -O3
+
+"$WASI_SDK_PATH/bin/clang" \
+ "--sysroot=$WASI_SDK_PATH/share/wasi-sysroot" \
+ -lwasi-emulated-signal -lwasi-emulated-getpid \
+ -O3 \
+ "${SHARED_FILES[@]/%/.o}" qjsc.o -o qjsc.wasm
+
+wazero run -mount ".:/" qjsc.wasm -- -c -o /repl.c -m /repl.js
+wazero run -mount ".:/" qjsc.wasm -- -fbignum -c -o /qjscalc.c /qjscalc.js
+
+"$WASI_SDK_PATH/bin/clang" \
+ "--sysroot=$WASI_SDK_PATH/share/wasi-sysroot" \
+ "${SHARED_FILES[@]/%/.o}" \
+ repl.c qjs.c qjscalc.c \
+ -I . \
+ -DCONFIG_VERSION='"wasi"' \
+ -DCONFIG_BIGNUM=y \
+ -D_WASI_EMULATED_PROCESS_CLOCKS -lwasi-emulated-process-clocks \
+ -D_WASI_EMULATED_SIGNAL -lwasi-emulated-signal \
+ -O3 -g -o qjs.wasm
diff --git a/qjs.c b/qjs.c
index d56b843..1039b86 100644
--- a/qjs.c
+++ b/qjs.c
@@ -146,7 +146,7 @@ static inline size_t js_trace_malloc_usable_size(void *ptr)
return malloc_size(ptr);
#elif defined(_WIN32)
return _msize(ptr);
-#elif defined(EMSCRIPTEN)
+#elif defined(EMSCRIPTEN) || defined(__wasi__)
return 0;
#elif defined(__linux__)
return malloc_usable_size(ptr);
@@ -268,7 +268,7 @@ static const JSMallocFunctions trace_mf = {
malloc_size,
#elif defined(_WIN32)
(size_t (*)(const void *))_msize,
-#elif defined(EMSCRIPTEN)
+#elif defined(EMSCRIPTEN) || defined(__wasi__)
NULL,
#elif defined(__linux__)
(size_t (*)(const void *))malloc_usable_size,
diff --git a/qjsc.c b/qjsc.c
index b9f1e4c..c1a9eaf 100644
--- a/qjsc.c
+++ b/qjsc.c
@@ -29,7 +29,7 @@
#include <assert.h>
#include <unistd.h>
#include <errno.h>
-#if !defined(_WIN32)
+#if !defined(_WIN32) && !defined(__wasi__)
#include <sys/wait.h>
#endif
diff --git a/quickjs-libc.c b/quickjs-libc.c
index e180dd0..43b8c6f 100644
--- a/quickjs-libc.c
+++ b/quickjs-libc.c
@@ -42,10 +42,12 @@
#include <conio.h>
#include <utime.h>
#else
+#if !defined(__wasi__)
#include <dlfcn.h>
#include <termios.h>
-#include <sys/ioctl.h>
#include <sys/wait.h>
+#endif
+#include <sys/ioctl.h>
#if defined(__APPLE__)
typedef sig_t sighandler_t;
@@ -57,7 +59,7 @@ typedef sig_t sighandler_t;
#endif
-#if !defined(_WIN32)
+#if !defined(_WIN32) && !defined(__wasi__)
/* enable the os.Worker API. IT relies on POSIX threads */
#define USE_WORKER
#endif
@@ -453,7 +455,7 @@ typedef JSModuleDef *(JSInitModuleFunc)(JSContext *ctx,
const char *module_name);
-#if defined(_WIN32)
+#if defined(_WIN32) || defined(__wasi__)
static JSModuleDef *js_module_loader_so(JSContext *ctx,
const char *module_name)
{
@@ -530,7 +532,7 @@ int js_module_set_import_meta(JSContext *ctx, JSValueConst func_val,
return -1;
if (!strchr(module_name, ':')) {
strcpy(buf, "file://");
-#if !defined(_WIN32)
+#if !defined(_WIN32) && !defined(__wasi__)
/* realpath() cannot be used with modules compiled with qjsc
because the corresponding module source code is not
necessarily present */
@@ -680,6 +682,7 @@ static JSValue js_std_unsetenv(JSContext *ctx, JSValueConst this_val,
static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
+#if !defined(__wasi__)
char **envp;
const char *name, *p, *value;
JSValue obj;
@@ -712,6 +715,12 @@ static JSValue js_std_getenviron(JSContext *ctx, JSValueConst this_val,
fail:
JS_FreeValue(ctx, obj);
return JS_EXCEPTION;
+#else
+ JSValue obj;
+ obj = JS_NewObject(ctx);
+ JS_FreeValue(ctx,obj);
+ return obj;
+#endif
}
static JSValue js_std_gc(JSContext *ctx, JSValueConst this_val,
@@ -797,9 +806,11 @@ static void js_std_file_finalizer(JSRuntime *rt, JSValue val)
JSSTDFile *s = JS_GetOpaque(val, js_std_file_class_id);
if (s) {
if (s->f && s->close_in_finalizer) {
+#if !defined(__wasi__)
if (s->is_popen)
pclose(s->f);
else
+#endif
fclose(s->f);
}
js_free_rt(rt, s);
@@ -901,6 +912,7 @@ static JSValue js_std_open(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+#if !defined(__wasi__)
static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -936,6 +948,7 @@ static JSValue js_std_popen(JSContext *ctx, JSValueConst this_val,
JS_FreeCString(ctx, mode);
return JS_EXCEPTION;
}
+#endif
static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -970,6 +983,7 @@ static JSValue js_std_fdopen(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
}
+#if !defined(__wasi__)
static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
@@ -981,6 +995,7 @@ static JSValue js_std_tmpfile(JSContext *ctx, JSValueConst this_val,
return JS_NULL;
return js_new_std_file(ctx, f, TRUE, FALSE);
}
+#endif
static JSValue js_std_sprintf(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -1041,8 +1056,10 @@ static JSValue js_std_file_close(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
if (!s->f)
return JS_ThrowTypeError(ctx, "invalid file handle");
+#if !defined(__wasi__)
if (s->is_popen)
err = js_get_errno(pclose(s->f));
+#endif
else
err = js_get_errno(fclose(s->f));
s->f = NULL;
@@ -1273,6 +1290,7 @@ static JSValue js_std_file_putByte(JSContext *ctx, JSValueConst this_val,
}
/* urlGet */
+#if !defined(__wasi__)
#define URL_GET_PROGRAM "curl -s -i"
#define URL_GET_BUF_SIZE 4096
@@ -1457,6 +1475,7 @@ static JSValue js_std_urlGet(JSContext *ctx, JSValueConst this_val,
JS_FreeValue(ctx, response);
return JS_EXCEPTION;
}
+#endif
static JSClassDef js_std_file_class = {
"FILE",
@@ -1489,16 +1508,22 @@ static const JSCFunctionListEntry js_std_funcs[] = {
JS_CFUNC_DEF("setenv", 1, js_std_setenv ),
JS_CFUNC_DEF("unsetenv", 1, js_std_unsetenv ),
JS_CFUNC_DEF("getenviron", 1, js_std_getenviron ),
+#if !defined(__wasi__)
JS_CFUNC_DEF("urlGet", 1, js_std_urlGet ),
+#endif
JS_CFUNC_DEF("loadFile", 1, js_std_loadFile ),
JS_CFUNC_DEF("strerror", 1, js_std_strerror ),
JS_CFUNC_DEF("parseExtJSON", 1, js_std_parseExtJSON ),
/* FILE I/O */
JS_CFUNC_DEF("open", 2, js_std_open ),
+#if !defined(__wasi__)
JS_CFUNC_DEF("popen", 2, js_std_popen ),
+#endif
JS_CFUNC_DEF("fdopen", 2, js_std_fdopen ),
+#if !defined(__wasi__)
JS_CFUNC_DEF("tmpfile", 0, js_std_tmpfile ),
+#endif
JS_CFUNC_MAGIC_DEF("puts", 1, js_std_file_puts, 0 ),
JS_CFUNC_DEF("printf", 1, js_std_printf ),
JS_CFUNC_DEF("sprintf", 1, js_std_sprintf ),
@@ -1665,7 +1690,7 @@ static JSValue js_os_isatty(JSContext *ctx, JSValueConst this_val,
return JS_EXCEPTION;
return JS_NewBool(ctx, (isatty(fd) != 0));
}
-
+#if !defined(__wasi__)
#if defined(_WIN32)
static JSValue js_os_ttyGetWinSize(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -1770,6 +1795,7 @@ static JSValue js_os_ttySetRaw(JSContext *ctx, JSValueConst this_val,
}
#endif /* !_WIN32 */
+#endif /* !__wasi__ */
static JSValue js_os_remove(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -1919,6 +1945,7 @@ typedef void (*sighandler_t)(int sig_num);
static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
{
+#if !defined(__wasi__)
JSRuntime *rt = JS_GetRuntime(ctx);
JSThreadState *ts = JS_GetRuntimeOpaque(rt);
JSOSSignalHandler *sh;
@@ -1960,6 +1987,7 @@ static JSValue js_os_signal(JSContext *ctx, JSValueConst this_val,
sh->func = JS_DupValue(ctx, func);
signal(sig_num, os_signal_handler);
}
+#endif
return JS_UNDEFINED;
}
@@ -2650,6 +2678,7 @@ static char *realpath(const char *path, char *buf)
}
#endif
+#if !defined(__wasi__)
/* return [path, errorcode] */
static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
int argc, JSValueConst *argv)
@@ -2671,6 +2700,7 @@ static JSValue js_os_realpath(JSContext *ctx, JSValueConst this_val,
}
return make_string_error(ctx, buf, err);
}
+#endif
#if !defined(_WIN32)
static JSValue js_os_symlink(JSContext *ctx, JSValueConst this_val,
@@ -2717,6 +2747,7 @@ static JSValue js_os_readlink(JSContext *ctx, JSValueConst this_val,
return make_string_error(ctx, buf, err);
}
+#if !defined(__wasi__)
static char **build_envp(JSContext *ctx, JSValueConst obj)
{
uint32_t len, i;
@@ -3119,6 +3150,7 @@ static JSValue js_os_dup2(JSContext *ctx, JSValueConst this_val,
}
#endif /* !_WIN32 */
+#endif /* !__wasi__ */
#ifdef USE_WORKER
@@ -3569,7 +3601,7 @@ void js_std_set_worker_new_context_func(JSContext *(*func)(JSRuntime *rt))
#define OS_PLATFORM "win32"
#elif defined(__APPLE__)
#define OS_PLATFORM "darwin"
-#elif defined(EMSCRIPTEN)
+#elif defined(EMSCRIPTEN) || defined(__wasi__)
#define OS_PLATFORM "js"
#else
#define OS_PLATFORM "linux"
@@ -3595,8 +3627,10 @@ static const JSCFunctionListEntry js_os_funcs[] = {
JS_CFUNC_MAGIC_DEF("read", 4, js_os_read_write, 0 ),
JS_CFUNC_MAGIC_DEF("write", 4, js_os_read_write, 1 ),
JS_CFUNC_DEF("isatty", 1, js_os_isatty ),
+#if !defined(__wasi__)
JS_CFUNC_DEF("ttyGetWinSize", 1, js_os_ttyGetWinSize ),
JS_CFUNC_DEF("ttySetRaw", 1, js_os_ttySetRaw ),
+#endif
JS_CFUNC_DEF("remove", 1, js_os_remove ),
JS_CFUNC_DEF("rename", 2, js_os_rename ),
JS_CFUNC_MAGIC_DEF("setReadHandler", 2, js_os_setReadHandler, 0 ),
@@ -3644,11 +3678,14 @@ static const JSCFunctionListEntry js_os_funcs[] = {
JS_CFUNC_MAGIC_DEF("stat", 1, js_os_stat, 0 ),
JS_CFUNC_DEF("utimes", 3, js_os_utimes ),
JS_CFUNC_DEF("sleep", 1, js_os_sleep ),
+#if !defined(__wasi__)
JS_CFUNC_DEF("realpath", 1, js_os_realpath ),
+#endif
#if !defined(_WIN32)
JS_CFUNC_MAGIC_DEF("lstat", 1, js_os_stat, 1 ),
JS_CFUNC_DEF("symlink", 2, js_os_symlink ),
JS_CFUNC_DEF("readlink", 1, js_os_readlink ),
+#if !defined(__wasi__)
JS_CFUNC_DEF("exec", 1, js_os_exec ),
JS_CFUNC_DEF("waitpid", 2, js_os_waitpid ),
OS_FLAG(WNOHANG),
@@ -3657,6 +3694,7 @@ static const JSCFunctionListEntry js_os_funcs[] = {
JS_CFUNC_DEF("dup", 1, js_os_dup ),
JS_CFUNC_DEF("dup2", 2, js_os_dup2 ),
#endif
+#endif
};
static int js_os_init(JSContext *ctx, JSModuleDef *m)
diff --git a/quickjs.c b/quickjs.c
index 48aeffc..1cb736a 100644
--- a/quickjs.c
+++ b/quickjs.c
@@ -50,7 +50,7 @@
#define OPTIMIZE 1
#define SHORT_OPCODES 1
-#if defined(EMSCRIPTEN)
+#if defined(EMSCRIPTEN) || defined(__wasi__)
#define DIRECT_DISPATCH 0
#else
#define DIRECT_DISPATCH 1
@@ -62,18 +62,18 @@
#define MALLOC_OVERHEAD 8
#endif
-#if !defined(_WIN32)
+#if !defined(_WIN32) && !defined(__wasi__)
/* define it if printf uses the RNDN rounding mode instead of RNDNA */
#define CONFIG_PRINTF_RNDN
#endif
/* define to include Atomics.* operations which depend on the OS
threads */
-#if !defined(EMSCRIPTEN)
+#if !defined(EMSCRIPTEN) && !defined(__wasi__)
#define CONFIG_ATOMICS
#endif
-#if !defined(EMSCRIPTEN)
+#if !defined(EMSCRIPTEN) && !defined(__wasi__)
/* enable stack limitation */
#define CONFIG_STACK_CHECK
#endif
@@ -1680,7 +1680,7 @@ static inline size_t js_def_malloc_usable_size(void *ptr)
return malloc_size(ptr);
#elif defined(_WIN32)
return _msize(ptr);
-#elif defined(EMSCRIPTEN)
+#elif defined(EMSCRIPTEN) || defined(__wasi__)
return 0;
#elif defined(__linux__)
return malloc_usable_size(ptr);
@@ -1754,7 +1754,7 @@ static const JSMallocFunctions def_malloc_funcs = {
malloc_size,
#elif defined(_WIN32)
(size_t (*)(const void *))_msize,
-#elif defined(EMSCRIPTEN)
+#elif defined(EMSCRIPTEN) || defined(__wasi__)
NULL,
#elif defined(__linux__)
(size_t (*)(const void *))malloc_usable_size,
diff --git a/quickjs.h b/quickjs.h
index d4a5cd3..7e90f00 100644
--- a/quickjs.h
+++ b/quickjs.h
@@ -53,7 +53,7 @@ typedef struct JSClass JSClass;
typedef uint32_t JSClassID;
typedef uint32_t JSAtom;
-#if INTPTR_MAX >= INT64_MAX
+#if INTPTR_MAX >= INT64_MAX && !defined(__wasi__)
#define JS_PTR64
#define JS_PTR64_DEF(a) a
#else
--
2.38.1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment