summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--auto/modules/wasm21
-rw-r--r--src/wasm/nxt_rt_wamr.c338
-rw-r--r--src/wasm/nxt_wasm.c1
-rw-r--r--src/wasm/nxt_wasm.h9
4 files changed, 366 insertions, 3 deletions
diff --git a/auto/modules/wasm b/auto/modules/wasm
index 1f388de6..17648b5f 100644
--- a/auto/modules/wasm
+++ b/auto/modules/wasm
@@ -62,6 +62,8 @@ NXT_WASM_LIB_PATH=${NXT_WASM_LIB_PATH=}
NXT_WASM_LDFLAGS=
if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then
NXT_WASM_LDFLAGS=-lwasmtime
+elif [ "$NXT_WASM_RUNTIME" = "wamr" ]; then
+ NXT_WASM_LDFLAGS="-lvmlib -lm"
fi
NXT_WASM_ADDITIONAL_FLAGS="-fno-strict-aliasing \
-Wno-missing-field-initializers \
@@ -111,10 +113,25 @@ if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then
return 0;
}"
+elif [ "$NXT_WASM_RUNTIME" = "wamr" ]; then
+ nxt_feature="wamr"
+ nxt_feature_name=""
+ nxt_feature_run=no
+ nxt_feature_incs="-I${NXT_WASM_INCLUDE_PATH}"
+ nxt_feature_libs="-L${NXT_WASM_LIB_PATH} $NXT_WASM_LDFLAGS"
+ nxt_feature_test="
+ #include <wasm_export.h>
- . auto/feature
+ int main(void) {
+ if (!wasm_runtime_init())
+ return 1;
+
+ return 0;
+ }"
fi
+. auto/feature
+
if [ $nxt_found = no ]; then
$echo
$echo $0: error: no $NXT_WASM_RUNTIME found.
@@ -143,6 +160,8 @@ NXT_WASM_MODULE_SRCS=" \
if [ "$NXT_WASM_RUNTIME" = "wasmtime" ]; then
NXT_WASM_MODULE_SRCS="$NXT_WASM_MODULE_SRCS src/wasm/nxt_rt_wasmtime.c"
+elif [ "$NXT_WASM_RUNTIME" = "wamr" ]; then
+ NXT_WASM_MODULE_SRCS="$NXT_WASM_MODULE_SRCS src/wasm/nxt_rt_wamr.c"
fi
diff --git a/src/wasm/nxt_rt_wamr.c b/src/wasm/nxt_rt_wamr.c
new file mode 100644
index 00000000..d33965ba
--- /dev/null
+++ b/src/wasm/nxt_rt_wamr.c
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) Andrew Clayton
+ * Copyright (C) F5, Inc.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <wasm_export.h>
+
+#include "nxt_wasm.h"
+
+
+typedef struct nxt_wamr_ctx_s nxt_wamr_ctx_t;
+
+struct nxt_wamr_ctx_s {
+ uint8_t *mod_buf;
+ wasm_module_t module;
+ wasm_module_inst_t module_inst;
+ wasm_exec_env_t exec_env;
+};
+
+static nxt_wamr_ctx_t nxt_wamr_ctx;
+
+
+static void
+nxt_wamr_err_msg(const char *fmt, ...)
+{
+ char dstr[20];
+ time_t t;
+ va_list args;
+ struct tm *tmp;
+
+ t = time(NULL);
+ tmp = localtime(&t);
+ if (tmp == NULL) {
+ return;
+ }
+
+ strftime(dstr, sizeof(dstr), "%Y/%m/%d %T", tmp);
+
+ fprintf(stderr, "%s [WAMR ERROR] %d ", dstr, getpid());
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+ fprintf(stderr, "\n");
+}
+
+
+static uint32_t
+nxt_wasm_get_init_mem_size(wasm_exec_env_t exec_env)
+{
+ return NXT_WASM_MEM_SIZE;
+}
+
+
+static void
+nxt_wasm_response_end(wasm_exec_env_t exec_env)
+{
+ nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env);
+
+ nxt_wasm_do_response_end(ctx);
+}
+
+
+static void
+nxt_wasm_send_response(wasm_exec_env_t exec_env, uint32_t offset)
+{
+ nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env);
+
+ nxt_wasm_do_send_response(ctx, offset);
+}
+
+
+static void
+nxt_wasm_send_headers(wasm_exec_env_t exec_env, uint32_t offset)
+{
+ nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env);
+
+ nxt_wasm_do_send_headers(ctx, offset);
+}
+
+
+static void
+nxt_wasm_set_resp_status(wasm_exec_env_t exec_env, uint16_t status)
+{
+ nxt_wasm_ctx_t *ctx = wasm_runtime_get_user_data(exec_env);
+
+ ctx->status = status;
+}
+
+
+static void
+nxt_wamr_execute_hook(const nxt_wasm_ctx_t *ctx, nxt_wasm_fh_t hook)
+{
+ bool ok;
+ const char *name = ctx->fh[hook].func_name;
+ nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx;
+ const nxt_wasm_func_t *func = ctx->fh[hook].func;
+
+ if (name == NULL) {
+ return;
+ }
+
+ ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func,
+ 0, NULL, 0, NULL);
+ if (!ok) {
+ nxt_wamr_err_msg("failed to call hook function [%s]. (%s)", name,
+ wasm_runtime_get_exception(rt_ctx->module_inst));
+ }
+}
+
+
+static int
+nxt_wamr_execute_request(const nxt_wasm_ctx_t *ctx)
+{
+ bool ok;
+ uint32_t i = 0;
+ wasm_val_t args[1] = { };
+ wasm_val_t results[1] = { };
+ nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx;
+ const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_REQUEST].func;
+
+ args[i].kind = WASM_I32;
+ args[i++].of.i32 = ctx->baddr_off;
+
+ ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func,
+ 1, results, i, args);
+ if (!ok) {
+ nxt_wamr_err_msg("Failed to call function [->wasm_request_handler]. "
+ "(%s)",
+ wasm_runtime_get_exception(rt_ctx->module_inst));
+ return -1;
+ }
+
+ return results[0].of.i32;
+}
+
+
+static bool
+nxt_wamr_set_function_imports(void)
+{
+ int nr_funcs;
+ bool ok;
+
+ static NativeSymbol import_functions[] = {
+ EXPORT_WASM_API_WITH_SIG(nxt_wasm_get_init_mem_size, "()i"),
+ EXPORT_WASM_API_WITH_SIG(nxt_wasm_response_end, "()"),
+ EXPORT_WASM_API_WITH_SIG(nxt_wasm_send_response, "(i)"),
+ EXPORT_WASM_API_WITH_SIG(nxt_wasm_send_headers, "(i)"),
+ EXPORT_WASM_API_WITH_SIG(nxt_wasm_set_resp_status, "(i)"),
+ };
+
+ nr_funcs = sizeof(import_functions) / sizeof(NativeSymbol);
+
+ ok = wasm_runtime_register_natives("env", import_functions, nr_funcs);
+ if (!ok) {
+ return false;
+ }
+
+ return true;
+}
+
+
+static int
+nxt_wamr_get_function_exports(nxt_wasm_ctx_t *ctx)
+{
+ int i;
+ nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx;
+
+ for (i = 0; i < NXT_WASM_FH_NR; i++) {
+ if (ctx->fh[i].func_name == NULL) {
+ continue;
+ }
+
+ ctx->fh[i].func = wasm_runtime_lookup_function(rt_ctx->module_inst,
+ ctx->fh[i].func_name,
+ NULL);
+ if (ctx->fh[i].func == NULL) {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static void
+nxt_wamr_wasi_init(const nxt_wasm_ctx_t *ctx)
+{
+ nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx;
+
+ wasm_runtime_set_wasi_args(rt_ctx->module,
+ (const char **)ctx->dirs, ctx->nr_dirs,
+ NULL, 0, NULL, 0, NULL, 0);
+}
+
+
+static int
+nxt_wamr_init_memory(nxt_wasm_ctx_t *ctx)
+{
+ bool ok;
+ uint32_t i = 0;
+ wasm_val_t args[1] = { };
+ wasm_val_t results[1] = { };
+ nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx;
+ const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_MALLOC].func;
+
+ args[i].kind = WASM_I32;
+ args[i++].of.i32 = NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE;
+
+ ok = wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func,
+ 1, results, i, args);
+ if (!ok) {
+ return -1;
+ }
+
+ ctx->baddr_off = results[0].of.i32;
+ ctx->baddr = wasm_runtime_addr_app_to_native(rt_ctx->module_inst,
+ ctx->baddr_off);
+
+ return 0;
+}
+
+
+static int
+nxt_wamr_init(nxt_wasm_ctx_t *ctx)
+{
+ int err;
+ bool ok;
+ char error_buf[128];
+ FILE *fp;
+ size_t file_size;
+ uint32_t stack_size = 16384, heap_size = 16384;
+ nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx;
+
+ ok = wasm_runtime_init();
+ if (!ok) {
+ nxt_wamr_err_msg("wasm_runtime_init() failed");
+ return -1;
+ }
+
+ ok = nxt_wamr_set_function_imports();
+ if (!ok) {
+ nxt_wamr_err_msg("nxt_wamr_set_function_imports() failed");
+ return -1;
+ }
+
+ fp = fopen(ctx->module_path, "r");
+ if (!fp) {
+ nxt_wamr_err_msg("fopen(\"%s\") failed", ctx->module_path);
+ return -1;
+ }
+
+ fseek(fp, 0L, SEEK_END);
+ file_size = ftell(fp);
+ rt_ctx->mod_buf = malloc(file_size);
+ fseek(fp, 0L, SEEK_SET);
+ if (fread(rt_ctx->mod_buf, file_size, 1, fp) != 1) {
+ nxt_wamr_err_msg("fread(\"%s\") failed", ctx->module_path);
+ return -1;
+ }
+ fclose(fp);
+
+ rt_ctx->module = wasm_runtime_load(rt_ctx->mod_buf, file_size, error_buf,
+ sizeof(error_buf));
+ if (rt_ctx->module == NULL) {
+ nxt_wamr_err_msg("wasm_runtime_load() failed");
+ return -1;
+ }
+
+ nxt_wamr_wasi_init(ctx);
+
+ rt_ctx->module_inst = wasm_runtime_instantiate(rt_ctx->module, stack_size,
+ heap_size, error_buf,
+ sizeof(error_buf));
+ if (rt_ctx->module_inst == NULL) {
+ nxt_wamr_err_msg("wasm_runtime_instantiate() failed");
+ return -1;
+ }
+
+ rt_ctx->exec_env = wasm_runtime_create_exec_env(rt_ctx->module_inst,
+ stack_size);
+ if (rt_ctx->exec_env == NULL) {
+ nxt_wamr_err_msg("wasm_runtime_create_exec_env() failed");
+ return -1;
+ }
+ wasm_runtime_set_user_data(rt_ctx->exec_env, ctx);
+
+ err = nxt_wamr_get_function_exports(ctx);
+ if (err) {
+ nxt_wamr_err_msg("nxt_wamr_get_function_exports() failed");
+ return -1;
+ }
+
+ err = nxt_wamr_init_memory(ctx);
+ if (err) {
+ nxt_wamr_err_msg("nxt_wamr_init_memory() failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void
+nxt_wamr_destroy(const nxt_wasm_ctx_t *ctx)
+{
+ uint32_t i = 0;
+ wasm_val_t args[1] = { };
+ nxt_wamr_ctx_t *rt_ctx = &nxt_wamr_ctx;
+ const nxt_wasm_func_t *func = ctx->fh[NXT_WASM_FH_FREE].func;
+
+ args[i].kind = WASM_I32;
+ args[i++].of.i32 = ctx->baddr_off;
+
+ wasm_runtime_call_wasm_a(rt_ctx->exec_env, (nxt_wasm_func_t)func,
+ 0, NULL, i, args);
+
+ wasm_runtime_destroy_exec_env(rt_ctx->exec_env);
+ wasm_runtime_deinstantiate(rt_ctx->module_inst);
+ wasm_runtime_unload(rt_ctx->module);
+ free(rt_ctx->mod_buf);
+ wasm_runtime_destroy();
+}
+
+
+const nxt_wasm_operations_t nxt_wasm_ops = {
+ .init = nxt_wamr_init,
+ .destroy = nxt_wamr_destroy,
+ .exec_request = nxt_wamr_execute_request,
+ .exec_hook = nxt_wamr_execute_hook,
+};
diff --git a/src/wasm/nxt_wasm.c b/src/wasm/nxt_wasm.c
index 92ed57ab..b2827bd6 100644
--- a/src/wasm/nxt_wasm.c
+++ b/src/wasm/nxt_wasm.c
@@ -292,6 +292,7 @@ nxt_wasm_setup(nxt_task_t *task, nxt_process_t *process,
nxt_wasm_ctx.dirs[i] = nxt_zalloc(str.length + 1);
memcpy(nxt_wasm_ctx.dirs[i], str.start, str.length);
}
+ nxt_wasm_ctx.nr_dirs = n;
out_init:
err = nxt_wops->init(&nxt_wasm_ctx);
diff --git a/src/wasm/nxt_wasm.h b/src/wasm/nxt_wasm.h
index 6bc3ae35..90e91b2b 100644
--- a/src/wasm/nxt_wasm.h
+++ b/src/wasm/nxt_wasm.h
@@ -11,9 +11,11 @@
#include <nxt_unit.h>
-#include <wasm.h>
#if defined(NXT_HAVE_WASM_WASMTIME)
+#include <wasm.h>
#include <wasmtime.h>
+#elif defined(NXT_HAVE_WASM_WAMR)
+#include <wasm_export.h>
#endif
@@ -21,7 +23,9 @@
#define NXT_WASM_MEM_SIZE (32UL * 1024 * 1024)
#if defined(NXT_HAVE_WASM_WASMTIME)
-typedef wasmtime_func_t nxt_wasm_func_t;
+typedef wasmtime_func_t nxt_wasm_func_t;
+#elif defined(NXT_HAVE_WASM_WAMR)
+typedef wasm_function_inst_t nxt_wasm_func_t;
#endif
@@ -113,6 +117,7 @@ struct nxt_wasm_ctx_s {
nxt_wasm_func_handler_t fh[NXT_WASM_FH_NR];
char **dirs;
+ size_t nr_dirs;
nxt_unit_request_info_t *req;