1
1
mirror of https://github.com/kanaka/mal.git synced 2024-10-26 14:22:25 +03:00

wasm: wax runtime. Use WASI preopen process.

Add wasi-sdk to Dockerfile to be able to compile C code to wasm that
uses WASI API calls.
This commit is contained in:
Joel Martin 2019-04-19 01:07:08 -05:00
parent d88adace47
commit 030f725c4a
8 changed files with 79 additions and 40 deletions

View File

@ -95,6 +95,7 @@ matrix:
- {env: IMPL=vhdl, services: [docker]}
- {env: IMPL=vimscript, services: [docker]}
- {env: IMPL=wasm wasm_MODE=wasmtime, services: [docker]}
- {env: IMPL=wasm wasm_MODE=wax, services: [docker]}
- {env: IMPL=wasm wasm_MODE=node, services: [docker]}
- {env: IMPL=wasm wasm_MODE=wace_libc, services: [docker]}
- {env: IMPL=wasm wasm_MODE=warpy, services: [docker]}

View File

@ -1035,6 +1035,7 @@ The WebAssembly implementation is written in
runs under several different non-web embeddings (runtimes):
node,
[wasmtime](https://github.com/CraneStation/wasmtime),
[wax](https://github.com/kanaka/wac),
[wace](https://github.com/kanaka/wac),
[warpy](https://github.com/kanaka/warpy).
@ -1046,6 +1047,9 @@ make wasm_MODE=node
# wasmtime
make wasm_MODE=wasmtime
wasmtime --dir=./ --dir=../ --dir=/ ./stepX_YYY.wasm
# wax
make wasm_MODE=wax
wace ./stepX_YYY.wasm
# wace
make wasm_MODE=wace_libc
wace ./stepX_YYY.wasm

View File

@ -98,6 +98,13 @@ RUN apt-get -y install software-properties-common && \
apt-get -y autoremove pypy
#
# wasi-sdk (C/C++ -> wasm+wasi)
#
RUN curl -LO https://github.com/CraneStation/wasi-sdk/releases/download/wasi-sdk-3/wasi-sdk_3.0_amd64.deb && \
dpkg -i wasi-sdk_3.0_amd64.deb && \
rm wasi-sdk_3.0_amd64.deb
#
# warpy
#
@ -111,8 +118,8 @@ RUN git clone https://github.com/kanaka/warpy/ && \
#
RUN git clone https://github.com/kanaka/wac/ && \
cd wac && \
make USE_SDL= wac wace && \
cp wac wace /usr/bin
make USE_SDL= wac wax wace && \
cp wac wax wace /usr/bin
#
# wasmtime
@ -128,6 +135,7 @@ RUN git clone --recursive https://github.com/CraneStation/wasmtime && \
FROM base as wasm
COPY --from=build_runtimes /usr/bin/wac /usr/bin/wac
COPY --from=build_runtimes /usr/bin/wax /usr/bin/wax
COPY --from=build_runtimes /usr/bin/wace /usr/bin/wace
COPY --from=build_runtimes /usr/bin/warpy /usr/bin/warpy
COPY --from=build_runtimes /usr/bin/wasmtime /usr/bin/wasmtime

View File

@ -1,5 +1,5 @@
MODE ?= $(strip \
$(if $(filter wasi wasmtime,$(wasm_MODE)),\
$(if $(filter wasi wax wasmtime,$(wasm_MODE)),\
wasi,\
$(if $(filter direct node js wace_fooboot warpy,$(wasm_MODE)),\
direct,\

View File

@ -1,4 +1,4 @@
(module $platform_os
(module $platform_direct
(import "env" "memory" (memory 256))
(import "env" "memoryBase" (global $memoryBase i32))
@ -26,8 +26,7 @@
(func $readline (param $prompt i32 $buf i32) (result i32)
;; TODO: don't hardcode count to 200
(LET $res ($lib_readline $prompt $buf 200))
$res
($lib_readline $prompt $buf 200)
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

View File

@ -4,15 +4,20 @@
(export "memory" (memory 0))
(global $memoryBase i32 0)
(global $RIGHT_FD_READ i64 (i64.const 2))
(global $WASI_RIGHT_FD_READ i64 (i64.const 2))
(global $WASI_ESUCCESS i32 0)
(global $WASI_EBADF i32 8)
(global $WASI_PREOPENTYPE_DIR i32 0)
(import "wasi_unstable" "proc_exit" (func $proc_exit (param i32)))
(import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
(import "wasi_unstable" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32)))
(import "wasi_unstable" "path_open" (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
(import "wasi_unstable" "args_sizes_get" (func $args_sizes_get (param i32 i32) (result i32)))
(import "wasi_unstable" "args_get" (func $args_get (param i32 i32) (result i32)))
(import "wasi_unstable" "args_sizes_get" (func $args_sizes_get (param i32 i32) (result i32)))
(import "wasi_unstable" "clock_time_get" (func $clock_time_get (param i32 i64 i32) (result i32)))
(import "wasi_unstable" "fd_prestat_get" (func $fd_prestat_get (param i32 i32) (result i32)))
(import "wasi_unstable" "fd_prestat_dir_name" (func $fd_prestat_dir_name (param i32 i32 i32) (result i32)))
(import "wasi_unstable" "fd_read" (func $fd_read (param i32 i32 i32 i32) (result i32)))
(import "wasi_unstable" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
(import "wasi_unstable" "path_open" (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32)))
(import "wasi_unstable" "proc_exit" (func $proc_exit (param i32)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -26,7 +31,7 @@
(func $print (param $addr i32)
(LET $ret 0
$nwritten_ptr (STATIC_ARRAY 4 4)
$iovec (STATIC_ARRAY 8 4))
$iovec (STATIC_ARRAY 8 8))
(i32.store $iovec $addr)
(i32.store offset=4 $iovec ($strlen $addr))
(local.set $ret ($fd_write 1 $iovec 1 $nwritten_ptr))
@ -37,7 +42,7 @@
(func $readline (param $prompt i32 $buf i32) (result i32)
(LET $ret 0
$nread_ptr (STATIC_ARRAY 4 4)
$iovec (STATIC_ARRAY 8 4))
$iovec (STATIC_ARRAY 8 8))
($print $prompt)
(i32.store $iovec $buf)
(i32.store offset=4 $iovec 200) ;; TODO: not hardcoded length
@ -51,43 +56,64 @@
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; We currently assume that files are mapped:
;; 3: ./
;; 4: ../
;; 5: /
;; In ./run, wasmtime is called like this:
;; wasmtime --dir=./ --dir=../ --dir=/ ...
;; TODO: we should use the prestat method to find the right
;; directory fd that matches our prefix as implemented at:
;; https://github.com/CraneStation/wasi-sysroot/blob/1cc98f27f5ab8afdc033e16eac8799ee606eb769/libc-bottom-half/crt/crt1.c#L71
(func $read_file (param $path i32 $buf i32) (result i32)
(LET $orig_path $path
$ret 0
$prestat_ptr (STATIC_ARRAY 8 4)
$pr_type 0
$pr_name_len 0
$prepath (STATIC_ARRAY 1024)
$dirfd 3
$fd_ptr (STATIC_ARRAY 4 4)
$nread_ptr (STATIC_ARRAY 4 4)
$iovec (STATIC_ARRAY 8 4))
(if (i32.eqz ($strncmp "/" $path 1))
$iovec (STATIC_ARRAY 8 8))
;; Find the pre-opened dirfd with the same prefix as the our path
;; following the algorithm at:
;; https://github.com/CraneStation/wasi-sysroot/blob/1cc98f27f5ab8afdc033e16eac8799ee606eb769/libc-bottom-half/crt/crt1.c#L71
;; The matching dirfd is then used to open and read the path.
(block $loop_done
(loop $loop
;; prestat the dirfd from 3 onward until EBADF is returned
(local.set $ret ($fd_prestat_get $dirfd $prestat_ptr))
(if (i32.eq (global.get $WASI_EBADF) $ret)
(br $loop_done))
(if (i32.ne (global.get $WASI_ESUCCESS) $ret)
(br $loop))
(local.set $pr_type (i32.load $prestat_ptr))
(local.set $pr_name_len (i32.load offset=4 $prestat_ptr))
;; Read the pre-opened path name
(local.set $ret ($fd_prestat_dir_name $dirfd $prepath $pr_name_len))
;;($printf_4 "dirfd: %d, pr_type: %d, pr_name_len: %d, prepath: %s\n"
;; $dirfd $pr_type $pr_name_len $prepath)
(if (i32.ne (global.get $WASI_ESUCCESS) $ret)
(br $loop_done))
(if (AND (i32.eq $pr_type (global.get $WASI_PREOPENTYPE_DIR))
(i32.eqz ($strncmp $prepath $path $pr_name_len)))
(then
;; $ret was success and the path prefix matches, so break
(local.set $path (i32.add $pr_name_len $path))
(br $loop_done)))
(local.set $dirfd (i32.add 1 $dirfd))
(br $loop)
)
)
(if (i32.ne (global.get $WASI_ESUCCESS) $ret)
(then
(local.set $dirfd 5)
(local.set $path (i32.add $path 1)))
(else (if (i32.eqz ($strncmp "../" $path 3))
(then
(local.set $dirfd 4)
(local.set $path (i32.add $path 3)))
(else
(local.set $dirfd 3)))))
($printf_1 "ERROR: slurp could not find permission for '%s'\n" $orig_path)
(return 0)))
(local.set $ret ($path_open $dirfd
1 ;; dirflags (symlink follow)
$path
($strlen $path)
0 ;; o_flags
(global.get $RIGHT_FD_READ)
(global.get $RIGHT_FD_READ)
(global.get $WASI_RIGHT_FD_READ)
(global.get $WASI_RIGHT_FD_READ)
0 ;; fs_flags
$fd_ptr))
(if (i32.ne 0 $ret)
(if (i32.ne (global.get $WASI_ESUCCESS) $ret)
(then
($printf_1 "ERROR: slurp failed to open '%s'\n" $orig_path)
(return 0)))
@ -96,7 +122,7 @@
;; TODO: use stat result instead of not hardcoded length
(i32.store offset=4 $iovec 16384)
(local.set $ret ($fd_read (i32.load $fd_ptr) $iovec 1 $nread_ptr))
(if (i32.ne 0 $ret)
(if (i32.ne (global.get $WASI_ESUCCESS) $ret)
(then
($printf_1 "ERROR: slurp failed to read '%s'\n" $orig_path)
(return 0)))
@ -144,8 +170,8 @@
($main (i32.wrap_i64 (i64.shr_u $argc_argv (i64.const 32)))
(i32.wrap_i64 $argc_argv)))
)
(start $entry)
;;(start $entry)
(export "_main" (func $entry))
(export "_start" (func $entry))
)

View File

@ -7,6 +7,8 @@ node|js)
exec ./run.js $(dirname $0)/${STEP:-stepA_mal}.wasm "${@}" ;;
warpy)
exec warpy --argv --memory-pages 256 $(dirname $0)/${STEP:-stepA_mal}.wasm "${@}" ;;
wax)
exec wax $(dirname $0)/${STEP:-stepA_mal}.wasm "${@}" ;;
wace_fooboot)
echo >&2 "wace_fooboot mode not yet supported" ;;
wace_libc|*)

View File

@ -115,7 +115,6 @@ async function loadWebAssembly(filename, args) {
imports.env.read_file = read_file
imports.env.get_time_ms = get_time_ms
imports.env.stdout = 0
imports.env.fputs = printline