diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d45bd9..bd5fe80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,6 +22,13 @@ jobs: with: version: 0.11.0 + # The current default version of clang on macos runners is 14, which doesn't support the wasm64-freestanding target. + - name: Install LLVM and Clang + if: matrix.os == 'macos-latest' + uses: KyleMayes/install-llvm-action@v2 + with: + version: "15.0" + - name: Setup Python uses: actions/setup-python@v4 with: @@ -32,9 +39,10 @@ jobs: working-directory: test/wasi/wasi-testsuite/test-runner run: python3 -m pip install -r requirements.txt - - uses: mwilliamson/setup-wabt-action@v2 + - name: Setup wasm-tools + uses: jcbhmr/setup-wasm-tools@v2 with: - wabt-version: "1.0.31" + wasm-tools-version: "1.207.0" - name: Build run: | diff --git a/README.md b/README.md index 0306a2f..59f707c 100644 --- a/README.md +++ b/README.md @@ -3,25 +3,32 @@
Markdown Logo -Bytebox is a Webassembly VM. +Bytebox is a WebAssembly VM.
-## Getting started +# Getting started -### Requirements +## Requirements Bytebox currently builds with [Zig 0.11.x](https://ziglang.org/download) to avoid churn on zig master. -### Run +To run the tests: +* `wasm-tools` is required to run the wasm testsuite. You can install it via the rust toolchain `cargo install wasm-tools` or directly from the [release page](https://github.com/bytecodealliance/wasm-tools/releases). +* `clang` v15.x is required to build the mem64 tests. However, if you don't have a compatible version of `clang` installed, you can pass `--noclang` to `zig build` to avoid the requirement. +* `python3` is required to run the wasi testsuite. You may need to run `python3 -m pip install -r test/wasi/wasi-testsuite/test-runner/requirements.txt` to ensure the wasi test runner has all the necessary dependencies installed. + +## Run Tests ```sh git clone --recurse-submodules https://github.com/rdunnington/bytebox.git cd bytebox -zig build test # run the WebAssembly spec testsuite -# run the wasi testsuite -python3 test/wasi/wasi-testsuite/test-runner/wasi_test_runner.py -r test/wasi/bytebox_adapter.py -t ./test/wasi/wasi-testsuite/tests/assemblyscript/testsuite/ ./test/wasi/wasi-testsuite/tests/c/testsuite/ ./test/wasi/wasi-testsuite/tests/rust/testsuite/ +zig build test-unit # run builtin zig unit tests +zig build test-wasm # run official wasm spec testsuite +zig build test-wasi # run official wasi spec testsuite +zig build test-mem64 # run memory64 compat test +zig build test # run all of the above in parallel (output will not be pretty!) ``` -### Usage +## Usage You can use the standalone runtime to load and execute WebAssembly programs: ```sh @@ -71,7 +78,7 @@ pub fn main() !void { Inter-language FFI is also supported. See `src/bytebox.h` for an overview in C. To use bytebox as a static library, link with the built library in `zig-out/lib/`. Note that Zig assumes a default stack size of 8MB, so you'll need to ensure the same in your program. -## Status +# Status This project is still in the alpha stage. @@ -81,7 +88,7 @@ This project is still in the alpha stage. |❌|TODO| |💀|Not planned/Removed from spec| -### [WebAssembly](https://webassembly.github.io/spec/core/index.html) support: +## [WebAssembly](https://webassembly.github.io/spec/core/index.html) support: | Status | Feature | | --- | --- | @@ -95,7 +102,7 @@ This project is still in the alpha stage. |✅|Bulk memory and table instructions| |✅|Vector instructions| -### [WASI Preview 1](https://github.com/WebAssembly/WASI/tree/main) support: +## [WASI Preview 1](https://github.com/WebAssembly/WASI/tree/main) support: | Status | Feature | | --- | --- | diff --git a/test/wasm/main.zig b/test/wasm/main.zig index 61842cd..16aa243 100644 --- a/test/wasm/main.zig +++ b/test/wasm/main.zig @@ -363,12 +363,13 @@ fn isSameError(err: anyerror, err_string: []const u8) bool { bytebox.MalformedError.MalformedMagicSignature => strcmp(err_string, "magic header not detected"), bytebox.MalformedError.MalformedUnexpectedEnd => strcmp(err_string, "unexpected end") or strcmp(err_string, "unexpected end of section or function") or - strcmp(err_string, "length out of bounds"), + strcmp(err_string, "length out of bounds") or + strcmp(err_string, "malformed section id"), bytebox.MalformedError.MalformedUnsupportedWasmVersion => strcmp(err_string, "unknown binary version"), bytebox.MalformedError.MalformedSectionId => strcmp(err_string, "malformed section id"), bytebox.MalformedError.MalformedTypeSentinel => strcmp(err_string, "integer representation too long") or strcmp(err_string, "integer too large"), bytebox.MalformedError.MalformedLEB128 => strcmp(err_string, "integer representation too long") or strcmp(err_string, "integer too large"), - bytebox.MalformedError.MalformedMissingZeroByte => strcmp(err_string, "zero byte expected"), + bytebox.MalformedError.MalformedMissingZeroByte => strcmp(err_string, "zero flag expected"), bytebox.MalformedError.MalformedTooManyLocals => strcmp(err_string, "too many locals"), bytebox.MalformedError.MalformedFunctionCodeSectionMismatch => strcmp(err_string, "function and code section have inconsistent lengths"), bytebox.MalformedError.MalformedMissingDataCountSection => strcmp(err_string, "data count section required") or strcmp(err_string, "unknown data segment"), @@ -378,15 +379,15 @@ fn isSameError(err: anyerror, err_string: []const u8) bool { bytebox.MalformedError.MalformedReferenceType => strcmp(err_string, "malformed reference type"), bytebox.MalformedError.MalformedSectionSizeMismatch => strcmp(err_string, "section size mismatch") or strcmp(err_string, "malformed section id") or - strcmp(err_string, "function and code section have inconsistent lengths"), // this one is a bit of a hack to resolve custom.8.wasm + strcmp(err_string, "function and code section have inconsistent lengths") or // this one is a bit of a hack to resolve custom.8.wasm + strcmp(err_string, "zero flag expected"), // the memory64 binary tests don't seem to be up to date with the reference types spec bytebox.MalformedError.MalformedInvalidImport => strcmp(err_string, "malformed import kind"), bytebox.MalformedError.MalformedLimits => strcmp(err_string, "integer too large") or strcmp(err_string, "integer representation too long") or strcmp(err_string, "malformed limits flags"), bytebox.MalformedError.MalformedMultipleStartSections => strcmp(err_string, "multiple start sections") or - strcmp(err_string, "unexpected content after last section"), + strcmp(err_string, "junk after last section"), bytebox.MalformedError.MalformedElementType => strcmp(err_string, "integer representation too long") or strcmp(err_string, "integer too large"), bytebox.MalformedError.MalformedUTF8Encoding => strcmp(err_string, "malformed UTF-8 encoding"), bytebox.MalformedError.MalformedMutability => strcmp(err_string, "malformed mutability"), - // ValidationTypeMismatch: result arity handles select.2.wasm which is the exact same binary as select.1.wasm but the test expects a different error :/ bytebox.ValidationError.ValidationTypeMismatch => strcmp(err_string, "type mismatch") or strcmp(err_string, "invalid result arity"), bytebox.ValidationError.ValidationTypeMustBeNumeric => strcmp(err_string, "type mismatch"), @@ -394,7 +395,8 @@ fn isSameError(err: anyerror, err_string: []const u8) bool { bytebox.ValidationError.ValidationUnknownFunction => std.mem.startsWith(u8, err_string, "unknown function"), bytebox.ValidationError.ValidationUnknownGlobal => std.mem.startsWith(u8, err_string, "unknown global"), bytebox.ValidationError.ValidationUnknownLocal => std.mem.startsWith(u8, err_string, "unknown local"), - bytebox.ValidationError.ValidationUnknownTable => std.mem.startsWith(u8, err_string, "unknown table"), + bytebox.ValidationError.ValidationUnknownTable => std.mem.startsWith(u8, err_string, "unknown table") or + strcmp(err_string, "zero flag expected"), // the memory64 binary tests don't seem to be up to date with the reference types spec bytebox.ValidationError.ValidationUnknownMemory => std.mem.startsWith(u8, err_string, "unknown memory"), bytebox.ValidationError.ValidationUnknownElement => strcmp(err_string, "unknown element") or std.mem.startsWith(u8, err_string, "unknown elem segment"), bytebox.ValidationError.ValidationUnknownData => strcmp(err_string, "unknown data") or std.mem.startsWith(u8, err_string, "unknown data segment"), @@ -1575,6 +1577,9 @@ pub fn main() !void { var suite_wast_path_relative = try std.fs.path.join(allocator, &[_][]const u8{ "../../../../", suite_wast_path }); defer allocator.free(suite_wast_path_relative); + const suite_json_filename: []const u8 = try std.mem.join(allocator, "", &[_][]const u8{ suite, ".json" }); + defer allocator.free(suite_json_filename); + var suite_wasm_folder: []const u8 = try std.fs.path.join(allocator, &[_][]const u8{ "test", "wasm", "wasm-generated", suite }); defer allocator.free(suite_wasm_folder); @@ -1590,7 +1595,7 @@ pub fn main() !void { } }; - var process = std.ChildProcess.init(&[_][]const u8{ "wast2json", "--enable-memory64", suite_wast_path_relative }, allocator); + var process = std.ChildProcess.init(&[_][]const u8{ "wasm-tools", "json-from-wast", "--pretty", "-o", suite_json_filename, suite_wast_path_relative }, allocator); process.cwd = suite_wasm_folder; diff --git a/test/wasm/wasm-testsuite b/test/wasm/wasm-testsuite index 3a04b2c..dc27dad 160000 --- a/test/wasm/wasm-testsuite +++ b/test/wasm/wasm-testsuite @@ -1 +1 @@ -Subproject commit 3a04b2cf93bd8fce277458d419eea8d9c326345c +Subproject commit dc27dad3e34e466bdbfea32fe3c73f5e31f88560