wasm: wax runtime. Use WASI preopen process.
authorJoel Martin <github@martintribe.org>
Fri, 19 Apr 2019 06:07:08 +0000 (01:07 -0500)
committerJoel Martin <github@martintribe.org>
Fri, 19 Apr 2019 06:07:08 +0000 (01:07 -0500)
Add wasi-sdk to Dockerfile to be able to compile C code to wasm that
uses WASI API calls.

.travis.yml
README.md
wasm/Dockerfile
wasm/Makefile
wasm/platform_direct.wam
wasm/platform_wasi.wam
wasm/run
wasm/run.js

index e85dcc4..d611a97 100644 (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]}
index 5deadc8..5fbe9fd 100644 (file)
--- a/README.md
+++ b/README.md
@@ -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
index 8e503f4..c966a40 100644 (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
index aeba518..892ba18 100644 (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,\
index a8e92b5..7d9c94c 100644 (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)
   )
 
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
index db4a2e4..5ce83b8 100644 (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
 
   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
-  ;; 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))
-      (then
-        (local.set $dirfd 5)
-        (local.set $path (i32.add $path 1)))
-    (else (if (i32.eqz ($strncmp "../" $path 3))
+         $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 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)))
     ;; 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)))
       ($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))
 
 )
index 8607932..73a5016 100755 (executable)
--- a/wasm/run
+++ b/wasm/run
@@ -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|*)
index d9877e1..2deaa5e 100755 (executable)
@@ -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