├── .gitattributes ├── .github └── workflows │ ├── ci-interpreter.yml │ ├── ci-spec.yml │ └── w3c-publish.yml ├── .gitignore ├── .gitmodules ├── Contributing.md ├── LICENSE ├── README.md ├── deploy_key ├── deploy_key.pub ├── document ├── LICENSE ├── Makefile ├── README.md ├── core │ ├── .gitignore │ ├── LICENSE │ ├── Makefile │ ├── README.md │ ├── appendix │ │ ├── algorithm.rst │ │ ├── changes.rst │ │ ├── custom.rst │ │ ├── embedding.rst │ │ ├── implementation.rst │ │ ├── index-instructions.py │ │ ├── index-rules.rst │ │ ├── index-types.rst │ │ ├── index.rst │ │ └── properties.rst │ ├── binary │ │ ├── conventions.rst │ │ ├── index.rst │ │ ├── instructions.rst │ │ ├── modules.rst │ │ ├── types.rst │ │ └── values.rst │ ├── conf.py │ ├── exec │ │ ├── conventions.rst │ │ ├── index.rst │ │ ├── instructions.rst │ │ ├── modules.rst │ │ ├── numerics.rst │ │ └── runtime.rst │ ├── index.bs │ ├── index.rst │ ├── intro │ │ ├── index.rst │ │ ├── introduction.rst │ │ └── overview.rst │ ├── make.bat │ ├── static │ │ ├── custom.css │ │ └── webassembly.png │ ├── syntax │ │ ├── conventions.rst │ │ ├── index.rst │ │ ├── instructions.rst │ │ ├── modules.rst │ │ ├── types.rst │ │ └── values.rst │ ├── text │ │ ├── conventions.rst │ │ ├── index.rst │ │ ├── instructions.rst │ │ ├── lexical.rst │ │ ├── modules.rst │ │ ├── types.rst │ │ └── values.rst │ ├── util │ │ ├── README.htmldiff.pl │ │ ├── bikeshed │ │ │ └── conf.py │ │ ├── bikeshed_fixup.py │ │ ├── check_macros.sh │ │ ├── katex_fix.patch │ │ ├── macros.def │ │ ├── mathdef.py │ │ ├── mathdefbs.py │ │ ├── mathjax2katex.py │ │ └── pseudo-lexer.py │ └── valid │ │ ├── conventions.rst │ │ ├── index.rst │ │ ├── instructions.rst │ │ ├── modules.rst │ │ └── types.rst ├── deploy.sh ├── index.html ├── js-api │ ├── Makefile │ └── index.bs ├── util │ └── htmldiff.pl └── web-api │ ├── Makefile │ └── index.bs ├── interpreter ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── binary │ ├── decode.ml │ ├── decode.mli │ ├── encode.ml │ ├── encode.mli │ ├── utf8.ml │ └── utf8.mli ├── dune ├── dune-project ├── exec │ ├── eval.ml │ ├── eval.mli │ ├── eval_num.ml │ ├── eval_num.mli │ ├── eval_vec.ml │ ├── eval_vec.mli │ ├── f32.ml │ ├── f32_convert.ml │ ├── f32_convert.mli │ ├── f64.ml │ ├── f64_convert.ml │ ├── f64_convert.mli │ ├── fxx.ml │ ├── i16.ml │ ├── i32.ml │ ├── i32_convert.ml │ ├── i32_convert.mli │ ├── i64.ml │ ├── i64_convert.ml │ ├── i64_convert.mli │ ├── i8.ml │ ├── ixx.ml │ ├── v128.ml │ └── v128.mli ├── host │ ├── env.ml │ └── spectest.ml ├── jslib │ └── wast.ml ├── main │ ├── flags.ml │ └── main.ml ├── runtime │ ├── data.ml │ ├── data.mli │ ├── elem.ml │ ├── elem.mli │ ├── func.ml │ ├── func.mli │ ├── global.ml │ ├── global.mli │ ├── instance.ml │ ├── memory.ml │ ├── memory.mli │ ├── table.ml │ └── table.mli ├── script │ ├── import.ml │ ├── import.mli │ ├── js.ml │ ├── js.mli │ ├── run.ml │ ├── run.mli │ └── script.ml ├── syntax │ ├── ast.ml │ ├── free.ml │ ├── free.mli │ ├── operators.ml │ ├── types.ml │ └── values.ml ├── text │ ├── arrange.ml │ ├── arrange.mli │ ├── lexer.mli │ ├── lexer.mll │ ├── parse.ml │ ├── parse.mli │ ├── parse_error.ml │ ├── parser.mly │ ├── print.ml │ └── print.mli ├── unittest │ └── smallint.ml ├── util │ ├── error.ml │ ├── error.mli │ ├── lib.ml │ ├── lib.mli │ ├── sexpr.ml │ ├── sexpr.mli │ ├── source.ml │ └── source.mli ├── valid │ ├── valid.ml │ └── valid.mli └── wasm.opam ├── papers ├── LICENSE ├── README.md ├── oopsla2019.pdf └── pldi2017.pdf ├── proposals ├── README.md ├── bulk-memory-operations │ └── Overview.md ├── multi-memory │ └── Overview.md ├── multi-value │ └── Overview.md ├── nontrapping-float-to-int-conversion │ └── Overview.md ├── reference-types │ └── Overview.md ├── sign-extension-ops │ └── Overview.md └── simd │ ├── BinarySIMD.md │ ├── ImplementationStatus.md │ ├── NewOpcodes.md │ ├── SIMD.md │ ├── TextSIMD.md │ ├── W3CTAG-SIMDExplainer.md │ └── WebAssembly-SIMD-May-2017.pdf ├── test ├── LICENSE ├── README.md ├── Todo.md ├── build.py ├── core │ ├── .gitignore │ ├── README.md │ ├── address.wast │ ├── align.wast │ ├── binary-leb128.wast │ ├── binary.wast │ ├── block.wast │ ├── br.wast │ ├── br_if.wast │ ├── br_table.wast │ ├── bulk.wast │ ├── call.wast │ ├── call_indirect.wast │ ├── comments.wast │ ├── const.wast │ ├── conversions.wast │ ├── custom.wast │ ├── data.wast │ ├── elem.wast │ ├── endianness.wast │ ├── exports.wast │ ├── f32.wast │ ├── f32_bitwise.wast │ ├── f32_cmp.wast │ ├── f64.wast │ ├── f64_bitwise.wast │ ├── f64_cmp.wast │ ├── fac.wast │ ├── float_exprs.wast │ ├── float_literals.wast │ ├── float_memory.wast │ ├── float_misc.wast │ ├── forward.wast │ ├── func.wast │ ├── func_ptrs.wast │ ├── global.wast │ ├── i32.wast │ ├── i64.wast │ ├── if.wast │ ├── imports.wast │ ├── inline-module.wast │ ├── int_exprs.wast │ ├── int_literals.wast │ ├── labels.wast │ ├── left-to-right.wast │ ├── linking.wast │ ├── load.wast │ ├── local_get.wast │ ├── local_set.wast │ ├── local_tee.wast │ ├── loop.wast │ ├── memory-multi.wast │ ├── memory.wast │ ├── memory_copy.wast │ ├── memory_fill.wast │ ├── memory_grow.wast │ ├── memory_init.wast │ ├── memory_redundancy.wast │ ├── memory_size.wast │ ├── memory_trap.wast │ ├── multi-memory │ │ ├── address0.wast │ │ ├── address1.wast │ │ ├── align0.wast │ │ ├── binary0.wast │ │ ├── data0.wast │ │ ├── data1.wast │ │ ├── data_drop0.wast │ │ ├── exports0.wast │ │ ├── float_exprs0.wast │ │ ├── float_exprs1.wast │ │ ├── float_memory0.wast │ │ ├── imports0.wast │ │ ├── imports1.wast │ │ ├── imports2.wast │ │ ├── imports3.wast │ │ ├── imports4.wast │ │ ├── linking0.wast │ │ ├── linking1.wast │ │ ├── linking2.wast │ │ ├── linking3.wast │ │ ├── load0.wast │ │ ├── load1.wast │ │ ├── load2.wast │ │ ├── memory_copy0.wast │ │ ├── memory_copy1.wast │ │ ├── memory_fill0.wast │ │ ├── memory_init0.wast │ │ ├── memory_size0.wast │ │ ├── memory_size1.wast │ │ ├── memory_size2.wast │ │ ├── memory_size3.wast │ │ ├── memory_trap0.wast │ │ ├── memory_trap1.wast │ │ ├── start0.wast │ │ ├── store0.wast │ │ ├── store1.wast │ │ └── traps0.wast │ ├── names.wast │ ├── nop.wast │ ├── obsolete-keywords.wast │ ├── ref_func.wast │ ├── ref_is_null.wast │ ├── ref_null.wast │ ├── return.wast │ ├── run.py │ ├── select.wast │ ├── simd │ │ ├── meta │ │ │ ├── README.md │ │ │ ├── gen_tests.py │ │ │ ├── simd.py │ │ │ ├── simd_arithmetic.py │ │ │ ├── simd_bitwise.py │ │ │ ├── simd_compare.py │ │ │ ├── simd_ext_mul.py │ │ │ ├── simd_extadd_pairwise.py │ │ │ ├── simd_f32x4.py │ │ │ ├── simd_f32x4_arith.py │ │ │ ├── simd_f32x4_cmp.py │ │ │ ├── simd_f32x4_pmin_pmax.py │ │ │ ├── simd_f32x4_rounding.py │ │ │ ├── simd_f64x2.py │ │ │ ├── simd_f64x2_arith.py │ │ │ ├── simd_f64x2_cmp.py │ │ │ ├── simd_f64x2_pmin_pmax.py │ │ │ ├── simd_f64x2_rounding.py │ │ │ ├── simd_float_op.py │ │ │ ├── simd_i16x8_arith.py │ │ │ ├── simd_i16x8_cmp.py │ │ │ ├── simd_i16x8_q15mulr_sat_s.py │ │ │ ├── simd_i32x4_arith.py │ │ │ ├── simd_i32x4_cmp.py │ │ │ ├── simd_i32x4_dot_i16x8.py │ │ │ ├── simd_i64x2_arith.py │ │ │ ├── simd_i64x2_cmp.py │ │ │ ├── simd_i8x16_arith.py │ │ │ ├── simd_i8x16_cmp.py │ │ │ ├── simd_int_arith2.py │ │ │ ├── simd_int_to_int_extend.py │ │ │ ├── simd_int_trunc_sat_float.py │ │ │ ├── simd_integer_op.py │ │ │ ├── simd_lane_value.py │ │ │ ├── simd_load_lane.py │ │ │ ├── simd_sat_arith.py │ │ │ ├── simd_store_lane.py │ │ │ └── test_assert.py │ │ ├── simd_address.wast │ │ ├── simd_align.wast │ │ ├── simd_bit_shift.wast │ │ ├── simd_bitwise.wast │ │ ├── simd_boolean.wast │ │ ├── simd_const.wast │ │ ├── simd_conversions.wast │ │ ├── simd_f32x4.wast │ │ ├── simd_f32x4_arith.wast │ │ ├── simd_f32x4_cmp.wast │ │ ├── simd_f32x4_pmin_pmax.wast │ │ ├── simd_f32x4_rounding.wast │ │ ├── simd_f64x2.wast │ │ ├── simd_f64x2_arith.wast │ │ ├── simd_f64x2_cmp.wast │ │ ├── simd_f64x2_pmin_pmax.wast │ │ ├── simd_f64x2_rounding.wast │ │ ├── simd_i16x8_arith.wast │ │ ├── simd_i16x8_arith2.wast │ │ ├── simd_i16x8_cmp.wast │ │ ├── simd_i16x8_extadd_pairwise_i8x16.wast │ │ ├── simd_i16x8_extmul_i8x16.wast │ │ ├── simd_i16x8_q15mulr_sat_s.wast │ │ ├── simd_i16x8_sat_arith.wast │ │ ├── simd_i32x4_arith.wast │ │ ├── simd_i32x4_arith2.wast │ │ ├── simd_i32x4_cmp.wast │ │ ├── simd_i32x4_dot_i16x8.wast │ │ ├── simd_i32x4_extadd_pairwise_i16x8.wast │ │ ├── simd_i32x4_extmul_i16x8.wast │ │ ├── simd_i32x4_trunc_sat_f32x4.wast │ │ ├── simd_i32x4_trunc_sat_f64x2.wast │ │ ├── simd_i64x2_arith.wast │ │ ├── simd_i64x2_arith2.wast │ │ ├── simd_i64x2_cmp.wast │ │ ├── simd_i64x2_extmul_i32x4.wast │ │ ├── simd_i8x16_arith.wast │ │ ├── simd_i8x16_arith2.wast │ │ ├── simd_i8x16_cmp.wast │ │ ├── simd_i8x16_sat_arith.wast │ │ ├── simd_int_to_int_extend.wast │ │ ├── simd_lane.wast │ │ ├── simd_linking.wast │ │ ├── simd_load.wast │ │ ├── simd_load16_lane.wast │ │ ├── simd_load32_lane.wast │ │ ├── simd_load64_lane.wast │ │ ├── simd_load8_lane.wast │ │ ├── simd_load_extend.wast │ │ ├── simd_load_splat.wast │ │ ├── simd_load_zero.wast │ │ ├── simd_memory-multi.wast │ │ ├── simd_splat.wast │ │ ├── simd_store.wast │ │ ├── simd_store16_lane.wast │ │ ├── simd_store32_lane.wast │ │ ├── simd_store64_lane.wast │ │ └── simd_store8_lane.wast │ ├── skip-stack-guard-page.wast │ ├── stack.wast │ ├── start.wast │ ├── store.wast │ ├── switch.wast │ ├── table-sub.wast │ ├── table.wast │ ├── table_copy.wast │ ├── table_fill.wast │ ├── table_get.wast │ ├── table_grow.wast │ ├── table_init.wast │ ├── table_set.wast │ ├── table_size.wast │ ├── token.wast │ ├── traps.wast │ ├── type.wast │ ├── unreachable.wast │ ├── unreached-invalid.wast │ ├── unreached-valid.wast │ ├── unwind.wast │ ├── utf8-custom-section-id.wast │ ├── utf8-import-field.wast │ ├── utf8-import-module.wast │ └── utf8-invalid-encoding.wast ├── harness │ ├── async_index.js │ ├── sync_index.js │ ├── testharness.css │ ├── testharness.js │ └── testharnessreport.js ├── js-api │ ├── LICENSE.md │ ├── README.md │ ├── assertions.js │ ├── bad-imports.js │ ├── constructor │ ├── error-interfaces-no-symbol-tostringtag.js │ ├── functions │ │ └── helper.js │ ├── global │ │ ├── constructor.any.js │ │ ├── toString.any.js │ │ ├── value-get-set.any.js │ │ └── valueOf.any.js │ ├── instance │ │ ├── constructor-bad-imports.any.js │ │ ├── constructor-caching.any.js │ │ ├── constructor.any.js │ │ ├── exports.any.js │ │ └── toString.any.js │ ├── instanceTestFactory.js │ ├── interface.any.js │ ├── limits.any.js │ ├── memory │ │ ├── assertions.js │ │ ├── buffer.any.js │ │ ├── constructor.any.js │ │ ├── grow.any.js │ │ └── toString.any.js │ ├── module │ │ ├── constructor.any.js │ │ ├── customSections.any.js │ │ ├── exports.any.js │ │ ├── imports.any.js │ │ └── toString.any.js │ ├── prototypes.any.js │ ├── table │ │ ├── assertions.js │ │ ├── constructor.any.js │ │ ├── get-set.any.js │ │ ├── grow.any.js │ │ ├── length.any.js │ │ └── toString.any.js │ └── wasm-module-builder.js ├── meta │ ├── Makefile │ ├── README.md │ ├── common.js │ ├── generate_memory_copy.js │ ├── generate_memory_fill.js │ ├── generate_memory_init.js │ ├── generate_table_copy.js │ ├── generate_table_init.js │ └── noderun.sh └── sync-js-api.py ├── w3c.json └── wasm-specs.bib /.gitattributes: -------------------------------------------------------------------------------- 1 | *.rst linguist-documentation=false 2 | document/* linguist-documentation=false 3 | document/*.rst linguist-documentation=false 4 | document/*/*.rst linguist-documentation=false 5 | test/harness/wast.js linguist-vendored 6 | test/harness/testharness* linguist-vendored 7 | 8 | -------------------------------------------------------------------------------- /.github/workflows/ci-interpreter.yml: -------------------------------------------------------------------------------- 1 | name: CI for interpreter & tests 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: [ .github/**, interpreter/**, test/** ] 7 | 8 | pull_request: 9 | branches: [ main ] 10 | paths: [ .github/**, interpreter/**, test/** ] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | jobs: 16 | interpreter: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout repo 20 | uses: actions/checkout@v2 21 | - name: Setup OCaml 22 | uses: ocaml/setup-ocaml@v2 23 | with: 24 | ocaml-compiler: 4.12.x 25 | - name: Setup OCaml tools 26 | run: opam install --yes ocamlfind.1.9.5 js_of_ocaml.4.0.0 js_of_ocaml-ppx.4.0.0 27 | - name: Setup Node.js 28 | uses: actions/setup-node@v2 29 | with: 30 | node-version: 20.x 31 | - name: Build interpreter 32 | run: cd interpreter && opam exec make 33 | - name: Run tests 34 | run: cd interpreter && opam exec make JS=node ci 35 | -------------------------------------------------------------------------------- /.github/workflows/w3c-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to W3C TR space 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: [ .github/**, document/** ] 7 | 8 | # Allows you to run this workflow manually from the Actions tab 9 | workflow_dispatch: 10 | inputs: 11 | w3c-status: 12 | required: true 13 | type: string 14 | 15 | jobs: 16 | publish-to-w3c-TR: 17 | if: github.repository == 'WebAssembly/spec' 18 | runs-on: ubuntu-latest 19 | steps: 20 | - name: Checkout repo 21 | uses: actions/checkout@v2 22 | with: 23 | submodules: "recursive" 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: 16 28 | - name: Setup Bikeshed 29 | run: pip install bikeshed && bikeshed update 30 | - name: Setup TexLive 31 | run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended 32 | - name: Setup Sphinx 33 | run: pip install six && pip install sphinx==5.1.0 34 | - name: Publish all specs to their https://www.w3.org/TR/ URLs 35 | run: cd document && make -e WD-echidna-CI 36 | env: 37 | W3C_STATUS: ${{ github.event_name == 'push' && 'WD' || inputs.w3c-status }} 38 | W3C_ECHIDNA_TOKEN_CORE: ${{ secrets.W3C_ECHIDNA_TOKEN_CORE }} 39 | W3C_ECHIDNA_TOKEN_JSAPI: ${{ secrets.W3C_ECHIDNA_TOKEN_JSAPI }} 40 | W3C_ECHIDNA_TOKEN_WEBAPI: ${{ secrets.W3C_ECHIDNA_TOKEN_WEBAPI }} 41 | YARN_ENABLE_IMMUTABLE_INSTALLS: false 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*~ 2 | **/*.tmproj 3 | **/*.pyc 4 | **/_build 5 | **/_output 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "document/core/util/katex"] 2 | path = document/core/util/katex 3 | url = https://github.com/KaTeX/KaTeX.git 4 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing to WebAssembly 2 | 3 | Interested in participating? Please follow 4 | [the same contributing guidelines as the design repository][]. 5 | 6 | [the same contributing guidelines as the design repository]: https://github.com/WebAssembly/design/blob/main/Contributing.md 7 | 8 | Also, please be sure to read [the README.md](README.md) for this repository. 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Please see the LICENSE file in each top-level directory for the terms applicable to that directory and its relative sub-directories. 2 | 3 | The relevant directories and licenses are: 4 | 5 | document/ - W3C Software and Document Notice and License 6 | interpreter/ - Apache License 2.0 7 | test/ - Apache License 2.0 8 | papers/ - Creative Commons Attribution 4.0 International License 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI for specs](https://github.com/WebAssembly/multi-memory/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/multi-memory/actions/workflows/ci-spec.yml) 2 | [![CI for interpreter & tests](https://github.com/WebAssembly/multi-memory/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/multi-memory/actions/workflows/ci-interpreter.yml) 3 | 4 | # Multi Memory Proposal for WebAssembly 5 | 6 | This repository is a clone of [github.com/WebAssembly/spec/](https://github.com/WebAssembly/spec/). 7 | It is meant for discussion, prototype specification and implementation of a proposal to add support for multiple memories to WebAssembly. 8 | 9 | * See the [overview](proposals/multi-memory/Overview.md) for a summary of the proposal. 10 | 11 | * See the [modified spec](https://webassembly.github.io/multi-memory/) for details. 12 | 13 | Original `README` from upstream repository follows… 14 | 15 | # spec 16 | 17 | This repository holds a prototypical reference implementation for WebAssembly, 18 | which is currently serving as the official specification. Eventually, we expect 19 | to produce a specification either written in human-readable prose or in a formal 20 | specification language. 21 | 22 | It also holds the WebAssembly testsuite, which tests numerous aspects of 23 | conformance to the spec. 24 | 25 | View the work-in-progress spec at [webassembly.github.io/spec](https://webassembly.github.io/spec/). 26 | 27 | At this time, the contents of this repository are under development and known 28 | to be "incomplet and inkorrect". 29 | 30 | Participation is welcome. Discussions about new features, significant semantic 31 | changes, or any specification change likely to generate substantial discussion 32 | should take place in 33 | [the WebAssembly design repository](https://github.com/WebAssembly/design) 34 | first, so that this spec repository can remain focused. And please follow the 35 | [guidelines for contributing](Contributing.md). 36 | 37 | # citing 38 | 39 | For citing WebAssembly in LaTeX, use [this bibtex file](wasm-specs.bib). 40 | -------------------------------------------------------------------------------- /deploy_key.pub: -------------------------------------------------------------------------------- 1 | ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQCf0VStDNZyAQ4ewMn5/svSDvEhit0FvcrV1CoVYWJ1lwvwpgwxHT8IRhFd9KfcRy+lidGgiNZ8ZCCo6kD3QUxoDCp2grvYHJburYLjKaNfnFHxcXIblglW+Nox5JNdmXKdBI4f2VdTlGih4TBFq2BCLO7AH8GpqGvL/wU58OFWU07bohsTIk93bep7IB37jYI5MTmhYcQndMpJZJ/BMCF+siUiD51aJLH8hRwtz7syzkSlCHd5tfj2hpbTRJZEOfKqgz3mYP5RzcO5MUnIp0eUui4RJ02sT0t4Gazk39sdKB51XJnl8v1IcLo/UeaAM8WymY7rPWzXn9rnLmF/3MdWiPWFrngtJo+UTn8vmGljo8Ift96lFeHDzhUhBXvgiwmjDVdRuSZ8qSNbc94GoIXlxMoXYsrrlKtrER80wtTROE4foHrLN4+rskX7TlUYyHYbZaTDLXWl7N6pbm09TUzarBJE3yMAUojC4LsHvd2vPzIyEXwx9NbiIYzhGqFBEIrbbGZW3PBgXBEpQz76naI6CAaLjaOdWyS/v/JDpdxoSb7YnHcLbPL/k50uqX3PyCYqwfiOlBQAOZp7woF8kKodmu2+FFOof30Te2GkgpynNj6fm6E0LKtj6FN8Hjj8Qie1aRcNMvBVVGaY7IdK8QDv8PPW+0DuBj027bnFj9JdKw== 2 | -------------------------------------------------------------------------------- /document/LICENSE: -------------------------------------------------------------------------------- 1 | This document is licensed under the W3C Software and Document License. 2 | Its text can be found at https://www.w3.org/copyright/software-license/ 3 | -------------------------------------------------------------------------------- /document/Makefile: -------------------------------------------------------------------------------- 1 | DIRS = js-api web-api core 2 | FILES = index.html 3 | BUILDDIR = _build 4 | TAR = tar 5 | 6 | # Global targets. 7 | 8 | .PHONY: all 9 | all: $(BUILDDIR) root $(DIRS) 10 | 11 | $(BUILDDIR): 12 | mkdir -p $@ 13 | 14 | .PHONY: deploy 15 | deploy: 16 | GIT_DEPLOY_DIR=$(BUILDDIR) bash deploy.sh 17 | 18 | .PHONY: publish 19 | publish: all deploy 20 | 21 | .PHONY: clean 22 | clean: $(DIRS:%=clean-%) 23 | rm -rf $(BUILDDIR) 24 | 25 | .PHONY: diff 26 | diff: $(DIRS:%=diff-%) 27 | 28 | # macOS: do “brew install tar” & run “make” as: TAR=gtar make -e WD-tar 29 | .PHONY: WD-tar 30 | WD-tar: 31 | for dir in $(DIRS); do \ 32 | TAR=$(TAR) $(MAKE) -e -C $$dir $@ || exit 1; \ 33 | done 34 | 35 | # macOS: do “brew install tar” & run “make” as: TAR=gtar make -e WD-echidna 36 | .PHONY: WD-echidna 37 | WD-echidna: 38 | for dir in $(DIRS); do \ 39 | $(MAKE) -e -C $$dir $@ || exit 1; \ 40 | done 41 | 42 | .PHONY: WD-echidna-CI 43 | WD-echidna-CI: 44 | for dir in $(DIRS); do \ 45 | $(MAKE) -e -C $$dir $@ || exit 1; \ 46 | done 47 | 48 | # Directory-specific targets. 49 | 50 | .PHONY: root 51 | root: $(BUILDDIR) 52 | touch $(BUILDDIR)/.nojekyll 53 | cp -f $(FILES) $(BUILDDIR)/ 54 | 55 | .PHONY: $(DIRS) 56 | $(DIRS): %: $(BUILDDIR) $(DIRS:%=build-%) $(DIRS:%=dir-%) 57 | 58 | .PHONY: $(DIRS:%=build-%) 59 | $(DIRS:%=build-%): build-%: 60 | (cd $(@:build-%=%); make BUILDDIR=$(BUILDDIR) all) 61 | 62 | .PHONY: $(DIRS:%=dir-%) 63 | $(DIRS:%=dir-%): dir-%: 64 | mkdir -p $(BUILDDIR)/$(@:dir-%=%) 65 | rm -rf $(BUILDDIR)/$(@:dir-%=%)/* 66 | cp -R $(@:dir-%=%)/$(BUILDDIR)/html/* $(BUILDDIR)/$(@:dir-%=%)/ 67 | 68 | .PHONY: $(DIRS:%=deploy-%) 69 | $(DIRS:%=deploy-%): deploy-%: 70 | GIT_DEPLOY_DIR=$(BUILDDIR) GIT_DEPLOY_SUBDIR=$(@:deploy-%=%) bash deploy.sh 71 | 72 | .PHONY: $(DIRS:%=publish-%) 73 | $(DIRS:%=publish-%): publish-%: % deploy-% 74 | 75 | .PHONY: $(DIRS:%=clean-%) 76 | $(DIRS:%=clean-%): clean-%: 77 | (cd $(@:clean-%=%); make BUILDDIR=$(BUILDDIR) clean) 78 | rm -rf $(BUILDDIR)/$(@:clean-%=%) 79 | 80 | .PHONY: $(DIRS:%=diff-%) 81 | $(DIRS:%=diff-%): diff-%: 82 | (cd $(@:diff-%=%); make BUILDDIR=$(BUILDDIR) diff) 83 | 84 | 85 | # Help. 86 | 87 | .PHONY: help 88 | help: 89 | @echo "Please use \`make ' where is one of" 90 | @echo " all to build all documents" 91 | @echo " publish to make all and push to gh-pages" 92 | @echo " to build a specific subdirectory" 93 | @echo " publish- to build and push a specific subdirectory" 94 | 95 | .PHONY: usage 96 | usage: help 97 | -------------------------------------------------------------------------------- /document/core/.gitignore: -------------------------------------------------------------------------------- 1 | _build 2 | _static 3 | document/*.pyc 4 | -------------------------------------------------------------------------------- /document/core/LICENSE: -------------------------------------------------------------------------------- 1 | W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE 2 | 3 | This work is being provided by the copyright holders under the following 4 | license. 5 | 6 | 7 | LICENSE 8 | 9 | By obtaining and/or copying this work, you (the licensee) agree that you have 10 | read, understood, and will comply with the following terms and conditions. 11 | 12 | Permission to copy, modify, and distribute this work, with or without 13 | modification, for any purpose and without fee or royalty is hereby granted, 14 | provided that you include the following on ALL copies of the work or portions 15 | thereof, including modifications: 16 | 17 | * The full text of this NOTICE in a location viewable to users of the 18 | redistributed or derivative work. 19 | 20 | * Any pre-existing intellectual property disclaimers, notices, or terms and 21 | conditions. If none exist, the W3C Software and Document Short Notice 22 | (https://www.w3.org/Consortium/Legal/copyright-software-short-notice) should 23 | be included. 24 | 25 | * Notice of any changes or modifications, through a copyright statement on the 26 | new code or document such as "This software or document includes material 27 | copied from or derived from [title and URI of the W3C document]. Copyright © [YEAR] W3C® (MIT, ERCIM, Keio, Beihang)." 28 | 29 | 30 | DISCLAIMERS 31 | 32 | THIS WORK IS PROVIDED "AS IS," AND COPYRIGHT HOLDERS MAKE NO REPRESENTATIONS 33 | OR WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO, WARRANTIES OF 34 | MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE 35 | SOFTWARE OR DOCUMENT WILL NOT INFRINGE ANY THIRD PARTY PATENTS, COPYRIGHTS, 36 | TRADEMARKS OR OTHER RIGHTS. 37 | 38 | COPYRIGHT HOLDERS WILL NOT BE LIABLE FOR ANY DIRECT, INDIRECT, SPECIAL OR 39 | CONSEQUENTIAL DAMAGES ARISING OUT OF ANY USE OF THE SOFTWARE OR DOCUMENT. 40 | 41 | The name and trademarks of copyright holders may NOT be used in advertising or 42 | publicity pertaining to the work without specific, written prior permission. 43 | Title to copyright in this work will at all times remain with copyright 44 | holders. 45 | 46 | 47 | NOTES 48 | 49 | This version: 50 | http://www.w3.org/Consortium/Legal/2015/copyright-software-and-document 51 | -------------------------------------------------------------------------------- /document/core/README.md: -------------------------------------------------------------------------------- 1 | # WebAssembly Core Specification 2 | 3 | This is the official WebAssembly "language" specification. 4 | 5 | It uses [Sphinx](http://www.sphinx-doc.org/). To install that: 6 | ``` 7 | pip install sphinx 8 | ``` 9 | To make HTML (result in `_build/html`): 10 | ``` 11 | make html 12 | ``` 13 | To make PDF (result in `_build/latex`, requires LaTeX): 14 | ``` 15 | make pdf 16 | ``` 17 | To make all: 18 | ``` 19 | make all 20 | ``` 21 | Finally, to make all and update webassembly.github.io/spec with it: 22 | ``` 23 | make publish 24 | ``` 25 | Please make sure to only use that once a change has approval. 26 | -------------------------------------------------------------------------------- /document/core/appendix/index-types.rst: -------------------------------------------------------------------------------- 1 | .. index:: type 2 | .. _index-type: 3 | 4 | Index of Types 5 | -------------- 6 | 7 | ======================================== =========================================== =============================================================================== 8 | Category Constructor Binary Opcode 9 | ======================================== =========================================== =============================================================================== 10 | :ref:`Type index ` :math:`x` (positive number as |Bs32| or |Bu32|) 11 | :ref:`Number type ` |I32| :math:`\hex{7F}` (-1 as |Bs7|) 12 | :ref:`Number type ` |I64| :math:`\hex{7E}` (-2 as |Bs7|) 13 | :ref:`Number type ` |F32| :math:`\hex{7D}` (-3 as |Bs7|) 14 | :ref:`Number type ` |F64| :math:`\hex{7C}` (-4 as |Bs7|) 15 | :ref:`Vector type ` |V128| :math:`\hex{7B}` (-5 as |Bs7|) 16 | (reserved) :math:`\hex{7A}` .. :math:`\hex{71}` 17 | :ref:`Reference type ` |FUNCREF| :math:`\hex{70}` (-16 as |Bs7|) 18 | :ref:`Reference type ` |EXTERNREF| :math:`\hex{6F}` (-17 as |Bs7|) 19 | (reserved) :math:`\hex{6E}` .. :math:`\hex{61}` 20 | :ref:`Function type ` :math:`[\valtype^\ast] \to [\valtype^\ast]` :math:`\hex{60}` (-32 as |Bs7|) 21 | (reserved) :math:`\hex{5F}` .. :math:`\hex{41}` 22 | :ref:`Result type ` :math:`[\epsilon]` :math:`\hex{40}` (-64 as |Bs7|) 23 | :ref:`Table type ` :math:`\limits~\reftype` (none) 24 | :ref:`Memory type ` :math:`\limits` (none) 25 | :ref:`Global type ` :math:`\mut~\valtype` (none) 26 | ======================================== =========================================== =============================================================================== 27 | -------------------------------------------------------------------------------- /document/core/appendix/index.rst: -------------------------------------------------------------------------------- 1 | .. _appendix: 2 | 3 | Appendix 4 | ======== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | embedding 10 | implementation 11 | algorithm 12 | custom 13 | properties 14 | changes 15 | 16 | .. only:: singlehtml 17 | 18 | .. toctree:: 19 | 20 | index-types 21 | index-instructions 22 | index-rules 23 | 24 | -------------------------------------------------------------------------------- /document/core/binary/index.rst: -------------------------------------------------------------------------------- 1 | .. _binary: 2 | 3 | Binary Format 4 | ============= 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | conventions 10 | values 11 | types 12 | instructions 13 | modules 14 | -------------------------------------------------------------------------------- /document/core/exec/index.rst: -------------------------------------------------------------------------------- 1 | .. _exec: 2 | 3 | Execution 4 | ========= 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | conventions 10 | runtime 11 | numerics 12 | instructions 13 | modules 14 | -------------------------------------------------------------------------------- /document/core/index.bs: -------------------------------------------------------------------------------- 1 | 18 | 19 |
20 | {
21 |   "WEBASSEMBLY": {
22 |     "href": "https://webassembly.github.io/spec/",
23 |     "title": "WebAssembly Specification",
24 |     "publisher": "W3C WebAssembly Community Group",
25 |     "status": "Draft"
26 |   }
27 | }
28 | 
29 | 30 |
31 | path: _build/bikeshed_singlehtml/index_fixed.html
32 | 
33 | -------------------------------------------------------------------------------- /document/core/index.rst: -------------------------------------------------------------------------------- 1 | WebAssembly Specification 2 | ========================= 3 | 4 | .. only:: html 5 | 6 | | Release |release| 7 | 8 | | Editor: Andreas Rossberg 9 | 10 | | Latest Draft: |WasmDraft| 11 | | Issue Tracker: |WasmIssues| 12 | 13 | .. toctree:: 14 | :maxdepth: 2 15 | 16 | intro/index 17 | syntax/index 18 | valid/index 19 | exec/index 20 | binary/index 21 | text/index 22 | appendix/index 23 | 24 | .. only:: latex 25 | 26 | .. toctree:: 27 | 28 | appendix/index-types 29 | appendix/index-instructions 30 | appendix/index-rules 31 | 32 | .. 33 | Only include these links when using (multi-page) html builder. 34 | (The singlepage html builder is called builder_singlehtml.) 35 | 36 | .. only:: builder_html 37 | 38 | * :ref:`index-type` 39 | * :ref:`index-instr` 40 | * :ref:`index-rules` 41 | 42 | * :ref:`genindex` 43 | -------------------------------------------------------------------------------- /document/core/intro/index.rst: -------------------------------------------------------------------------------- 1 | .. _intro: 2 | 3 | Introduction 4 | ============ 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | introduction 10 | overview 11 | -------------------------------------------------------------------------------- /document/core/static/custom.css: -------------------------------------------------------------------------------- 1 | a { 2 | color: #004BAB; 3 | text-decoration: none; 4 | } 5 | 6 | a.reference { 7 | border-bottom: none; 8 | } 9 | 10 | a.reference:hover { 11 | border-bottom: 1px dotted #004BAB; 12 | } 13 | 14 | body { 15 | font-size: 15px; 16 | } 17 | 18 | div.document { 19 | width: unset; 20 | max-width: 1000px; 21 | } 22 | div.bodywrapper { margin: 0 0 0 200px; } 23 | div.body { padding: 0 10px 0 10px; } 24 | div.footer { 25 | width: unset; 26 | max-width: 1000px; 27 | } 28 | 29 | div.body h1 { font-size: 200%; } 30 | div.body h2 { font-size: 150%; } 31 | div.body h3 { font-size: 120%; } 32 | div.body h4 { font-size: 110%; } 33 | 34 | div.note { 35 | border: 0px; 36 | font-size: 90%; 37 | background-color: #F6F8FF; 38 | } 39 | 40 | div.admonition { 41 | padding: 10px; 42 | } 43 | 44 | div.admonition p.admonition-title { 45 | margin: 0px 0px 0px 0px; 46 | font-size: 100%; 47 | font-weight: bold; 48 | } 49 | 50 | div.math { 51 | background-color: #F0F0F0; 52 | padding: 3px 0 3px 0; 53 | overflow-x: auto; 54 | overflow-y: hidden; 55 | } 56 | 57 | div.relations { 58 | display: block; 59 | } 60 | 61 | div.sphinxsidebar { 62 | z-index: 1; 63 | background: #FFF; 64 | margin-top: -30px; 65 | font-size: 13px; 66 | width: 200px; 67 | height: 100%; 68 | } 69 | 70 | div.sphinxsidebarwrapper p.logo { 71 | padding: 30px 40px 10px 0px; 72 | } 73 | 74 | div.sphinxsidebar h3 { 75 | font-size: 0px; 76 | } 77 | 78 | div.sphinxsidebar a { 79 | border-bottom: 0px; 80 | } 81 | 82 | div.sphinxsidebar a:hover { 83 | border-bottom: 1px dotted; 84 | } 85 | -------------------------------------------------------------------------------- /document/core/static/webassembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssembly/multi-memory/cf8b5aa27257311b8eac80ae83f4ba22ee308064/document/core/static/webassembly.png -------------------------------------------------------------------------------- /document/core/syntax/index.rst: -------------------------------------------------------------------------------- 1 | .. _syntax: 2 | 3 | Structure 4 | ========= 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | conventions 10 | values 11 | types 12 | instructions 13 | modules 14 | -------------------------------------------------------------------------------- /document/core/text/index.rst: -------------------------------------------------------------------------------- 1 | .. _text: 2 | 3 | Text Format 4 | =========== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | conventions 10 | lexical 11 | values 12 | types 13 | instructions 14 | modules 15 | -------------------------------------------------------------------------------- /document/core/util/README.htmldiff.pl: -------------------------------------------------------------------------------- 1 | This file is a copy of the HTML diff script found here: 2 | https://dev.w3.org/cvsweb/2009/htmldiff/ 3 | -------------------------------------------------------------------------------- /document/core/util/bikeshed/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Sphinx configuration for bikeshed builds (make bikeshed). 4 | # This imports the main document/core/conf.py, then overwrites certain config 5 | # values for the bikeshed build. 6 | 7 | import os 8 | import sys 9 | original_pwd = os.path.abspath('../..') 10 | # Change sys.path so that we can find the main 'conf.py'. 11 | sys.path.insert(0, original_pwd) 12 | from conf import * 13 | main_conf_pwd = pwd 14 | 15 | # Now that we have imported all the settings, we need to overwrite some of 16 | # them. 17 | 18 | # The first is `pwd`, we want to reset it to document/core, because rst_prolog 19 | # below depends on this to find macros.def. 20 | pwd = original_pwd 21 | 22 | # The bikeshed build requires the mathdefbs extension. 23 | extensions[extensions.index('util.mathdef')] = 'util.mathdefbs' 24 | 25 | # Overwrite html themes and configurations. 26 | html_theme = 'classic' 27 | html_permalinks = False 28 | html_theme_options = { 29 | 'nosidebar': True, 30 | } 31 | html_show_copyright = False 32 | 33 | # Overwrite the prolog to make sure the include directive has the correct path. 34 | 35 | main_macros_def = "/" + main_conf_pwd + "/util/macros.def" 36 | # If we hit this assertion, the configuration files probably moved, or files 37 | # are renamed, and we have to update rst_prolog accordingly. 38 | assert(main_macros_def in rst_prolog) 39 | rst_prolog = rst_prolog.replace(main_macros_def, "/" + pwd + "/util/macros.def") 40 | 41 | del mathjax3_config 42 | -------------------------------------------------------------------------------- /document/core/util/check_macros.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd `dirname $0`/.. 4 | 5 | FILES=`ls */*.rst` 6 | ERRORS=0 7 | 8 | for XREF in `grep xref util/macros.def`; do 9 | if echo $XREF | grep -q "[|]"; then 10 | MACRO=`echo $XREF | sed 's/^[^|]*[|]//g' | sed 's/[|].*$//g'` 11 | elif echo $XREF | grep -q xref; then 12 | FILE=`echo $XREF | sed 's/^.*xref{//g' | sed 's/}.*$//g'`.rst 13 | LABEL=`echo $XREF | sed 's/^[^}]*}{//g' | sed 's/}.*$//g'` 14 | TARGET=".. _$LABEL:" 15 | if ! [ -f $FILE ] || ! grep -q "$TARGET" $FILE; then 16 | ERRORS=1 17 | echo Undefined cross-reference $FILE:$LABEL in macro "|$MACRO|" 18 | if ! [ -f $FILE ]; then 19 | echo ...non-existent file $FILE 20 | fi 21 | if grep -q "$TARGET" $FILES; then 22 | echo ...defined in `grep -l "$TARGET" $FILES` 23 | fi 24 | fi 25 | fi 26 | done 27 | 28 | if [ $ERRORS -eq 0 ]; then 29 | echo All cross-references okay. 30 | else 31 | exit 1; 32 | fi 33 | -------------------------------------------------------------------------------- /document/core/util/katex_fix.patch: -------------------------------------------------------------------------------- 1 | 123c123,126 2 | < font: normal 1.21em KaTeX_Main, Times New Roman, serif; 3 | --- 4 | > /* font: normal 1.21em KaTeX_Main, Times New Roman, serif; */ 5 | > font-weight: normal; 6 | > font-size: 1.21em; 7 | > font-family: KaTeX_Main, Times New Roman, serif; 8 | 126d128 9 | < text-rendering: auto; 10 | 989c991 11 | < .katex-display { 12 | --- 13 | > div > .katex-display { 14 | 994c996 15 | < .katex-display > .katex { 16 | --- 17 | > div > .katex-display > .katex { 18 | 999c1001 19 | < .katex-display > .katex > .katex-html { 20 | --- 21 | > div > .katex-display > .katex > .katex-html { 22 | 1003c1005 23 | < .katex-display > .katex > .katex-html > .tag { 24 | --- 25 | > div > .katex-display > .katex > .katex-html > .tag { 26 | 1007c1009,1022 27 | < 28 | --- 29 | > /* Force borders on tables */ 30 | > table { 31 | > border-collapse: collapse; 32 | > } 33 | > .docutils th, td { 34 | > border: 1px solid; 35 | > padding: .4em; 36 | > } 37 | > .footnote td { 38 | > border: 0; 39 | > } 40 | > .codepre { 41 | > white-space: pre; 42 | > } 43 | -------------------------------------------------------------------------------- /document/core/util/pseudo-lexer.py: -------------------------------------------------------------------------------- 1 | from pygments.lexer import RegexLexer 2 | from pygments.token import * 3 | from sphinx.highlighting import lexers 4 | 5 | class PseudoLexer(RegexLexer): 6 | name = 'Pseudo' 7 | aliases = ['pseudo'] 8 | filenames = ['*.pseudo'] 9 | 10 | tokens = { 11 | 'root': [ 12 | (r"(? string -> Ast.module_ (* raises Code *) 4 | 5 | val decode_custom : Ast.name -> string -> string -> string list (* raises Code *) 6 | -------------------------------------------------------------------------------- /interpreter/binary/encode.mli: -------------------------------------------------------------------------------- 1 | exception Code of Source.region * string 2 | 3 | val version : int32 4 | val encode : Ast.module_ -> string 5 | val encode_custom : Ast.name -> string -> string 6 | -------------------------------------------------------------------------------- /interpreter/binary/utf8.ml: -------------------------------------------------------------------------------- 1 | type codepoint = int 2 | type unicode = codepoint list 3 | 4 | exception Utf8 5 | 6 | let con n = 0x80 lor (n land 0x3f) 7 | 8 | let rec encode ns = Lib.String.implode (List.map Char.chr (encode' ns)) 9 | and encode' = function 10 | | [] -> [] 11 | | n::ns when n < 0 -> 12 | raise Utf8 13 | | n::ns when n < 0x80 -> 14 | n :: encode' ns 15 | | n::ns when n < 0x800 -> 16 | 0xc0 lor (n lsr 6) :: con n :: encode' ns 17 | | n::ns when n < 0x10000 -> 18 | 0xe0 lor (n lsr 12) :: con (n lsr 6) :: con n :: encode' ns 19 | | n::ns when n < 0x110000 -> 20 | 0xf0 lor (n lsr 18) :: con (n lsr 12) :: con (n lsr 6) :: con n 21 | :: encode' ns 22 | | _ -> 23 | raise Utf8 24 | 25 | let con b = if b land 0xc0 = 0x80 then b land 0x3f else raise Utf8 26 | let code min n = 27 | if n < min || (0xd800 <= n && n < 0xe000) || n >= 0x110000 then raise Utf8 28 | else n 29 | 30 | let rec decode s = decode' (List.map Char.code (Lib.String.explode s)) 31 | and decode' = function 32 | | [] -> [] 33 | | b1::bs when b1 < 0x80 -> 34 | code 0x0 b1 :: decode' bs 35 | | b1::bs when b1 < 0xc0 -> 36 | raise Utf8 37 | | b1::b2::bs when b1 < 0xe0 -> 38 | code 0x80 ((b1 land 0x1f) lsl 6 + con b2) :: decode' bs 39 | | b1::b2::b3::bs when b1 < 0xf0 -> 40 | code 0x800 ((b1 land 0x0f) lsl 12 + con b2 lsl 6 + con b3) :: decode' bs 41 | | b1::b2::b3::b4::bs when b1 < 0xf8 -> 42 | code 0x10000 ((b1 land 0x07) lsl 18 + con b2 lsl 12 + con b3 lsl 6 + con b4) 43 | :: decode' bs 44 | | _ -> 45 | raise Utf8 46 | -------------------------------------------------------------------------------- /interpreter/binary/utf8.mli: -------------------------------------------------------------------------------- 1 | type codepoint = int 2 | type unicode = codepoint list 3 | 4 | exception Utf8 5 | 6 | val decode : string -> unicode (* raises Utf8 *) 7 | val encode : unicode -> string (* raises Utf8 *) 8 | -------------------------------------------------------------------------------- /interpreter/dune: -------------------------------------------------------------------------------- 1 | (include_subdirs unqualified) 2 | 3 | (library 4 | (public_name wasm) 5 | (modules :standard \ main wasm wast smallint) 6 | ) 7 | 8 | (executable 9 | (public_name wasm) 10 | (modules wasm) 11 | (libraries wasm) 12 | (flags (-open Wasm)) 13 | ) 14 | 15 | (executable 16 | (name smallint) 17 | (modules smallint) 18 | (libraries wasm) 19 | (flags (-open Wasm)) 20 | ) 21 | 22 | (executable 23 | (name wast) 24 | (modules wast) 25 | (modes js) 26 | (libraries js_of_ocaml wasm) 27 | (preprocess (pps js_of_ocaml-ppx)) 28 | ) 29 | 30 | (env (_ (flags (-w +a-4-27-42-44-45-70 -warn-error +a-3)))) 31 | 32 | (subdir text 33 | (ocamllex (modules lexer)) 34 | (menhir (modules parser)) 35 | ) 36 | 37 | (rule 38 | (targets wasm.ml) 39 | (deps main/main.ml) 40 | (action (copy main/main.ml wasm.ml)) 41 | ) 42 | 43 | (rule 44 | (alias runtest) 45 | (deps 46 | ./wasm.exe 47 | ./smallint.exe 48 | (source_tree ../test) 49 | ) 50 | (action 51 | (progn 52 | (run ../test/core/run.py --wasm ./wasm.exe) 53 | (run ./smallint.exe) 54 | ) 55 | ) 56 | ) 57 | -------------------------------------------------------------------------------- /interpreter/dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 2.9) 2 | 3 | (name wasm) 4 | (license Apache-2.0) 5 | (source (github WebAssembly/spec)) 6 | 7 | (authors "Andreas Rossberg = 4.12)) 20 | (menhir (>= 20220210)) 21 | ) 22 | ) 23 | -------------------------------------------------------------------------------- /interpreter/exec/eval.mli: -------------------------------------------------------------------------------- 1 | open Values 2 | open Instance 3 | 4 | exception Link of Source.region * string 5 | exception Trap of Source.region * string 6 | exception Crash of Source.region * string 7 | exception Exhaustion of Source.region * string 8 | 9 | val init : Ast.module_ -> extern list -> module_inst (* raises Link, Trap *) 10 | val invoke : func_inst -> value list -> value list (* raises Trap *) 11 | -------------------------------------------------------------------------------- /interpreter/exec/eval_num.mli: -------------------------------------------------------------------------------- 1 | open Values 2 | 3 | val eval_unop : Ast.unop -> num -> num 4 | val eval_binop : Ast.binop -> num -> num -> num 5 | val eval_testop : Ast.testop -> num -> bool 6 | val eval_relop : Ast.relop -> num -> num -> bool 7 | val eval_cvtop : Ast.cvtop -> num -> num 8 | -------------------------------------------------------------------------------- /interpreter/exec/eval_vec.mli: -------------------------------------------------------------------------------- 1 | open Values 2 | 3 | val eval_testop : Ast.vec_testop -> vec -> bool 4 | val eval_unop : Ast.vec_unop -> vec -> vec 5 | val eval_binop : Ast.vec_binop -> vec -> vec -> vec 6 | val eval_relop : Ast.vec_relop -> vec -> vec -> vec 7 | val eval_cvtop : Ast.vec_cvtop -> vec -> vec 8 | val eval_shiftop : Ast.vec_shiftop -> vec -> num -> vec 9 | val eval_bitmaskop : Ast.vec_bitmaskop -> vec -> num 10 | val eval_vtestop : Ast.vec_vtestop -> vec -> bool 11 | val eval_vunop : Ast.vec_vunop -> vec -> vec 12 | val eval_vbinop : Ast.vec_vbinop -> vec -> vec -> vec 13 | val eval_vternop : Ast.vec_vternop -> vec -> vec -> vec -> vec 14 | val eval_splatop : Ast.vec_splatop -> num -> vec 15 | val eval_extractop : Ast.vec_extractop -> vec -> num 16 | val eval_replaceop : Ast.vec_replaceop -> vec -> num -> vec 17 | -------------------------------------------------------------------------------- /interpreter/exec/f32.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * OCaml lacks 32-bit floats, however we can emulate all the basic operations 3 | * using 64-bit floats, as described in the paper 4 | * "When is double rounding innocuous?" by Samuel A. Figueroa. 5 | *) 6 | include Fxx.Make 7 | (struct 8 | include Int32 9 | let mantissa = 23 10 | let pos_nan = 0x7fc0_0000l 11 | let neg_nan = 0xffc0_0000l 12 | let bare_nan = 0x7f80_0000l 13 | let to_hex_string = Printf.sprintf "%lx" 14 | end) 15 | -------------------------------------------------------------------------------- /interpreter/exec/f32_convert.ml: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible type conversions to f32 implementation *) 2 | 3 | let demote_f64 x = 4 | let xf = F64.to_float x in 5 | if xf = xf then F32.of_float xf else 6 | let nan64bits = F64.to_bits x in 7 | let sign_field = Int64.(shift_left (shift_right_logical nan64bits 63) 31) in 8 | let significand_field = Int64.(shift_right_logical (shift_left nan64bits 12) 41) in 9 | let fields = Int64.logor sign_field significand_field in 10 | let nan32bits = Int32.logor 0x7fc0_0000l (I32_convert.wrap_i64 fields) in 11 | F32.of_bits nan32bits 12 | 13 | let convert_i32_s x = 14 | F32.of_float (Int32.to_float x) 15 | 16 | (* 17 | * Similar to convert_i64_u below, the high half of the i32 range are beyond 18 | * the range where f32 can represent odd numbers, though we do need to adjust 19 | * the least significant bit to round correctly. 20 | *) 21 | let convert_i32_u x = 22 | F32.of_float Int32.( 23 | if x >= zero then to_float x else 24 | to_float (logor (shift_right_logical x 1) (logand x 1l)) *. 2.0 25 | ) 26 | 27 | (* 28 | * Values that are too large would get rounded when represented in f64, 29 | * but double rounding via i64->f64->f32 can produce inaccurate results. 30 | * Hence, for large values we shift right but make sure to accumulate the lost 31 | * bits in the least significant bit, such that rounding still is correct. 32 | *) 33 | let convert_i64_s x = 34 | F32.of_float Int64.( 35 | if abs x < 0x10_0000_0000_0000L then to_float x else 36 | let r = if logand x 0xfffL = 0L then 0L else 1L in 37 | to_float (logor (shift_right x 12) r) *. 0x1p12 38 | ) 39 | 40 | let convert_i64_u x = 41 | F32.of_float Int64.( 42 | if I64.lt_u x 0x10_0000_0000_0000L then to_float x else 43 | let r = if logand x 0xfffL = 0L then 0L else 1L in 44 | to_float (logor (shift_right_logical x 12) r) *. 0x1p12 45 | ) 46 | 47 | let reinterpret_i32 = F32.of_bits 48 | -------------------------------------------------------------------------------- /interpreter/exec/f32_convert.mli: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible type conversions to f32 implementation *) 2 | 3 | val demote_f64 : F64.t -> F32.t 4 | val convert_i32_s : I32.t -> F32.t 5 | val convert_i32_u : I32.t -> F32.t 6 | val convert_i64_s : I64.t -> F32.t 7 | val convert_i64_u : I64.t -> F32.t 8 | val reinterpret_i32 : I32.t -> F32.t 9 | -------------------------------------------------------------------------------- /interpreter/exec/f64.ml: -------------------------------------------------------------------------------- 1 | include Fxx.Make 2 | (struct 3 | include Int64 4 | let mantissa = 52 5 | let pos_nan = 0x7ff8_0000_0000_0000L 6 | let neg_nan = 0xfff8_0000_0000_0000L 7 | let bare_nan = 0x7ff0_0000_0000_0000L 8 | let to_hex_string = Printf.sprintf "%Lx" 9 | end) 10 | -------------------------------------------------------------------------------- /interpreter/exec/f64_convert.ml: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible type conversions to f64 implementation *) 2 | 3 | let promote_f32 x = 4 | let xf = F32.to_float x in 5 | if xf = xf then F64.of_float xf else 6 | let nan32bits = I64_convert.extend_i32_u (F32.to_bits x) in 7 | let sign_field = Int64.(shift_left (shift_right_logical nan32bits 31) 63) in 8 | let significand_field = Int64.(shift_right_logical (shift_left nan32bits 41) 12) in 9 | let fields = Int64.logor sign_field significand_field in 10 | let nan64bits = Int64.logor 0x7ff8_0000_0000_0000L fields in 11 | F64.of_bits nan64bits 12 | 13 | let convert_i32_s x = 14 | F64.of_float (Int32.to_float x) 15 | 16 | (* 17 | * Unlike the other convert_u functions, the high half of the i32 range is 18 | * within the range where f32 can represent odd numbers, so we can't do the 19 | * shift. Instead, we can use int64 signed arithmetic. 20 | *) 21 | let convert_i32_u x = 22 | F64.of_float Int64.(to_float (logand (of_int32 x) 0x0000_0000_ffff_ffffL)) 23 | 24 | let convert_i64_s x = 25 | F64.of_float (Int64.to_float x) 26 | 27 | (* 28 | * Values in the low half of the int64 range can be converted with a signed 29 | * conversion. The high half is beyond the range where f64 can represent odd 30 | * numbers, so we can shift the value right, adjust the least significant 31 | * bit to round correctly, do a conversion, and then scale it back up. 32 | *) 33 | let convert_i64_u x = 34 | F64.of_float Int64.( 35 | if x >= zero then to_float x else 36 | to_float (logor (shift_right_logical x 1) (logand x 1L)) *. 2.0 37 | ) 38 | 39 | let reinterpret_i64 = F64.of_bits 40 | -------------------------------------------------------------------------------- /interpreter/exec/f64_convert.mli: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible type conversions to f64 implementation *) 2 | 3 | val promote_f32 : F32.t -> F64.t 4 | val convert_i32_s : I32.t -> F64.t 5 | val convert_i32_u : I32.t -> F64.t 6 | val convert_i64_s : I64.t -> F64.t 7 | val convert_i64_u : I64.t -> F64.t 8 | val reinterpret_i64 : I64.t -> F64.t 9 | -------------------------------------------------------------------------------- /interpreter/exec/i16.ml: -------------------------------------------------------------------------------- 1 | (* Uses Int32 as the underlying storage. All int16 values will be 2 | * stored signed-extended. E.g. -1 will be stored with all high bits set. 3 | *) 4 | include Ixx.Make (struct 5 | include Int32 6 | 7 | let bitwidth = 16 8 | let to_hex_string i = Printf.sprintf "%lx" (Int32.logand i 0xffffl) 9 | 10 | let of_int64 = Int64.to_int32 11 | let to_int64 = Int64.of_int32 12 | end) 13 | -------------------------------------------------------------------------------- /interpreter/exec/i32.ml: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible i32 implementation *) 2 | 3 | include Ixx.Make 4 | (struct 5 | include Int32 6 | let bitwidth = 32 7 | let to_hex_string = Printf.sprintf "%lx" 8 | 9 | let of_int64 = Int64.to_int32 10 | let to_int64 = Int64.of_int32 11 | end) 12 | -------------------------------------------------------------------------------- /interpreter/exec/i32_convert.ml: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible type conversions to i32 implementation *) 2 | 3 | let wrap_i64 x = Int64.to_int32 x 4 | 5 | let trunc_f32_s x = 6 | if F32.ne x x then 7 | raise Ixx.InvalidConversion 8 | else 9 | let xf = F32.to_float x in 10 | if xf >= -.Int32.(to_float min_int) || xf < Int32.(to_float min_int) then 11 | raise Ixx.Overflow 12 | else 13 | Int32.of_float xf 14 | 15 | let trunc_f32_u x = 16 | if F32.ne x x then 17 | raise Ixx.InvalidConversion 18 | else 19 | let xf = F32.to_float x in 20 | if xf >= -.Int32.(to_float min_int) *. 2.0 || xf <= -1.0 then 21 | raise Ixx.Overflow 22 | else 23 | Int64.(to_int32 (of_float xf)) 24 | 25 | let trunc_f64_s x = 26 | if F64.ne x x then 27 | raise Ixx.InvalidConversion 28 | else 29 | let xf = F64.to_float x in 30 | if xf >= -.Int32.(to_float min_int) || xf <= Int32.(to_float min_int) -. 1.0 then 31 | raise Ixx.Overflow 32 | else 33 | Int32.of_float xf 34 | 35 | let trunc_f64_u x = 36 | if F64.ne x x then 37 | raise Ixx.InvalidConversion 38 | else 39 | let xf = F64.to_float x in 40 | if xf >= -.Int32.(to_float min_int) *. 2.0 || xf <= -1.0 then 41 | raise Ixx.Overflow 42 | else 43 | Int64.(to_int32 (of_float xf)) 44 | 45 | let trunc_sat_f32_s x = 46 | if F32.ne x x then 47 | 0l 48 | else 49 | let xf = F32.to_float x in 50 | if xf < Int32.(to_float min_int) then 51 | Int32.min_int 52 | else if xf >= -.Int32.(to_float min_int) then 53 | Int32.max_int 54 | else 55 | Int32.of_float xf 56 | 57 | let trunc_sat_f32_u x = 58 | if F32.ne x x then 59 | 0l 60 | else 61 | let xf = F32.to_float x in 62 | if xf <= -1.0 then 63 | 0l 64 | else if xf >= -.Int32.(to_float min_int) *. 2.0 then 65 | -1l 66 | else 67 | Int64.(to_int32 (of_float xf)) 68 | 69 | let trunc_sat_f64_s x = 70 | if F64.ne x x then 71 | 0l 72 | else 73 | let xf = F64.to_float x in 74 | if xf < Int32.(to_float min_int) then 75 | Int32.min_int 76 | else if xf >= -.Int32.(to_float min_int) then 77 | Int32.max_int 78 | else 79 | Int32.of_float xf 80 | 81 | let trunc_sat_f64_u x = 82 | if F64.ne x x then 83 | 0l 84 | else 85 | let xf = F64.to_float x in 86 | if xf <= -1.0 then 87 | 0l 88 | else if xf >= -.Int32.(to_float min_int) *. 2.0 then 89 | -1l 90 | else 91 | Int64.(to_int32 (of_float xf)) 92 | 93 | let reinterpret_f32 = F32.to_bits 94 | -------------------------------------------------------------------------------- /interpreter/exec/i32_convert.mli: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible type conversions to i32 implementation *) 2 | 3 | val wrap_i64 : I64.t -> I32.t 4 | val trunc_f32_s : F32.t -> I32.t 5 | val trunc_f32_u : F32.t -> I32.t 6 | val trunc_f64_s : F64.t -> I32.t 7 | val trunc_f64_u : F64.t -> I32.t 8 | val trunc_sat_f32_s : F32.t -> I32.t 9 | val trunc_sat_f32_u : F32.t -> I32.t 10 | val trunc_sat_f64_s : F64.t -> I32.t 11 | val trunc_sat_f64_u : F64.t -> I32.t 12 | val reinterpret_f32 : F32.t -> I32.t 13 | -------------------------------------------------------------------------------- /interpreter/exec/i64.ml: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible i64 implementation *) 2 | 3 | include Ixx.Make 4 | (struct 5 | include Int64 6 | let bitwidth = 64 7 | let to_hex_string = Printf.sprintf "%Lx" 8 | 9 | let of_int64 i = i 10 | let to_int64 i = i 11 | end) 12 | -------------------------------------------------------------------------------- /interpreter/exec/i64_convert.mli: -------------------------------------------------------------------------------- 1 | (* WebAssembly-compatible type conversions to i64 implementation *) 2 | 3 | val extend_i32_s : I32.t -> I64.t 4 | val extend_i32_u : I32.t -> I64.t 5 | val trunc_f32_s : F32.t -> I64.t 6 | val trunc_f32_u : F32.t -> I64.t 7 | val trunc_f64_s : F64.t -> I64.t 8 | val trunc_f64_u : F64.t -> I64.t 9 | val trunc_sat_f32_s : F32.t -> I64.t 10 | val trunc_sat_f32_u : F32.t -> I64.t 11 | val trunc_sat_f64_s : F64.t -> I64.t 12 | val trunc_sat_f64_u : F64.t -> I64.t 13 | val reinterpret_f64 : F64.t -> I64.t 14 | -------------------------------------------------------------------------------- /interpreter/exec/i8.ml: -------------------------------------------------------------------------------- 1 | (* Uses Int32 as the underlying storage. All int8 values will be 2 | * stored signed-extended. E.g. -1 will be stored with all high bits set. 3 | *) 4 | include Ixx.Make (struct 5 | include Int32 6 | 7 | let bitwidth = 8 8 | let to_hex_string i = Printf.sprintf "%lx" (Int32.logand i 0xffl) 9 | 10 | let of_int64 = Int64.to_int32 11 | let to_int64 = Int64.of_int32 12 | end) 13 | -------------------------------------------------------------------------------- /interpreter/host/env.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Emulation of (a subset of) the `env` module currently used by Binaryen, 3 | * so that we can run modules generated by Binaryen. This is a stopgap until 4 | * we have agreement on what libc should look like. 5 | *) 6 | 7 | open Values 8 | open Types 9 | open Instance 10 | 11 | 12 | let error msg = raise (Eval.Crash (Source.no_region, msg)) 13 | 14 | let type_error v t = 15 | error 16 | ("type error, expected " ^ string_of_value_type t ^ 17 | ", got " ^ string_of_value_type (type_of_value v)) 18 | 19 | let empty = function 20 | | [] -> () 21 | | vs -> error "type error, too many arguments" 22 | 23 | let single = function 24 | | [] -> error "type error, missing arguments" 25 | | [v] -> v 26 | | vs -> error "type error, too many arguments" 27 | 28 | let int = function 29 | | Num (I32 i) -> Int32.to_int i 30 | | v -> type_error v (NumType I32Type) 31 | 32 | 33 | let abort vs = 34 | empty vs; 35 | print_endline "Abort!"; 36 | exit (-1) 37 | 38 | let exit vs = 39 | exit (int (single vs)) 40 | 41 | 42 | let lookup name t = 43 | match Utf8.encode name, t with 44 | | "abort", ExternFuncType t -> ExternFunc (Func.alloc_host t abort) 45 | | "exit", ExternFuncType t -> ExternFunc (Func.alloc_host t exit) 46 | | _ -> raise Not_found 47 | -------------------------------------------------------------------------------- /interpreter/host/spectest.ml: -------------------------------------------------------------------------------- 1 | (* 2 | * Simple collection of functions useful for writing test cases. 3 | *) 4 | 5 | open Types 6 | open Values 7 | open Instance 8 | 9 | 10 | let global (GlobalType (t, _) as gt) = 11 | let v = 12 | match t with 13 | | NumType I32Type -> Num (I32 666l) 14 | | NumType I64Type -> Num (I64 666L) 15 | | NumType F32Type -> Num (F32 (F32.of_float 666.6)) 16 | | NumType F64Type -> Num (F64 (F64.of_float 666.6)) 17 | | VecType V128Type -> Vec (V128 (V128.I32x4.of_lanes [666l; 666l; 666l; 666l])) 18 | | RefType t -> Ref (NullRef t) 19 | in Global.alloc gt v 20 | 21 | let table = 22 | Table.alloc (TableType ({min = 10l; max = Some 20l}, FuncRefType)) 23 | (NullRef FuncRefType) 24 | let memory = Memory.alloc (MemoryType {min = 1l; max = Some 2l}) 25 | let func f t = Func.alloc_host t (f t) 26 | 27 | let print_value v = 28 | Printf.printf "%s : %s\n" 29 | (Values.string_of_value v) 30 | (Types.string_of_value_type (Values.type_of_value v)) 31 | 32 | let print (FuncType (_, out)) vs = 33 | List.iter print_value vs; 34 | flush_all (); 35 | List.map default_value out 36 | 37 | 38 | let lookup name t = 39 | match Utf8.encode name, t with 40 | | "print", _ -> ExternFunc (func print (FuncType ([], []))) 41 | | "print_i32", _ -> ExternFunc (func print (FuncType ([NumType I32Type], []))) 42 | | "print_i64", _ -> ExternFunc (func print (FuncType ([NumType I64Type], []))) 43 | | "print_f32", _ -> ExternFunc (func print (FuncType ([NumType F32Type], []))) 44 | | "print_f64", _ -> ExternFunc (func print (FuncType ([NumType F64Type], []))) 45 | | "print_i32_f32", _ -> 46 | ExternFunc (func print (FuncType ([NumType I32Type; NumType F32Type], []))) 47 | | "print_f64_f64", _ -> 48 | ExternFunc (func print (FuncType ([NumType F64Type; NumType F64Type], []))) 49 | | "global_i32", _ -> ExternGlobal (global (GlobalType (NumType I32Type, Immutable))) 50 | | "global_i64", _ -> ExternGlobal (global (GlobalType (NumType I64Type, Immutable))) 51 | | "global_f32", _ -> ExternGlobal (global (GlobalType (NumType F32Type, Immutable))) 52 | | "global_f64", _ -> ExternGlobal (global (GlobalType (NumType F64Type, Immutable))) 53 | | "table", _ -> ExternTable table 54 | | "memory", _ -> ExternMemory memory 55 | | _ -> raise Not_found 56 | -------------------------------------------------------------------------------- /interpreter/jslib/wast.ml: -------------------------------------------------------------------------------- 1 | (* Implements a wrapper library that allows the use of the reference 2 | * interpreter's encode/decode functionality in JavaScript. 3 | *) 4 | open Wasm 5 | open Js_of_ocaml 6 | 7 | let () = 8 | Js.export "WebAssemblyText" 9 | (object%js (_self) 10 | 11 | method encode (s : Js.js_string Js.t) : (Typed_array.arrayBuffer Js.t) = 12 | let _, def = Parse.Module.parse_string (Js.to_string s) in 13 | let bs = 14 | match def.Source.it with 15 | | Script.Textual m -> (Encode.encode m) 16 | | Script.Encoded (_, bs) -> bs 17 | | Script.Quoted (_, _) -> failwith "Unsupported" in 18 | let buf = new%js Typed_array.arrayBuffer (String.length bs) in 19 | let u8arr = new%js Typed_array.uint8Array_fromBuffer buf in 20 | String.iteri (fun i c -> Typed_array.set u8arr i (int_of_char c)) bs; buf 21 | 22 | method decode (buf : Typed_array.arrayBuffer Js.t) width : (Js.js_string Js.t) = 23 | let s = Typed_array.String.of_uint8Array (new%js Typed_array.uint8Array_fromBuffer buf) in 24 | let m = Decode.decode "(decode)" s in 25 | Js.string (Sexpr.to_string width (Arrange.module_ m)) 26 | 27 | end) 28 | -------------------------------------------------------------------------------- /interpreter/main/flags.ml: -------------------------------------------------------------------------------- 1 | let interactive = ref false 2 | let trace = ref false 3 | let unchecked = ref false 4 | let print_sig = ref false 5 | let dry = ref false 6 | let width = ref 80 7 | let harness = ref true 8 | let budget = ref 256 9 | -------------------------------------------------------------------------------- /interpreter/main/main.ml: -------------------------------------------------------------------------------- 1 | let name = "wasm" 2 | let version = "2.0.1" 3 | 4 | let configure () = 5 | Import.register (Utf8.decode "spectest") Spectest.lookup; 6 | Import.register (Utf8.decode "env") Env.lookup 7 | 8 | let banner () = 9 | print_endline (name ^ " " ^ version ^ " reference interpreter") 10 | 11 | let usage = "Usage: " ^ name ^ " [option] [file ...]" 12 | 13 | let args = ref [] 14 | let add_arg source = args := !args @ [source] 15 | 16 | let quote s = "\"" ^ String.escaped s ^ "\"" 17 | 18 | let argspec = Arg.align 19 | [ 20 | "-", Arg.Set Flags.interactive, 21 | " run interactively (default if no files given)"; 22 | "-e", Arg.String add_arg, " evaluate string"; 23 | "-i", Arg.String (fun file -> add_arg ("(input " ^ quote file ^ ")")), 24 | " read script from file"; 25 | "-o", Arg.String (fun file -> add_arg ("(output " ^ quote file ^ ")")), 26 | " write module to file"; 27 | "-b", Arg.Int (fun n -> Flags.budget := n), 28 | " configure call depth budget (default is " ^ string_of_int !Flags.budget ^ ")"; 29 | "-w", Arg.Int (fun n -> Flags.width := n), 30 | " configure output width (default is " ^ string_of_int !Flags.width ^ ")"; 31 | "-s", Arg.Set Flags.print_sig, " show module signatures"; 32 | "-u", Arg.Set Flags.unchecked, " unchecked, do not perform validation"; 33 | "-j", Arg.Clear Flags.harness, " exclude harness for JS conversion"; 34 | "-d", Arg.Set Flags.dry, " dry, do not run program"; 35 | "-t", Arg.Set Flags.trace, " trace execution"; 36 | "-v", Arg.Unit banner, " show version" 37 | ] 38 | 39 | let () = 40 | Printexc.record_backtrace true; 41 | try 42 | configure (); 43 | Arg.parse argspec 44 | (fun file -> add_arg ("(input " ^ quote file ^ ")")) usage; 45 | List.iter (fun arg -> if not (Run.run_string arg) then exit 1) !args; 46 | if !args = [] then Flags.interactive := true; 47 | if !Flags.interactive then begin 48 | Flags.print_sig := true; 49 | banner (); 50 | Run.run_stdin () 51 | end 52 | with exn -> 53 | flush_all (); 54 | prerr_endline 55 | (Sys.argv.(0) ^ ": uncaught exception " ^ Printexc.to_string exn); 56 | Printexc.print_backtrace stderr; 57 | exit 2 58 | -------------------------------------------------------------------------------- /interpreter/runtime/data.ml: -------------------------------------------------------------------------------- 1 | type data = string ref 2 | type t = data 3 | 4 | exception Bounds 5 | 6 | let alloc bs = ref bs 7 | 8 | let size seg = I64.of_int_u (String.length !seg) 9 | 10 | let load seg i = 11 | let i' = Int64.to_int i in 12 | if i' < 0 || i' >= String.length !seg then raise Bounds; 13 | !seg.[i'] 14 | 15 | let drop seg = seg := "" 16 | -------------------------------------------------------------------------------- /interpreter/runtime/data.mli: -------------------------------------------------------------------------------- 1 | type data 2 | type t = data 3 | 4 | val alloc : string -> data 5 | val size : data -> Memory.address 6 | val load : data -> Memory.address -> char 7 | val drop : data -> unit 8 | -------------------------------------------------------------------------------- /interpreter/runtime/elem.ml: -------------------------------------------------------------------------------- 1 | type elem = Values.ref_ list ref 2 | type t = elem 3 | 4 | exception Bounds 5 | 6 | let alloc rs = ref rs 7 | let size seg = Lib.List32.length !seg 8 | 9 | let load seg i = 10 | if i < 0l || i >= Lib.List32.length !seg then raise Bounds; 11 | Lib.List32.nth !seg i 12 | 13 | let drop seg = seg := [] 14 | -------------------------------------------------------------------------------- /interpreter/runtime/elem.mli: -------------------------------------------------------------------------------- 1 | open Values 2 | 3 | type elem 4 | type t = elem 5 | 6 | val alloc : ref_ list -> elem 7 | val size : elem -> Table.size 8 | val load : elem -> Table.index -> ref_ 9 | val drop : elem -> unit 10 | -------------------------------------------------------------------------------- /interpreter/runtime/func.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Values 3 | 4 | type 'inst t = 'inst func 5 | and 'inst func = 6 | | AstFunc of func_type * 'inst * Ast.func 7 | | HostFunc of func_type * (value list -> value list) 8 | 9 | let alloc ft inst f = AstFunc (ft, inst, f) 10 | let alloc_host ft f = HostFunc (ft, f) 11 | 12 | let type_of = function 13 | | AstFunc (ft, _, _) -> ft 14 | | HostFunc (ft, _) -> ft 15 | -------------------------------------------------------------------------------- /interpreter/runtime/func.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Values 3 | 4 | type 'inst t = 'inst func 5 | and 'inst func = 6 | | AstFunc of func_type * 'inst * Ast.func 7 | | HostFunc of func_type * (value list -> value list) 8 | 9 | val alloc : func_type -> 'inst -> Ast.func -> 'inst func 10 | val alloc_host : func_type -> (value list -> value list) -> 'inst func 11 | val type_of : 'inst func -> func_type 12 | -------------------------------------------------------------------------------- /interpreter/runtime/global.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Values 3 | 4 | type global = {ty : global_type; mutable content : value} 5 | type t = global 6 | 7 | exception Type 8 | exception NotMutable 9 | 10 | let alloc (GlobalType (t, _) as ty) v = 11 | if type_of_value v <> t then raise Type; 12 | {ty; content = v} 13 | 14 | let type_of glob = 15 | glob.ty 16 | 17 | let load glob = 18 | glob.content 19 | 20 | let store glob v = 21 | let GlobalType (t, mut) = glob.ty in 22 | if mut <> Mutable then raise NotMutable; 23 | if type_of_value v <> t then raise Type; 24 | glob.content <- v 25 | -------------------------------------------------------------------------------- /interpreter/runtime/global.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Values 3 | 4 | type global 5 | type t = global 6 | 7 | exception Type 8 | exception NotMutable 9 | 10 | val alloc : global_type -> value -> global (* raises Type *) 11 | val type_of : global -> global_type 12 | 13 | val load : global -> value 14 | val store : global -> value -> unit (* raises Type, NotMutable *) 15 | -------------------------------------------------------------------------------- /interpreter/runtime/instance.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | 3 | type module_inst = 4 | { 5 | types : func_type list; 6 | funcs : func_inst list; 7 | tables : table_inst list; 8 | memories : memory_inst list; 9 | globals : global_inst list; 10 | elems : elem_inst list; 11 | datas : data_inst list; 12 | exports : export_inst list; 13 | } 14 | 15 | and func_inst = module_inst ref Func.t 16 | and table_inst = Table.t 17 | and memory_inst = Memory.t 18 | and global_inst = Global.t 19 | and elem_inst = Elem.t 20 | and data_inst = Data.t 21 | and export_inst = Ast.name * extern 22 | 23 | and extern = 24 | | ExternFunc of func_inst 25 | | ExternTable of table_inst 26 | | ExternMemory of memory_inst 27 | | ExternGlobal of global_inst 28 | 29 | 30 | (* Reference types *) 31 | 32 | type Values.ref_ += FuncRef of func_inst 33 | 34 | let () = 35 | let type_of_ref' = !Values.type_of_ref' in 36 | Values.type_of_ref' := function 37 | | FuncRef _ -> FuncRefType 38 | | r -> type_of_ref' r 39 | 40 | let () = 41 | let string_of_ref' = !Values.string_of_ref' in 42 | Values.string_of_ref' := function 43 | | FuncRef _ -> "func" 44 | | r -> string_of_ref' r 45 | 46 | let () = 47 | let eq_ref' = !Values.eq_ref' in 48 | Values.eq_ref' := fun r1 r2 -> 49 | match r1, r2 with 50 | | FuncRef f1, FuncRef f2 -> f1 == f2 51 | | _, _ -> eq_ref' r1 r2 52 | 53 | 54 | (* Auxiliary functions *) 55 | 56 | let empty_module_inst = 57 | { types = []; funcs = []; tables = []; memories = []; globals = []; 58 | elems = []; datas = []; exports = [] } 59 | 60 | let extern_type_of = function 61 | | ExternFunc func -> ExternFuncType (Func.type_of func) 62 | | ExternTable tab -> ExternTableType (Table.type_of tab) 63 | | ExternMemory mem -> ExternMemoryType (Memory.type_of mem) 64 | | ExternGlobal glob -> ExternGlobalType (Global.type_of glob) 65 | 66 | let export inst name = 67 | try Some (List.assoc name inst.exports) with Not_found -> None 68 | -------------------------------------------------------------------------------- /interpreter/runtime/memory.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Values 3 | 4 | type memory 5 | type t = memory 6 | 7 | type size = int32 (* number of pages *) 8 | type address = int64 9 | type offset = int32 10 | type count = int32 11 | 12 | exception Type 13 | exception Bounds 14 | exception SizeOverflow 15 | exception SizeLimit 16 | exception OutOfMemory 17 | 18 | val page_size : int64 19 | 20 | val alloc : memory_type -> memory (* raises Type, SizeOverflow, OutOfMemory *) 21 | val type_of : memory -> memory_type 22 | val size : memory -> size 23 | val bound : memory -> address 24 | val grow : memory -> size -> unit 25 | (* raises SizeLimit, SizeOverflow, OutOfMemory *) 26 | 27 | val load_byte : memory -> address -> int (* raises Bounds *) 28 | val store_byte : memory -> address -> int -> unit (* raises Bounds *) 29 | val load_bytes : memory -> address -> int -> string (* raises Bounds *) 30 | val store_bytes : memory -> address -> string -> unit (* raises Bounds *) 31 | 32 | val load_num : 33 | memory -> address -> offset -> num_type -> num (* raises Bounds *) 34 | val store_num : 35 | memory -> address -> offset -> num -> unit (* raises Bounds *) 36 | val load_num_packed : 37 | pack_size -> extension -> memory -> address -> offset -> num_type -> num 38 | (* raises Type, Bounds *) 39 | val store_num_packed : 40 | pack_size -> memory -> address -> offset -> num -> unit 41 | (* raises Type, Bounds *) 42 | 43 | val load_vec : 44 | memory -> address -> offset -> vec_type -> vec (* raises Bounds *) 45 | val store_vec : 46 | memory -> address -> offset -> vec -> unit 47 | (* raises Type, Bounds *) 48 | val load_vec_packed : 49 | pack_size -> vec_extension -> memory -> address -> offset -> vec_type -> vec 50 | (* raises Type, Bounds *) 51 | -------------------------------------------------------------------------------- /interpreter/runtime/table.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Values 3 | 4 | type size = int32 5 | type index = int32 6 | type count = int32 7 | 8 | type table = {mutable ty : table_type; mutable content : ref_ array} 9 | type t = table 10 | 11 | exception Type 12 | exception Bounds 13 | exception SizeOverflow 14 | exception SizeLimit 15 | exception OutOfMemory 16 | 17 | let valid_limits {min; max} = 18 | match max with 19 | | None -> true 20 | | Some m -> I32.le_u min m 21 | 22 | let create size r = 23 | try Lib.Array32.make size r 24 | with Out_of_memory | Invalid_argument _ -> raise OutOfMemory 25 | 26 | let alloc (TableType (lim, _) as ty) r = 27 | if not (valid_limits lim) then raise Type; 28 | {ty; content = create lim.min r} 29 | 30 | let size tab = 31 | Lib.Array32.length tab.content 32 | 33 | let type_of tab = 34 | tab.ty 35 | 36 | let grow tab delta r = 37 | let TableType (lim, t) = tab.ty in 38 | assert (lim.min = size tab); 39 | let old_size = lim.min in 40 | let new_size = Int32.add old_size delta in 41 | if I32.gt_u old_size new_size then raise SizeOverflow else 42 | let lim' = {lim with min = new_size} in 43 | if not (valid_limits lim') then raise SizeLimit else 44 | let after = create new_size r in 45 | Array.blit tab.content 0 after 0 (Array.length tab.content); 46 | tab.ty <- TableType (lim', t); 47 | tab.content <- after 48 | 49 | let load tab i = 50 | if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; 51 | Lib.Array32.get tab.content i 52 | 53 | let store tab i r = 54 | let TableType (lim, t) = tab.ty in 55 | if type_of_ref r <> t then raise Type; 56 | if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; 57 | Lib.Array32.set tab.content i r 58 | 59 | let blit tab offset rs = 60 | let data = Array.of_list rs in 61 | let len = Lib.Array32.length data in 62 | if offset < 0l || offset > Int32.sub (Lib.Array32.length tab.content) len then raise Bounds; 63 | Lib.Array32.blit data 0l tab.content offset len 64 | -------------------------------------------------------------------------------- /interpreter/runtime/table.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Values 3 | 4 | type table 5 | type t = table 6 | 7 | type size = int32 8 | type index = int32 9 | type count = int32 10 | 11 | exception Type 12 | exception Bounds 13 | exception SizeOverflow 14 | exception SizeLimit 15 | exception OutOfMemory 16 | 17 | val alloc : table_type -> ref_ -> table (* raises Type, OutOfMemory *) 18 | val type_of : table -> table_type 19 | val size : table -> size 20 | val grow : table -> size -> ref_ -> unit 21 | (* raises SizeOverflow, SizeLimit, OutOfMemory *) 22 | 23 | val load : table -> index -> ref_ (* raises Bounds *) 24 | val store : table -> index -> ref_ -> unit (* raises Type, Bounds *) 25 | val blit : table -> index -> ref_ list -> unit (* raises Bounds *) 26 | -------------------------------------------------------------------------------- /interpreter/script/import.ml: -------------------------------------------------------------------------------- 1 | open Source 2 | open Ast 3 | 4 | module Unknown = Error.Make () 5 | exception Unknown = Unknown.Error (* indicates unknown import name *) 6 | 7 | module Registry = Map.Make(struct type t = Ast.name let compare = compare end) 8 | let registry = ref Registry.empty 9 | 10 | let register name lookup = registry := Registry.add name lookup !registry 11 | 12 | let lookup (m : module_) (im : import) : Instance.extern = 13 | let {module_name; item_name; idesc} = im.it in 14 | let t = import_type m im in 15 | try Registry.find module_name !registry item_name t with Not_found -> 16 | Unknown.error im.at 17 | ("unknown import \"" ^ string_of_name module_name ^ 18 | "\".\"" ^ string_of_name item_name ^ "\"") 19 | 20 | let link m = List.map (lookup m) m.it.imports 21 | -------------------------------------------------------------------------------- /interpreter/script/import.mli: -------------------------------------------------------------------------------- 1 | exception Unknown of Source.region * string 2 | 3 | val link : Ast.module_ -> Instance.extern list (* raises Unknown *) 4 | 5 | val register : 6 | Ast.name -> 7 | (Ast.name -> Types.extern_type -> Instance.extern (* raises Not_found *)) -> 8 | unit 9 | -------------------------------------------------------------------------------- /interpreter/script/js.mli: -------------------------------------------------------------------------------- 1 | val of_script : Script.script -> string 2 | -------------------------------------------------------------------------------- /interpreter/script/run.mli: -------------------------------------------------------------------------------- 1 | exception Abort of Source.region * string 2 | exception Assert of Source.region * string 3 | exception IO of Source.region * string 4 | 5 | val trace : string -> unit 6 | 7 | val run_string : string -> bool 8 | val run_file : string -> bool 9 | val run_stdin : unit -> unit 10 | -------------------------------------------------------------------------------- /interpreter/script/script.ml: -------------------------------------------------------------------------------- 1 | type var = string Source.phrase 2 | 3 | type Values.ref_ += ExternRef of int32 4 | type num = Values.num Source.phrase 5 | type ref_ = Values.ref_ Source.phrase 6 | type literal = Values.value Source.phrase 7 | 8 | type definition = definition' Source.phrase 9 | and definition' = 10 | | Textual of Ast.module_ 11 | | Encoded of string * string 12 | | Quoted of string * string 13 | 14 | type action = action' Source.phrase 15 | and action' = 16 | | Invoke of var option * Ast.name * literal list 17 | | Get of var option * Ast.name 18 | 19 | type nanop = nanop' Source.phrase 20 | and nanop' = (Lib.void, Lib.void, nan, nan) Values.op 21 | and nan = CanonicalNan | ArithmeticNan 22 | 23 | type num_pat = 24 | | NumPat of num 25 | | NanPat of nanop 26 | 27 | type vec_pat = 28 | | VecPat of (V128.shape * num_pat list) Values.vecop 29 | 30 | type ref_pat = 31 | | RefPat of ref_ 32 | | RefTypePat of Types.ref_type 33 | 34 | type result = result' Source.phrase 35 | and result' = 36 | | NumResult of num_pat 37 | | VecResult of vec_pat 38 | | RefResult of ref_pat 39 | 40 | type assertion = assertion' Source.phrase 41 | and assertion' = 42 | | AssertMalformed of definition * string 43 | | AssertInvalid of definition * string 44 | | AssertUnlinkable of definition * string 45 | | AssertUninstantiable of definition * string 46 | | AssertReturn of action * result list 47 | | AssertTrap of action * string 48 | | AssertExhaustion of action * string 49 | 50 | type command = command' Source.phrase 51 | and command' = 52 | | Module of var option * definition 53 | | Register of Ast.name * var option 54 | | Action of action 55 | | Assertion of assertion 56 | | Meta of meta 57 | 58 | and meta = meta' Source.phrase 59 | and meta' = 60 | | Input of var option * string 61 | | Output of var option * string option 62 | | Script of var option * script 63 | 64 | and script = command list 65 | 66 | 67 | let () = 68 | let type_of_ref' = !Values.type_of_ref' in 69 | Values.type_of_ref' := function 70 | | ExternRef _ -> Types.ExternRefType 71 | | r -> type_of_ref' r 72 | 73 | let () = 74 | let string_of_ref' = !Values.string_of_ref' in 75 | Values.string_of_ref' := function 76 | | ExternRef n -> "ref " ^ Int32.to_string n 77 | | r -> string_of_ref' r 78 | 79 | let () = 80 | let eq_ref' = !Values.eq_ref' in 81 | Values.eq_ref' := fun r1 r2 -> 82 | match r1, r2 with 83 | | ExternRef n1, ExternRef n2 -> n1 = n2 84 | | _, _ -> eq_ref' r1 r2 85 | -------------------------------------------------------------------------------- /interpreter/syntax/free.mli: -------------------------------------------------------------------------------- 1 | module Set : Set.S with type elt = int32 2 | 3 | type t = 4 | { 5 | types : Set.t; 6 | globals : Set.t; 7 | tables : Set.t; 8 | memories : Set.t; 9 | funcs : Set.t; 10 | elems : Set.t; 11 | datas : Set.t; 12 | locals : Set.t; 13 | labels : Set.t; 14 | } 15 | 16 | val empty : t 17 | val union : t -> t -> t 18 | 19 | val instr : Ast.instr -> t 20 | val block : Ast.instr list -> t 21 | val const : Ast.const -> t 22 | 23 | val type_ : Ast.type_ -> t 24 | val global : Ast.global -> t 25 | val func : Ast.func -> t 26 | val table : Ast.table -> t 27 | val memory : Ast.memory -> t 28 | val elem : Ast.elem_segment -> t 29 | val data : Ast.data_segment -> t 30 | val export : Ast.export -> t 31 | val import : Ast.import -> t 32 | val start : Ast.start -> t 33 | 34 | val module_ : Ast.module_ -> t 35 | 36 | val list : ('a -> t) -> 'a list -> t 37 | -------------------------------------------------------------------------------- /interpreter/text/arrange.mli: -------------------------------------------------------------------------------- 1 | open Sexpr 2 | 3 | val instr : Ast.instr -> sexpr 4 | val func : Ast.func -> sexpr 5 | val module_ : Ast.module_ -> sexpr 6 | val script : [`Textual | `Binary] -> Script.script -> sexpr list 7 | -------------------------------------------------------------------------------- /interpreter/text/lexer.mli: -------------------------------------------------------------------------------- 1 | val convert_pos : Lexing.position -> Source.pos 2 | 3 | val token : Lexing.lexbuf -> Parser.token (* raises Source.Error *) 4 | -------------------------------------------------------------------------------- /interpreter/text/parse.ml: -------------------------------------------------------------------------------- 1 | exception Syntax = Parse_error.Syntax 2 | 3 | module type S = 4 | sig 5 | type t 6 | val parse : string -> Lexing.lexbuf -> t 7 | val parse_file : string -> t 8 | val parse_string : string -> t 9 | val parse_channel : in_channel -> t 10 | end 11 | 12 | let convert_pos lexbuf = 13 | { Source.left = Lexer.convert_pos lexbuf.Lexing.lex_start_p; 14 | Source.right = Lexer.convert_pos lexbuf.Lexing.lex_curr_p 15 | } 16 | 17 | let make (type a) (start : _ -> _ -> a) : (module S with type t = a) = 18 | (module struct 19 | type t = a 20 | 21 | let parse name lexbuf = 22 | Lexing.set_filename lexbuf name; 23 | try start Lexer.token lexbuf with Parser.Error -> 24 | raise (Syntax (convert_pos lexbuf, "unexpected token")) 25 | 26 | let parse_string s = 27 | parse "string" (Lexing.from_string ~with_positions:true s) 28 | 29 | let parse_channel oc = 30 | parse "channel" (Lexing.from_channel ~with_positions:true oc) 31 | 32 | let parse_file name = 33 | let oc = open_in name in 34 | Fun.protect ~finally:(fun () -> close_in oc) (fun () -> 35 | parse name (Lexing.from_channel ~with_positions:true oc) 36 | ) 37 | end) 38 | 39 | module Module = (val make Parser.module1) 40 | module Script = (val make Parser.script) 41 | module Script1 = (val make Parser.script1) 42 | -------------------------------------------------------------------------------- /interpreter/text/parse.mli: -------------------------------------------------------------------------------- 1 | exception Syntax of Source.region * string 2 | 3 | module type S = 4 | sig 5 | type t 6 | val parse : string -> Lexing.lexbuf -> t 7 | val parse_file : string -> t 8 | val parse_string : string -> t 9 | val parse_channel : in_channel -> t 10 | end 11 | 12 | module Module : S with type t = Script.var option * Script.definition 13 | module Script1 : S with type t = Script.script 14 | module Script : S with type t = Script.script 15 | -------------------------------------------------------------------------------- /interpreter/text/parse_error.ml: -------------------------------------------------------------------------------- 1 | (* This is here since both Lexer, Parser, and Parse need it, 2 | * but menhir cannot create a Parser that exports it. *) 3 | exception Syntax of Source.region * string 4 | -------------------------------------------------------------------------------- /interpreter/text/print.ml: -------------------------------------------------------------------------------- 1 | let instr oc width e = Sexpr.output oc width (Arrange.instr e) 2 | let func oc width f = Sexpr.output oc width (Arrange.func f) 3 | let module_ oc width m = Sexpr.output oc width (Arrange.module_ m) 4 | let script oc width mode s = 5 | List.iter (Sexpr.output oc width) (Arrange.script mode s) 6 | -------------------------------------------------------------------------------- /interpreter/text/print.mli: -------------------------------------------------------------------------------- 1 | val instr : out_channel -> int -> Ast.instr -> unit 2 | val func : out_channel -> int -> Ast.func -> unit 3 | val module_ : out_channel -> int -> Ast.module_ -> unit 4 | val script : out_channel -> int -> [`Textual | `Binary] -> Script.script -> unit 5 | -------------------------------------------------------------------------------- /interpreter/util/error.ml: -------------------------------------------------------------------------------- 1 | module Make () = 2 | struct 3 | exception Error of Source.region * string 4 | 5 | let warn at m = prerr_endline (Source.string_of_region at ^ ": warning: " ^ m) 6 | let error at m = raise (Error (at, m)) 7 | end 8 | 9 | -------------------------------------------------------------------------------- /interpreter/util/error.mli: -------------------------------------------------------------------------------- 1 | module Make () : 2 | sig 3 | exception Error of Source.region * string 4 | 5 | val warn : Source.region -> string -> unit 6 | val error : Source.region -> string -> 'a (* raises Error *) 7 | end 8 | 9 | -------------------------------------------------------------------------------- /interpreter/util/sexpr.ml: -------------------------------------------------------------------------------- 1 | type sexpr = Atom of string | Node of string * sexpr list 2 | 3 | type rope = Leaf of string | Concat of rope list 4 | let (^+) s r = Concat [Leaf s; r] 5 | let (+^) r s = Concat [r; Leaf s] 6 | 7 | let rec iter f = function 8 | | Leaf s -> f s 9 | | Concat rs -> List.iter (iter f) rs 10 | 11 | let rec concat = function 12 | | Leaf s -> s 13 | | Concat rs -> String.concat "" (List.map concat rs) 14 | 15 | let rec pp off width = function 16 | | Atom s -> String.length s, Leaf s 17 | | Node (s, xs) -> 18 | let lens, rs = List.split (List.map (pp (off + 2) width) xs) in 19 | let len = String.length s + List.length rs + List.fold_left (+) 2 lens in 20 | let sep, fin = 21 | if off + len <= width then " ", "" 22 | else let indent = String.make off ' ' in "\n " ^ indent, "\n" ^ indent 23 | in len, "(" ^+ s ^+ Concat (List.map (fun r -> sep ^+ r) rs) +^ fin +^ ")" 24 | 25 | let output oc width x = 26 | iter (output_string oc) (snd (pp 0 width x)); 27 | output_string oc "\n"; 28 | flush oc 29 | 30 | let print = output stdout 31 | 32 | let to_string width x = concat (snd (pp 0 width x)) ^ "\n" 33 | -------------------------------------------------------------------------------- /interpreter/util/sexpr.mli: -------------------------------------------------------------------------------- 1 | type sexpr = Atom of string | Node of string * sexpr list 2 | 3 | val output : out_channel -> int -> sexpr -> unit 4 | val print : int -> sexpr -> unit 5 | val to_string : int -> sexpr -> string 6 | -------------------------------------------------------------------------------- /interpreter/util/source.ml: -------------------------------------------------------------------------------- 1 | type pos = {file : string; line : int; column : int} 2 | type region = {left : pos; right : pos} 3 | type 'a phrase = {at : region; it : 'a} 4 | 5 | let (@@) x region = {it = x; at = region} 6 | let at region x = x @@ region 7 | 8 | 9 | (* Positions and regions *) 10 | 11 | let no_pos = {file = ""; line = 0; column = 0} 12 | let no_region = {left = no_pos; right = no_pos} 13 | 14 | let string_of_pos pos = 15 | if pos.line = -1 then 16 | Printf.sprintf "0x%x" pos.column 17 | else 18 | string_of_int pos.line ^ "." ^ string_of_int (pos.column + 1) 19 | 20 | let string_of_region r = 21 | r.left.file ^ ":" ^ string_of_pos r.left ^ 22 | (if r.right = r.left then "" else "-" ^ string_of_pos r.right) 23 | -------------------------------------------------------------------------------- /interpreter/util/source.mli: -------------------------------------------------------------------------------- 1 | type pos = {file : string; line : int; column : int} 2 | type region = {left : pos; right : pos} 3 | type 'a phrase = {at : region; it : 'a} 4 | 5 | val no_pos : pos 6 | val no_region : region 7 | 8 | val string_of_pos : pos -> string 9 | val string_of_region : region -> string 10 | 11 | val (@@) : 'a -> region -> 'a phrase 12 | val at : region -> 'a -> 'a phrase 13 | -------------------------------------------------------------------------------- /interpreter/valid/valid.mli: -------------------------------------------------------------------------------- 1 | exception Invalid of Source.region * string 2 | 3 | val check_module : Ast.module_ -> unit (* raises Invalid *) 4 | -------------------------------------------------------------------------------- /interpreter/wasm.opam: -------------------------------------------------------------------------------- 1 | # This file is generated by dune, edit dune-project instead 2 | opam-version: "2.0" 3 | synopsis: 4 | "Library to read and write WebAssembly (Wasm) files and manipulate their AST" 5 | maintainer: ["Andreas Rossberg = "2.9"} 13 | "ocaml" {>= "4.12"} 14 | "menhir" {>= "20220210"} 15 | "odoc" {with-doc} 16 | ] 17 | build: [ 18 | ["dune" "subst"] {dev} 19 | [ 20 | "dune" 21 | "build" 22 | "-p" 23 | name 24 | "-j" 25 | jobs 26 | "--promote-install-files=false" 27 | "@install" 28 | "@runtest" {with-test} 29 | "@doc" {with-doc} 30 | ] 31 | ["dune" "install" "-p" name "--create-install-files" name] 32 | ] 33 | dev-repo: "git+https://github.com/WebAssembly/spec.git" 34 | -------------------------------------------------------------------------------- /papers/LICENSE: -------------------------------------------------------------------------------- 1 | This work is licensed under the Creative Commons Attribution 4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. 2 | -------------------------------------------------------------------------------- /papers/README.md: -------------------------------------------------------------------------------- 1 | * [Bringing the Web up to Speed with WebAssembly](pldi2017.pdf) 2 | 3 | Andreas Haas, Andreas Rossberg, Derek Schuff, Ben Titzer, Dan Gohman, Luke Wagner, Alon Zakai, JF Bastien, Michael Holman 4 | 5 | ACM-SIGPLAN Conference on Programming Language Design and Implementation (PLDI 2017) 6 | 7 | *Describes the WebAssembly design, its formalisation, and initial implementations.* 8 | 9 | * [Weakening WebAssembly](oopsla2019.pdf) 10 | 11 | Conrad Watt, Andreas Rossberg, Jean Pichon-Pharabod 12 | 13 | ACM-SIGPLAN Conference on Object-Oriented Programming, Systems, Language and Architectures (OOSPLA 2019) 14 | 15 | *Describes and formalises the extension of WebAssembly with threads and a suitable memory model.* 16 | -------------------------------------------------------------------------------- /papers/oopsla2019.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssembly/multi-memory/cf8b5aa27257311b8eac80ae83f4ba22ee308064/papers/oopsla2019.pdf -------------------------------------------------------------------------------- /papers/pldi2017.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssembly/multi-memory/cf8b5aa27257311b8eac80ae83f4ba22ee308064/papers/pldi2017.pdf -------------------------------------------------------------------------------- /proposals/README.md: -------------------------------------------------------------------------------- 1 | # Proposals 2 | 3 | This directory contains overviews for post-MVP proposals that have been finished and merged into the spec. 4 | Proposals that are not yet finished can be found at https://github.com/WebAssembly/proposals. 5 | 6 | **Note:** The design documents in this folder are archived here for historical purposes and are no longer actively maintained. 7 | Consequently, they may be outdated, contain unfixed errors, or provide insufficient context. 8 | -------------------------------------------------------------------------------- /proposals/sign-extension-ops/Overview.md: -------------------------------------------------------------------------------- 1 | # Sign-extension operators proposal for WebAssembly 2 | 3 | This page describes a proposal for the post-MVP 4 | [sign-extension operator feature][future sext]. 5 | 6 | This proposal adds five new integer instructions for sign-extending 8-bit, 7 | 16-bit, and 32-bit values. 8 | 9 | ## New Sign-extending Operators 10 | 11 | To support sign-extending, five new sign-extension operators are added: 12 | 13 | * `i32.extend8_s`: extend a signed 8-bit integer to a 32-bit integer 14 | * `i32.extend16_s`: extend a signed 16-bit integer to a 32-bit integer 15 | * `i64.extend8_s`: extend a signed 8-bit integer to a 64-bit integer 16 | * `i64.extend16_s`: extend a signed 16-bit integer to a 64-bit integer 17 | * `i64.extend32_s`: extend a signed 32-bit integer to a 64-bit integer 18 | 19 | Note that `i64.extend32_s` was not originally included when this proposal was 20 | discussed in the May 2017 CG meeting. The reason given was that 21 | the behavior matches `i64.extend_s/i32`. It was later discovered that this is 22 | not correct, as `i64.extend_s/i32` sign-extends an `i32` value to `i64`, 23 | whereas `i64.extend32_s` sign-extends an `i64` value to `i64`. The behavior 24 | of `i64.extend32_s` can be emulated with `i32.wrap/i64` followed by 25 | `i64.extend_s/i32`, but the same can be said of the sign-extending load 26 | operations. Therefore, `i64.extend32_s` has been added for consistency. 27 | 28 | ## [Spec Changes][spec] 29 | 30 | The [instruction syntax][] is modified as follows: 31 | 32 | ``` 33 | instr ::= ... | 34 | inn.extend8_s | inn.extend16_s | i64.extend32_s 35 | ``` 36 | 37 | The [instruction binary format][] is modified as follows: 38 | 39 | ``` 40 | instr ::= ... 41 | | 0xC0 => i32.extend8_s 42 | | 0xC1 => i32.extend16_s 43 | | 0xC2 => i64.extend8_s 44 | | 0xC3 => i64.extend16_s 45 | | 0xC4 => i64.extend32_s 46 | ``` 47 | 48 | [future sext]: https://github.com/WebAssembly/design/blob/main/FutureFeatures.md#additional-integer-operators 49 | [instruction syntax]: https://webassembly.github.io/spec/syntax/instructions.html 50 | [instruction binary format]: https://webassembly.github.io/spec/binary/instructions.html 51 | [spec]: https://webassembly.github.io/sign-extension-ops/ 52 | -------------------------------------------------------------------------------- /proposals/simd/TextSIMD.md: -------------------------------------------------------------------------------- 1 | # Text format for SIMD 2 | 3 | ### v128.const 4 | 5 | The `v128.const` instruction has multiple valid text formats corresponding to 6 | different lane interpretations. The valid text formats are 7 | 8 | ``` 9 | v128.const i8x16 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 i8 10 | v128.const i16x8 i16 i16 i16 i16 i16 i16 i16 i16 11 | v128.const i32x4 i32 i32 i32 i32 12 | v128.const i64x2 i64 i64 13 | v128.const f32x4 f32 f32 f32 f32 14 | v128.const f64x2 f64 f64 15 | ``` 16 | 17 | The canonical text format used for printing `v128.const` instructions is 18 | 19 | ``` 20 | v128.const i32x4 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN 0xNNNNNNNN 21 | ``` 22 | 23 | ### i8x16.shuffle 24 | 25 | ``` 26 | i8x16.shuffle i5 i5 i5 i5 i5 i5 i5 i5 i5 i5 i5 i5 i5 i5 i5 i5 27 | ``` 28 | -------------------------------------------------------------------------------- /proposals/simd/WebAssembly-SIMD-May-2017.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssembly/multi-memory/cf8b5aa27257311b8eac80ae83f4ba22ee308064/proposals/simd/WebAssembly-SIMD-May-2017.pdf -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | This directory contains the WebAssembly test suite. It is split into three 2 | directories: 3 | 4 | * [`core/`](core/), tests for the core semantics 5 | * [`js-api/`](js-api/), tests for the JavaScript API. 6 | * [`html/`](html/), tests for the JavaScript API in a DOM environment. 7 | 8 | A list of to-do's can be found [here](Todo.md). 9 | 10 | ## Multi-stage testing 11 | 12 | The wast tests can be converted to JavaScript, and the JavaScript tests 13 | to HTML tests, using the `build.py` script. It will create a `out/` directory 14 | (checked in in this repository, to be able to use it from github pages), 15 | containing subdirectories with expanded tests, as well as a landing page for 16 | runnning all of them in HTML. 17 | 18 | The HTML tests are just [Web Platform Tests](http://testthewebforward.org) 19 | using the 20 | [testharness.js](https://web-platform-tests.org/writing-tests/testharness-api.html) 21 | library. 22 | 23 | Each wast test gets its equivalent JS test, and each JS test (including wast 24 | test) gets its equivalent WPT, to be easily run in browser vendors' automation. 25 | 26 | ## Procedure for adding a new test 27 | 28 | - put the test in the right directory according to the above (top) description. 29 | - ideally, commit here so the actual content commit and build commit are 30 | separated. 31 | - re-run `build.py` so that the landing page is updated and all the cascading 32 | happens. 33 | - re-commit here, if necessary. 34 | 35 | ## Local HTTP serving of the repository 36 | 37 | From the root of your clone of this repository: 38 | 39 | ``` 40 | python -m SimpleHTTPServer 8000 41 | ``` 42 | 43 | Then open your favorite browser and browse to `http://localhost:8000/test/out`. 44 | -------------------------------------------------------------------------------- /test/Todo.md: -------------------------------------------------------------------------------- 1 | This is a rough list of "tests to write". Everything here should either be 2 | specified in [Semantics.md](https://github.com/WebAssembly/design/blob/main/Semantics.md), 3 | have a link to an open issue/PR, or be obvious. Comments/corrections/additions 4 | welcome. 5 | 6 | Linear memory semantics: 7 | - test that one can clobber the entire contents of the linear memory without corrupting: call stack, local variables, program execution. 8 | 9 | Misc optimizer bait: 10 | - test that the scheduler doesn't move a trapping div past a call which may not return 11 | - test that linearized multidimensional array accesses can have overindexing in interesting ways 12 | - test that 32-bit loop induction variables that wrap aren't promoted to 64-bit 13 | - test that code after a non-obviously infinite loop is not executed 14 | 15 | Misc x86 optimizer bait: 16 | - test that oeq handles NaN right in if, if-else, and setcc cases 17 | 18 | SIMD (post-MVP): 19 | - test that SIMD insert/extract don't canonicalize NaNs 20 | - test that SIMD lanes are in little-endian order 21 | - test non-constant-index and out-of-bounds shuffle masks 22 | - test that subnormals work as intended 23 | - test that byte-misaligned accesses work 24 | 25 | Threads (post-MVP): 26 | - test that thread-local variables are actually thread-local 27 | - test that atomic operations that isLockFree says are lock-free actually are 28 | (is this possible?) 29 | - test that isLockFree is true for datatypes that the spec says should 30 | always be lock-free 31 | - test that 16-bit and 8-bit cmpxchg does a wrapped 8-bit or 16-bit compare 32 | 33 | FMA (post-MVP): 34 | - http://www.vinc17.org/software/fma-tests.c 35 | -------------------------------------------------------------------------------- /test/core/.gitignore: -------------------------------------------------------------------------------- 1 | output -------------------------------------------------------------------------------- /test/core/README.md: -------------------------------------------------------------------------------- 1 | This directory contains tests for the core WebAssembly semantics, as described in [Semantics.md](https://github.com/WebAssembly/design/blob/main/Semantics.md) and specified by the [spec interpreter](https://github.com/WebAssembly/spec/blob/main/interpreter). 2 | 3 | Tests are written in the [S-Expression script format](https://github.com/WebAssembly/spec/blob/main/interpreter/README.md#s-expression-syntax) defined by the interpreter. 4 | 5 | The test suite can be run with the spec interpreter as follows: 6 | ``` 7 | ./run.py --wasm 8 | ``` 9 | where the path points to the spec interpreter executable (or a tool that understands similar options). If the binary is in the working directory, this option can be omitted. 10 | 11 | In addition, the option `--js ` can be given to point to a stand-alone JavaScript interpreter supporting the WebAssembly API. If provided, all tests are also executed in JavaScript. 12 | -------------------------------------------------------------------------------- /test/core/comments.wast: -------------------------------------------------------------------------------- 1 | ;; Test comment syntax 2 | 3 | ;;comment 4 | 5 | ;;;;;;;;;;; 6 | 7 | ;;comment 8 | 9 | ( ;;comment 10 | module;;comment 11 | );;comment 12 | 13 | ;;) 14 | ;;;) 15 | ;; ;) 16 | ;; (; 17 | 18 | (;;) 19 | 20 | (;comment;) 21 | 22 | (;;comment;) 23 | 24 | (;;;comment;) 25 | 26 | (;;;;;;;;;;;;;;) 27 | 28 | (;(((((((((( ;) 29 | 30 | (;)))))))))));) 31 | 32 | (;comment";) 33 | 34 | (;comment"";) 35 | 36 | (;comment""";) 37 | 38 | ;; ASCII 00-1F, 7F 39 | (; 40 | 41 | ;) 42 | 43 | ;; null-byte followed immediately by end-of-comment delimiter 44 | (;;) 45 | 46 | 47 | (;Heiße Würstchen;) 48 | 49 | (;;) 50 | 51 | (;comment 52 | comment;) 53 | 54 | (;comment;) 55 | 56 | (;comment;)((;comment;) 57 | (;comment;)module(;comment;) 58 | (;comment;))(;comment;) 59 | 60 | (;comment(;nested;)comment;) 61 | 62 | (;comment 63 | (;nested 64 | ;)comment 65 | ;) 66 | 67 | (module 68 | (;comment(;nested(;further;)nested;)comment;) 69 | ) 70 | 71 | (;comment;;comment;) 72 | 73 | (;comment;;comment 74 | ;) 75 | 76 | (module 77 | (;comment;;comment(;nested;)comment;) 78 | ) 79 | 80 | 81 | ;; Newline recognition 82 | 83 | (module quote 84 | "(func (export \"f1\") (result i32)" 85 | " (i32.const 1)" 86 | " ;; comment\0a" 87 | " (return (i32.const 2))" 88 | "\0a" 89 | ")" 90 | "(func (export \"f2\") (result i32)" 91 | " (i32.const 1)" 92 | " ;; comment\0d" 93 | " (return (i32.const 2))" 94 | "\0a" 95 | ")" 96 | "(func (export \"f3\") (result i32)" 97 | " (i32.const 1)" 98 | " ;; comment\0d\0a" 99 | " (return (i32.const 2))" 100 | "\0a" 101 | ")" 102 | ) 103 | 104 | (assert_return (invoke "f1") (i32.const 2)) 105 | (assert_return (invoke "f2") (i32.const 2)) 106 | (assert_return (invoke "f3") (i32.const 2)) 107 | -------------------------------------------------------------------------------- /test/core/forward.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func $even (export "even") (param $n i32) (result i32) 3 | (if (result i32) (i32.eq (local.get $n) (i32.const 0)) 4 | (then (i32.const 1)) 5 | (else (call $odd (i32.sub (local.get $n) (i32.const 1)))) 6 | ) 7 | ) 8 | 9 | (func $odd (export "odd") (param $n i32) (result i32) 10 | (if (result i32) (i32.eq (local.get $n) (i32.const 0)) 11 | (then (i32.const 0)) 12 | (else (call $even (i32.sub (local.get $n) (i32.const 1)))) 13 | ) 14 | ) 15 | ) 16 | 17 | (assert_return (invoke "even" (i32.const 13)) (i32.const 0)) 18 | (assert_return (invoke "even" (i32.const 20)) (i32.const 1)) 19 | (assert_return (invoke "odd" (i32.const 13)) (i32.const 1)) 20 | (assert_return (invoke "odd" (i32.const 20)) (i32.const 0)) 21 | -------------------------------------------------------------------------------- /test/core/inline-module.wast: -------------------------------------------------------------------------------- 1 | (func) (memory 0) (func (export "f")) 2 | -------------------------------------------------------------------------------- /test/core/memory-multi.wast: -------------------------------------------------------------------------------- 1 | ;; From wasmtime misc_testsuite/multi-memory/simple.wast 2 | 3 | ;; Should be replaced with suitable extensions to ../meta/generate_memory_*.js 4 | 5 | (module 6 | (memory $mem1 1) 7 | (memory $mem2 1) 8 | 9 | (func (export "init1") (result i32) 10 | (memory.init $mem1 $d (i32.const 1) (i32.const 0) (i32.const 4)) 11 | (i32.load $mem1 (i32.const 1)) 12 | ) 13 | 14 | (func (export "init2") (result i32) 15 | (memory.init $mem2 $d (i32.const 1) (i32.const 4) (i32.const 4)) 16 | (i32.load $mem2 (i32.const 1)) 17 | ) 18 | 19 | (data $d "\01\00\00\00" "\02\00\00\00") 20 | ) 21 | 22 | (assert_return (invoke "init1") (i32.const 1)) 23 | (assert_return (invoke "init2") (i32.const 2)) 24 | 25 | 26 | (module 27 | (memory $mem1 1) 28 | (memory $mem2 1) 29 | 30 | (func (export "fill1") (result i32) 31 | (memory.fill $mem1 (i32.const 1) (i32.const 0x01) (i32.const 4)) 32 | (i32.load $mem1 (i32.const 1)) 33 | ) 34 | 35 | (func (export "fill2") (result i32) 36 | (memory.fill $mem2 (i32.const 1) (i32.const 0x02) (i32.const 2)) 37 | (i32.load $mem2 (i32.const 1)) 38 | ) 39 | ) 40 | 41 | (assert_return (invoke "fill1") (i32.const 0x01010101)) 42 | (assert_return (invoke "fill2") (i32.const 0x0202)) 43 | -------------------------------------------------------------------------------- /test/core/memory_redundancy.wast: -------------------------------------------------------------------------------- 1 | ;; Test that optimizers don't do redundant-load, store-to-load, or dead-store 2 | ;; optimizations when there are interfering stores, even of different types 3 | ;; and to non-identical addresses. 4 | 5 | (module 6 | (memory 1 1) 7 | 8 | (func (export "zero_everything") 9 | (i32.store (i32.const 0) (i32.const 0)) 10 | (i32.store (i32.const 4) (i32.const 0)) 11 | (i32.store (i32.const 8) (i32.const 0)) 12 | (i32.store (i32.const 12) (i32.const 0)) 13 | ) 14 | 15 | (func (export "test_store_to_load") (result i32) 16 | (i32.store (i32.const 8) (i32.const 0)) 17 | (f32.store (i32.const 5) (f32.const -0.0)) 18 | (i32.load (i32.const 8)) 19 | ) 20 | 21 | (func (export "test_redundant_load") (result i32) 22 | (local $t i32) 23 | (local $s i32) 24 | (local.set $t (i32.load (i32.const 8))) 25 | (i32.store (i32.const 5) (i32.const 0x80000000)) 26 | (local.set $s (i32.load (i32.const 8))) 27 | (i32.add (local.get $t) (local.get $s)) 28 | ) 29 | 30 | (func (export "test_dead_store") (result f32) 31 | (local $t f32) 32 | (i32.store (i32.const 8) (i32.const 0x23232323)) 33 | (local.set $t (f32.load (i32.const 11))) 34 | (i32.store (i32.const 8) (i32.const 0)) 35 | (local.get $t) 36 | ) 37 | 38 | ;; A function named "malloc" which implementations nonetheless shouldn't 39 | ;; assume behaves like C malloc. 40 | (func $malloc (export "malloc") 41 | (param $size i32) 42 | (result i32) 43 | (i32.const 16) 44 | ) 45 | 46 | ;; Call malloc twice, but unlike C malloc, we don't get non-aliasing pointers. 47 | (func (export "malloc_aliasing") 48 | (result i32) 49 | (local $x i32) 50 | (local $y i32) 51 | (local.set $x (call $malloc (i32.const 4))) 52 | (local.set $y (call $malloc (i32.const 4))) 53 | (i32.store (local.get $x) (i32.const 42)) 54 | (i32.store (local.get $y) (i32.const 43)) 55 | (i32.load (local.get $x)) 56 | ) 57 | ) 58 | 59 | (assert_return (invoke "test_store_to_load") (i32.const 0x00000080)) 60 | (invoke "zero_everything") 61 | (assert_return (invoke "test_redundant_load") (i32.const 0x00000080)) 62 | (invoke "zero_everything") 63 | (assert_return (invoke "test_dead_store") (f32.const 0x1.18p-144)) 64 | (invoke "zero_everything") 65 | (assert_return (invoke "malloc_aliasing") (i32.const 43)) 66 | -------------------------------------------------------------------------------- /test/core/multi-memory/align0.wast: -------------------------------------------------------------------------------- 1 | ;; Test aligned and unaligned read/write 2 | 3 | (module 4 | (memory $mem0 0) 5 | (memory $mem1 1) 6 | (memory $mem2 0) 7 | 8 | ;; $default: natural alignment, $1: align=1, $2: align=2, $4: align=4, $8: align=8 9 | 10 | (func (export "f32_align_switch") (param i32) (result f32) 11 | (local f32 f32) 12 | (local.set 1 (f32.const 10.0)) 13 | (block $4 14 | (block $2 15 | (block $1 16 | (block $default 17 | (block $0 18 | (br_table $0 $default $1 $2 $4 (local.get 0)) 19 | ) ;; 0 20 | (f32.store $mem1 (i32.const 0) (local.get 1)) 21 | (local.set 2 (f32.load $mem1 (i32.const 0))) 22 | (br $4) 23 | ) ;; default 24 | (f32.store $mem1 align=1 (i32.const 0) (local.get 1)) 25 | (local.set 2 (f32.load $mem1 align=1 (i32.const 0))) 26 | (br $4) 27 | ) ;; 1 28 | (f32.store $mem1 align=2 (i32.const 0) (local.get 1)) 29 | (local.set 2 (f32.load $mem1 align=2 (i32.const 0))) 30 | (br $4) 31 | ) ;; 2 32 | (f32.store $mem1 align=4 (i32.const 0) (local.get 1)) 33 | (local.set 2 (f32.load $mem1 align=4 (i32.const 0))) 34 | ) ;; 4 35 | (local.get 2) 36 | ) 37 | ) 38 | 39 | (assert_return (invoke "f32_align_switch" (i32.const 0)) (f32.const 10.0)) 40 | (assert_return (invoke "f32_align_switch" (i32.const 1)) (f32.const 10.0)) 41 | (assert_return (invoke "f32_align_switch" (i32.const 2)) (f32.const 10.0)) 42 | (assert_return (invoke "f32_align_switch" (i32.const 3)) (f32.const 10.0)) 43 | 44 | -------------------------------------------------------------------------------- /test/core/multi-memory/data0.wast: -------------------------------------------------------------------------------- 1 | ;; Test the data section 2 | 3 | ;; Syntax 4 | 5 | (module 6 | (memory $mem0 1) 7 | (memory $mem1 1) 8 | (memory $mem2 1) 9 | 10 | (data (i32.const 0)) 11 | (data (i32.const 1) "a" "" "bcd") 12 | (data (offset (i32.const 0))) 13 | (data (offset (i32.const 0)) "" "a" "bc" "") 14 | (data (memory 0) (i32.const 0)) 15 | (data (memory 0x0) (i32.const 1) "a" "" "bcd") 16 | (data (memory 0x000) (offset (i32.const 0))) 17 | (data (memory 0) (offset (i32.const 0)) "" "a" "bc" "") 18 | (data (memory $mem0) (i32.const 0)) 19 | (data (memory $mem1) (i32.const 1) "a" "" "bcd") 20 | (data (memory $mem2) (offset (i32.const 0))) 21 | (data (memory $mem0) (offset (i32.const 0)) "" "a" "bc" "") 22 | 23 | (data $d1 (i32.const 0)) 24 | (data $d2 (i32.const 1) "a" "" "bcd") 25 | (data $d3 (offset (i32.const 0))) 26 | (data $d4 (offset (i32.const 0)) "" "a" "bc" "") 27 | (data $d5 (memory 0) (i32.const 0)) 28 | (data $d6 (memory 0x0) (i32.const 1) "a" "" "bcd") 29 | (data $d7 (memory 0x000) (offset (i32.const 0))) 30 | (data $d8 (memory 0) (offset (i32.const 0)) "" "a" "bc" "") 31 | (data $d9 (memory $mem0) (i32.const 0)) 32 | (data $d10 (memory $mem1) (i32.const 1) "a" "" "bcd") 33 | (data $d11 (memory $mem2) (offset (i32.const 0))) 34 | (data $d12 (memory $mem0) (offset (i32.const 0)) "" "a" "bc" "") 35 | ) 36 | 37 | ;; Basic use 38 | 39 | (module 40 | (memory 1) 41 | (data (i32.const 0) "a") 42 | ) 43 | (module 44 | (import "spectest" "memory" (memory 1)) 45 | (import "spectest" "memory" (memory 1)) 46 | (import "spectest" "memory" (memory 1)) 47 | (data (memory 0) (i32.const 0) "a") 48 | (data (memory 1) (i32.const 0) "a") 49 | (data (memory 2) (i32.const 0) "a") 50 | ) 51 | 52 | (module 53 | (global (import "spectest" "global_i32") i32) 54 | (memory 1) 55 | (data (global.get 0) "a") 56 | ) 57 | (module 58 | (global (import "spectest" "global_i32") i32) 59 | (import "spectest" "memory" (memory 1)) 60 | (data (global.get 0) "a") 61 | ) 62 | 63 | (module 64 | (global $g (import "spectest" "global_i32") i32) 65 | (memory 1) 66 | (data (global.get $g) "a") 67 | ) 68 | (module 69 | (global $g (import "spectest" "global_i32") i32) 70 | (import "spectest" "memory" (memory 1)) 71 | (data (global.get $g) "a") 72 | ) 73 | 74 | -------------------------------------------------------------------------------- /test/core/multi-memory/data_drop0.wast: -------------------------------------------------------------------------------- 1 | ;; data.drop 2 | (module 3 | (memory $mem0 0) 4 | (memory $mem1 1) 5 | (memory $mem2 0) 6 | (data $p "x") 7 | (data $a (memory 1) (i32.const 0) "x") 8 | 9 | (func (export "drop_passive") (data.drop $p)) 10 | (func (export "init_passive") (param $len i32) 11 | (memory.init $mem1 $p (i32.const 0) (i32.const 0) (local.get $len))) 12 | 13 | (func (export "drop_active") (data.drop $a)) 14 | (func (export "init_active") (param $len i32) 15 | (memory.init $mem1 $a (i32.const 0) (i32.const 0) (local.get $len))) 16 | ) 17 | 18 | (invoke "init_passive" (i32.const 1)) 19 | (invoke "drop_passive") 20 | (invoke "drop_passive") 21 | (assert_return (invoke "init_passive" (i32.const 0))) 22 | (assert_trap (invoke "init_passive" (i32.const 1)) "out of bounds memory access") 23 | (invoke "init_passive" (i32.const 0)) 24 | (invoke "drop_active") 25 | (assert_return (invoke "init_active" (i32.const 0))) 26 | (assert_trap (invoke "init_active" (i32.const 1)) "out of bounds memory access") 27 | (invoke "init_active" (i32.const 0)) 28 | 29 | -------------------------------------------------------------------------------- /test/core/multi-memory/exports0.wast: -------------------------------------------------------------------------------- 1 | ;; Memories 2 | 3 | (module (memory 0) (export "a" (memory 0))) 4 | (module (memory 0) (export "a" (memory 0)) (export "b" (memory 0))) 5 | (module (memory 0) (memory 0) (export "a" (memory 0)) (export "b" (memory 1))) 6 | (module 7 | (memory $mem0 0) 8 | (memory $mem1 0) 9 | (memory $mem2 0) 10 | (memory $mem3 0) 11 | (memory $mem4 0) 12 | (memory $mem5 0) 13 | (memory $mem6 0) 14 | 15 | (export "a" (memory $mem0)) 16 | (export "b" (memory $mem1)) 17 | (export "ac" (memory $mem2)) 18 | (export "bc" (memory $mem3)) 19 | (export "ad" (memory $mem4)) 20 | (export "bd" (memory $mem5)) 21 | (export "be" (memory $mem6)) 22 | 23 | (export "za" (memory $mem0)) 24 | (export "zb" (memory $mem1)) 25 | (export "zac" (memory $mem2)) 26 | (export "zbc" (memory $mem3)) 27 | (export "zad" (memory $mem4)) 28 | (export "zbd" (memory $mem5)) 29 | (export "zbe" (memory $mem6)) 30 | ) 31 | 32 | (module 33 | (export "a" (memory 0)) 34 | (memory 6) 35 | 36 | (export "b" (memory 1)) 37 | (memory 3) 38 | ) 39 | 40 | (module 41 | (export "a" (memory 0)) 42 | (memory 0 1) 43 | (memory 0 1) 44 | (memory 0 1) 45 | (memory 0 1) 46 | 47 | (export "b" (memory 3)) 48 | ) 49 | (module (export "a" (memory $a)) (memory $a 0)) 50 | (module (export "a" (memory $a)) (memory $a 0 1)) 51 | 52 | -------------------------------------------------------------------------------- /test/core/multi-memory/float_exprs0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0 0) 3 | (memory $m 1 1) 4 | (memory 0 0) 5 | (func (export "init") (param $i i32) (param $x f64) 6 | (f64.store $m (local.get $i) (local.get $x))) 7 | 8 | (func (export "run") (param $n i32) (param $z f64) 9 | (local $i i32) 10 | (block $exit 11 | (loop $cont 12 | (f64.store $m 13 | (local.get $i) 14 | (f64.div (f64.load $m (local.get $i)) (local.get $z)) 15 | ) 16 | (local.set $i (i32.add (local.get $i) (i32.const 8))) 17 | (br_if $cont (i32.lt_u (local.get $i) (local.get $n))) 18 | ) 19 | ) 20 | ) 21 | 22 | (func (export "check") (param $i i32) (result f64) (f64.load $m (local.get $i))) 23 | ) 24 | 25 | (invoke "init" (i32.const 0) (f64.const 15.1)) 26 | (invoke "init" (i32.const 8) (f64.const 15.2)) 27 | (invoke "init" (i32.const 16) (f64.const 15.3)) 28 | (invoke "init" (i32.const 24) (f64.const 15.4)) 29 | (assert_return (invoke "check" (i32.const 0)) (f64.const 15.1)) 30 | (assert_return (invoke "check" (i32.const 8)) (f64.const 15.2)) 31 | (assert_return (invoke "check" (i32.const 16)) (f64.const 15.3)) 32 | (assert_return (invoke "check" (i32.const 24)) (f64.const 15.4)) 33 | (invoke "run" (i32.const 32) (f64.const 3.0)) 34 | (assert_return (invoke "check" (i32.const 0)) (f64.const 0x1.4222222222222p+2)) 35 | (assert_return (invoke "check" (i32.const 8)) (f64.const 0x1.4444444444444p+2)) 36 | (assert_return (invoke "check" (i32.const 16)) (f64.const 0x1.4666666666667p+2)) 37 | (assert_return (invoke "check" (i32.const 24)) (f64.const 0x1.4888888888889p+2)) 38 | 39 | -------------------------------------------------------------------------------- /test/core/multi-memory/float_memory0.wast: -------------------------------------------------------------------------------- 1 | ;; Test that floating-point load and store are bit-preserving. 2 | 3 | ;; Test that load and store do not canonicalize NaNs as x87 does. 4 | 5 | (module 6 | (memory 0 0) 7 | (memory 0 0) 8 | (memory 0 0) 9 | (memory $m (data "\00\00\a0\7f")) 10 | (memory 0 0) 11 | (memory 0 0) 12 | 13 | (func (export "f32.load") (result f32) (f32.load $m (i32.const 0))) 14 | (func (export "i32.load") (result i32) (i32.load $m (i32.const 0))) 15 | (func (export "f32.store") (f32.store $m (i32.const 0) (f32.const nan:0x200000))) 16 | (func (export "i32.store") (i32.store $m (i32.const 0) (i32.const 0x7fa00000))) 17 | (func (export "reset") (i32.store $m (i32.const 0) (i32.const 0))) 18 | ) 19 | 20 | (assert_return (invoke "i32.load") (i32.const 0x7fa00000)) 21 | (assert_return (invoke "f32.load") (f32.const nan:0x200000)) 22 | (invoke "reset") 23 | (assert_return (invoke "i32.load") (i32.const 0x0)) 24 | (assert_return (invoke "f32.load") (f32.const 0.0)) 25 | (invoke "f32.store") 26 | (assert_return (invoke "i32.load") (i32.const 0x7fa00000)) 27 | (assert_return (invoke "f32.load") (f32.const nan:0x200000)) 28 | (invoke "reset") 29 | (assert_return (invoke "i32.load") (i32.const 0x0)) 30 | (assert_return (invoke "f32.load") (f32.const 0.0)) 31 | (invoke "i32.store") 32 | (assert_return (invoke "i32.load") (i32.const 0x7fa00000)) 33 | (assert_return (invoke "f32.load") (f32.const nan:0x200000)) 34 | 35 | (module 36 | (memory 0 0) 37 | (memory $m (data "\00\00\00\00\00\00\f4\7f")) 38 | 39 | (func (export "f64.load") (result f64) (f64.load $m (i32.const 0))) 40 | (func (export "i64.load") (result i64) (i64.load $m (i32.const 0))) 41 | (func (export "f64.store") (f64.store $m (i32.const 0) (f64.const nan:0x4000000000000))) 42 | (func (export "i64.store") (i64.store $m (i32.const 0) (i64.const 0x7ff4000000000000))) 43 | (func (export "reset") (i64.store $m (i32.const 0) (i64.const 0))) 44 | ) 45 | 46 | (assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000)) 47 | (assert_return (invoke "f64.load") (f64.const nan:0x4000000000000)) 48 | (invoke "reset") 49 | (assert_return (invoke "i64.load") (i64.const 0x0)) 50 | (assert_return (invoke "f64.load") (f64.const 0.0)) 51 | (invoke "f64.store") 52 | (assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000)) 53 | (assert_return (invoke "f64.load") (f64.const nan:0x4000000000000)) 54 | (invoke "reset") 55 | (assert_return (invoke "i64.load") (i64.const 0x0)) 56 | (assert_return (invoke "f64.load") (f64.const 0.0)) 57 | (invoke "i64.store") 58 | (assert_return (invoke "i64.load") (i64.const 0x7ff4000000000000)) 59 | (assert_return (invoke "f64.load") (f64.const nan:0x4000000000000)) 60 | 61 | -------------------------------------------------------------------------------- /test/core/multi-memory/imports0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "func")) 3 | (func (export "func-i32") (param i32)) 4 | (func (export "func-f32") (param f32)) 5 | (func (export "func->i32") (result i32) (i32.const 22)) 6 | (func (export "func->f32") (result f32) (f32.const 11)) 7 | (func (export "func-i32->i32") (param i32) (result i32) (local.get 0)) 8 | (func (export "func-i64->i64") (param i64) (result i64) (local.get 0)) 9 | (global (export "global-i32") i32 (i32.const 55)) 10 | (global (export "global-f32") f32 (f32.const 44)) 11 | (global (export "global-mut-i64") (mut i64) (i64.const 66)) 12 | (table (export "table-10-inf") 10 funcref) 13 | (table (export "table-10-20") 10 20 funcref) 14 | (memory (export "memory-2-inf") 2) 15 | (memory (export "memory-2-4") 2 4) 16 | ) 17 | 18 | (register "test") 19 | 20 | (assert_unlinkable 21 | (module (import "test" "memory-2-inf" (func))) 22 | "incompatible import type" 23 | ) 24 | (assert_unlinkable 25 | (module (import "test" "memory-2-4" (func))) 26 | "incompatible import type" 27 | ) 28 | 29 | (assert_unlinkable 30 | (module (import "test" "memory-2-inf" (global i32))) 31 | "incompatible import type" 32 | ) 33 | (assert_unlinkable 34 | (module (import "test" "memory-2-4" (global i32))) 35 | "incompatible import type" 36 | ) 37 | 38 | (assert_unlinkable 39 | (module (import "test" "memory-2-inf" (table 10 funcref))) 40 | "incompatible import type" 41 | ) 42 | (assert_unlinkable 43 | (module (import "test" "memory-2-4" (table 10 funcref))) 44 | "incompatible import type" 45 | ) 46 | -------------------------------------------------------------------------------- /test/core/multi-memory/imports1.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (import "spectest" "memory" (memory 1 2)) 3 | (import "spectest" "memory" (memory 1 2)) 4 | (memory $m (import "spectest" "memory") 1 2) 5 | (import "spectest" "memory" (memory 1 2)) 6 | 7 | (data (memory 2) (i32.const 10) "\10") 8 | 9 | (func (export "load") (param i32) (result i32) (i32.load $m (local.get 0))) 10 | ) 11 | 12 | (assert_return (invoke "load" (i32.const 0)) (i32.const 0)) 13 | (assert_return (invoke "load" (i32.const 10)) (i32.const 16)) 14 | (assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000)) 15 | (assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access") 16 | 17 | -------------------------------------------------------------------------------- /test/core/multi-memory/imports2.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory (export "z") 0 0) 3 | (memory (export "memory-2-inf") 2) 4 | (memory (export "memory-2-4") 2 4) 5 | ) 6 | 7 | (register "test") 8 | 9 | (module 10 | (import "test" "z" (memory 0)) 11 | (memory $m (import "spectest" "memory") 1 2) 12 | (data (memory 1) (i32.const 10) "\10") 13 | 14 | (func (export "load") (param i32) (result i32) (i32.load $m (local.get 0))) 15 | ) 16 | 17 | (assert_return (invoke "load" (i32.const 0)) (i32.const 0)) 18 | (assert_return (invoke "load" (i32.const 10)) (i32.const 16)) 19 | (assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000)) 20 | (assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access") 21 | 22 | (module 23 | (memory (import "spectest" "memory") 1 2) 24 | (data (memory 0) (i32.const 10) "\10") 25 | 26 | (func (export "load") (param i32) (result i32) (i32.load (local.get 0))) 27 | ) 28 | (assert_return (invoke "load" (i32.const 0)) (i32.const 0)) 29 | (assert_return (invoke "load" (i32.const 10)) (i32.const 16)) 30 | (assert_return (invoke "load" (i32.const 8)) (i32.const 0x100000)) 31 | (assert_trap (invoke "load" (i32.const 1000000)) "out of bounds memory access") 32 | 33 | (module 34 | (import "test" "memory-2-inf" (memory 2)) 35 | (import "test" "memory-2-inf" (memory 1)) 36 | (import "test" "memory-2-inf" (memory 0)) 37 | ) 38 | 39 | (module 40 | (import "spectest" "memory" (memory 1)) 41 | (import "spectest" "memory" (memory 0)) 42 | (import "spectest" "memory" (memory 1 2)) 43 | (import "spectest" "memory" (memory 0 2)) 44 | (import "spectest" "memory" (memory 1 3)) 45 | (import "spectest" "memory" (memory 0 3)) 46 | ) 47 | 48 | (assert_unlinkable 49 | (module (import "test" "unknown" (memory 1))) 50 | "unknown import" 51 | ) 52 | (assert_unlinkable 53 | (module (import "spectest" "unknown" (memory 1))) 54 | "unknown import" 55 | ) 56 | 57 | (assert_unlinkable 58 | (module (import "test" "memory-2-inf" (memory 3))) 59 | "incompatible import type" 60 | ) 61 | (assert_unlinkable 62 | (module (import "test" "memory-2-inf" (memory 2 3))) 63 | "incompatible import type" 64 | ) 65 | (assert_unlinkable 66 | (module (import "spectest" "memory" (memory 2))) 67 | "incompatible import type" 68 | ) 69 | (assert_unlinkable 70 | (module (import "spectest" "memory" (memory 1 1))) 71 | "incompatible import type" 72 | ) 73 | 74 | -------------------------------------------------------------------------------- /test/core/multi-memory/imports3.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "func")) 3 | (func (export "func-i32") (param i32)) 4 | (func (export "func-f32") (param f32)) 5 | (func (export "func->i32") (result i32) (i32.const 22)) 6 | (func (export "func->f32") (result f32) (f32.const 11)) 7 | (func (export "func-i32->i32") (param i32) (result i32) (local.get 0)) 8 | (func (export "func-i64->i64") (param i64) (result i64) (local.get 0)) 9 | (global (export "global-i32") i32 (i32.const 55)) 10 | (global (export "global-f32") f32 (f32.const 44)) 11 | (global (export "global-mut-i64") (mut i64) (i64.const 66)) 12 | (table (export "table-10-inf") 10 funcref) 13 | (table (export "table-10-20") 10 20 funcref) 14 | (memory (export "memory-2-inf") 2) 15 | (memory (export "memory-2-4") 2 4) 16 | ) 17 | 18 | (register "test") 19 | (assert_unlinkable 20 | (module 21 | (import "test" "memory-2-4" (memory 1)) 22 | (import "test" "func-i32" (memory 1)) 23 | ) 24 | "incompatible import type" 25 | ) 26 | (assert_unlinkable 27 | (module 28 | (import "test" "memory-2-4" (memory 1)) 29 | (import "test" "global-i32" (memory 1)) 30 | ) 31 | "incompatible import type" 32 | ) 33 | (assert_unlinkable 34 | (module 35 | (import "test" "memory-2-4" (memory 1)) 36 | (import "test" "table-10-inf" (memory 1)) 37 | ) 38 | "incompatible import type" 39 | ) 40 | (assert_unlinkable 41 | (module 42 | (import "test" "memory-2-4" (memory 1)) 43 | (import "spectest" "print_i32" (memory 1)) 44 | ) 45 | "incompatible import type" 46 | ) 47 | (assert_unlinkable 48 | (module 49 | (import "test" "memory-2-4" (memory 1)) 50 | (import "spectest" "global_i32" (memory 1)) 51 | ) 52 | "incompatible import type" 53 | ) 54 | (assert_unlinkable 55 | (module 56 | (import "test" "memory-2-4" (memory 1)) 57 | (import "spectest" "table" (memory 1)) 58 | ) 59 | "incompatible import type" 60 | ) 61 | 62 | (assert_unlinkable 63 | (module 64 | (import "test" "memory-2-4" (memory 1)) 65 | (import "spectest" "memory" (memory 2)) 66 | ) 67 | "incompatible import type" 68 | ) 69 | (assert_unlinkable 70 | (module 71 | (import "test" "memory-2-4" (memory 1)) 72 | (import "spectest" "memory" (memory 1 1)) 73 | ) 74 | "incompatible import type" 75 | ) 76 | -------------------------------------------------------------------------------- /test/core/multi-memory/imports4.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory (export "memory-2-inf") 2) 3 | (memory (export "memory-2-4") 2 4) 4 | ) 5 | 6 | (register "test") 7 | 8 | (module 9 | (import "test" "memory-2-4" (memory 1)) 10 | (memory $m (import "spectest" "memory") 0 3) ;; actual has max size 2 11 | (func (export "grow") (param i32) (result i32) (memory.grow $m (local.get 0))) 12 | ) 13 | (assert_return (invoke "grow" (i32.const 0)) (i32.const 1)) 14 | (assert_return (invoke "grow" (i32.const 1)) (i32.const 1)) 15 | (assert_return (invoke "grow" (i32.const 0)) (i32.const 2)) 16 | (assert_return (invoke "grow" (i32.const 1)) (i32.const -1)) 17 | (assert_return (invoke "grow" (i32.const 0)) (i32.const 2)) 18 | 19 | (module $Mgm 20 | (memory 0) 21 | (memory 0) 22 | (memory $m (export "memory") 1) ;; initial size is 1 23 | (func (export "grow") (result i32) (memory.grow $m (i32.const 1))) 24 | ) 25 | (register "grown-memory" $Mgm) 26 | (assert_return (invoke $Mgm "grow") (i32.const 1)) ;; now size is 2 27 | 28 | (module $Mgim1 29 | ;; imported memory limits should match, because external memory size is 2 now 30 | (import "test" "memory-2-4" (memory 1)) 31 | (memory $m (export "memory") (import "grown-memory" "memory") 2) 32 | (memory 0) 33 | (memory 0) 34 | (func (export "grow") (result i32) (memory.grow $m (i32.const 1))) 35 | ) 36 | (register "grown-imported-memory" $Mgim1) 37 | (assert_return (invoke $Mgim1 "grow") (i32.const 2)) ;; now size is 3 38 | 39 | (module $Mgim2 40 | ;; imported memory limits should match, because external memory size is 3 now 41 | (import "test" "memory-2-4" (memory 1)) 42 | (memory $m (import "grown-imported-memory" "memory") 3) 43 | (memory 0) 44 | (memory 0) 45 | (func (export "size") (result i32) (memory.size $m)) 46 | ) 47 | (assert_return (invoke $Mgim2 "size") (i32.const 3)) 48 | -------------------------------------------------------------------------------- /test/core/multi-memory/linking0.wast: -------------------------------------------------------------------------------- 1 | (module $Mt 2 | (type (func (result i32))) 3 | (type (func)) 4 | 5 | (table (export "tab") 10 funcref) 6 | (elem (i32.const 2) $g $g $g $g) 7 | (func $g (result i32) (i32.const 4)) 8 | (func (export "h") (result i32) (i32.const -4)) 9 | 10 | (func (export "call") (param i32) (result i32) 11 | (call_indirect (type 0) (local.get 0)) 12 | ) 13 | ) 14 | (register "Mt" $Mt) 15 | 16 | (assert_unlinkable 17 | (module 18 | (table (import "Mt" "tab") 10 funcref) 19 | (memory (import "spectest" "memory") 1) 20 | (memory (import "Mt" "mem") 1) ;; does not exist 21 | (func $f (result i32) (i32.const 0)) 22 | (elem (i32.const 7) $f) 23 | (elem (i32.const 9) $f) 24 | ) 25 | "unknown import" 26 | ) 27 | (assert_trap (invoke $Mt "call" (i32.const 7)) "uninitialized element") 28 | 29 | 30 | (assert_trap 31 | (module 32 | (table (import "Mt" "tab") 10 funcref) 33 | (func $f (result i32) (i32.const 0)) 34 | (elem (i32.const 7) $f) 35 | (memory 0) 36 | (memory $m 1) 37 | (memory 0) 38 | (data $m (i32.const 0x10000) "d") ;; out of bounds 39 | ) 40 | "out of bounds memory access" 41 | ) 42 | (assert_return (invoke $Mt "call" (i32.const 7)) (i32.const 0)) 43 | -------------------------------------------------------------------------------- /test/core/multi-memory/linking1.wast: -------------------------------------------------------------------------------- 1 | (module $Mm 2 | (memory $mem0 (export "mem0") 0 0) 3 | (memory $mem1 (export "mem1") 1 5) 4 | (memory $mem2 (export "mem2") 0 0) 5 | 6 | (data (memory 1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") 7 | 8 | (func (export "load") (param $a i32) (result i32) 9 | (i32.load8_u $mem1 (local.get 0)) 10 | ) 11 | ) 12 | (register "Mm" $Mm) 13 | 14 | (module $Nm 15 | (func $loadM (import "Mm" "load") (param i32) (result i32)) 16 | (memory (import "Mm" "mem0") 0) 17 | 18 | (memory $m 1) 19 | (data (memory 1) (i32.const 10) "\f0\f1\f2\f3\f4\f5") 20 | 21 | (export "Mm.load" (func $loadM)) 22 | (func (export "load") (param $a i32) (result i32) 23 | (i32.load8_u $m (local.get 0)) 24 | ) 25 | ) 26 | 27 | (assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 2)) 28 | (assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 2)) 29 | (assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2)) 30 | 31 | (module $Om 32 | (memory (import "Mm" "mem1") 1) 33 | (data (i32.const 5) "\a0\a1\a2\a3\a4\a5\a6\a7") 34 | 35 | (func (export "load") (param $a i32) (result i32) 36 | (i32.load8_u (local.get 0)) 37 | ) 38 | ) 39 | 40 | (assert_return (invoke $Mm "load" (i32.const 12)) (i32.const 0xa7)) 41 | (assert_return (invoke $Nm "Mm.load" (i32.const 12)) (i32.const 0xa7)) 42 | (assert_return (invoke $Nm "load" (i32.const 12)) (i32.const 0xf2)) 43 | (assert_return (invoke $Om "load" (i32.const 12)) (i32.const 0xa7)) 44 | 45 | (module 46 | (memory (import "Mm" "mem1") 0) 47 | (data (i32.const 0xffff) "a") 48 | ) 49 | 50 | (assert_trap 51 | (module 52 | (memory (import "Mm" "mem0") 0) 53 | (data (i32.const 0xffff) "a") 54 | ) 55 | "out of bounds memory access" 56 | ) 57 | 58 | (assert_trap 59 | (module 60 | (memory (import "Mm" "mem1") 0) 61 | (data (i32.const 0x10000) "a") 62 | ) 63 | "out of bounds memory access" 64 | ) 65 | 66 | -------------------------------------------------------------------------------- /test/core/multi-memory/linking2.wast: -------------------------------------------------------------------------------- 1 | (module $Mm 2 | (memory $mem0 (export "mem0") 0 0) 3 | (memory $mem1 (export "mem1") 1 5) 4 | (memory $mem2 (export "mem2") 0 0) 5 | 6 | (data (memory 1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") 7 | 8 | (func (export "load") (param $a i32) (result i32) 9 | (i32.load8_u $mem1 (local.get 0)) 10 | ) 11 | ) 12 | (register "Mm" $Mm) 13 | 14 | (module $Pm 15 | (memory (import "Mm" "mem1") 1 8) 16 | 17 | (func (export "grow") (param $a i32) (result i32) 18 | (memory.grow (local.get 0)) 19 | ) 20 | ) 21 | 22 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 1)) 23 | (assert_return (invoke $Pm "grow" (i32.const 2)) (i32.const 1)) 24 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 3)) 25 | (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 3)) 26 | (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const 4)) 27 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5)) 28 | (assert_return (invoke $Pm "grow" (i32.const 1)) (i32.const -1)) 29 | (assert_return (invoke $Pm "grow" (i32.const 0)) (i32.const 5)) 30 | 31 | -------------------------------------------------------------------------------- /test/core/multi-memory/linking3.wast: -------------------------------------------------------------------------------- 1 | (module $Mm 2 | (memory $mem0 (export "mem0") 0 0) 3 | (memory $mem1 (export "mem1") 5 5) 4 | (memory $mem2 (export "mem2") 0 0) 5 | 6 | (data (memory 1) (i32.const 10) "\00\01\02\03\04\05\06\07\08\09") 7 | 8 | (func (export "load") (param $a i32) (result i32) 9 | (i32.load8_u $mem1 (local.get 0)) 10 | ) 11 | ) 12 | (register "Mm" $Mm) 13 | 14 | (assert_unlinkable 15 | (module 16 | (func $host (import "spectest" "print")) 17 | (memory (import "Mm" "mem1") 1) 18 | (table (import "Mm" "tab") 0 funcref) ;; does not exist 19 | (data (i32.const 0) "abc") 20 | ) 21 | "unknown import" 22 | ) 23 | (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 0)) 24 | 25 | ;; Unlike in v1 spec, active data segments written before an 26 | ;; out-of-bounds access persist after the instantiation failure. 27 | (assert_trap 28 | (module 29 | ;; Note: the memory is 5 pages large by the time we get here. 30 | (memory (import "Mm" "mem1") 1) 31 | (data (i32.const 0) "abc") 32 | (data (i32.const 327670) "zzzzzzzzzzzzzzzzzz") ;; (partially) out of bounds 33 | ) 34 | "out of bounds memory access" 35 | ) 36 | (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) 37 | (assert_return (invoke $Mm "load" (i32.const 327670)) (i32.const 0)) 38 | 39 | (assert_trap 40 | (module 41 | (memory (import "Mm" "mem1") 1) 42 | (data (i32.const 0) "abc") 43 | (table 0 funcref) 44 | (func) 45 | (elem (i32.const 0) 0) ;; out of bounds 46 | ) 47 | "out of bounds table access" 48 | ) 49 | (assert_return (invoke $Mm "load" (i32.const 0)) (i32.const 97)) 50 | 51 | ;; Store is modified if the start function traps. 52 | (module $Ms 53 | (type $t (func (result i32))) 54 | (memory (export "memory") 1) 55 | (table (export "table") 1 funcref) 56 | (func (export "get memory[0]") (type $t) 57 | (i32.load8_u (i32.const 0)) 58 | ) 59 | (func (export "get table[0]") (type $t) 60 | (call_indirect (type $t) (i32.const 0)) 61 | ) 62 | ) 63 | (register "Ms" $Ms) 64 | 65 | (assert_trap 66 | (module 67 | (import "Ms" "memory" (memory 1)) 68 | (import "Ms" "table" (table 1 funcref)) 69 | (data (i32.const 0) "hello") 70 | (elem (i32.const 0) $f) 71 | (func $f (result i32) 72 | (i32.const 0xdead) 73 | ) 74 | (func $main 75 | (unreachable) 76 | ) 77 | (start $main) 78 | ) 79 | "unreachable" 80 | ) 81 | 82 | (assert_return (invoke $Ms "get memory[0]") (i32.const 104)) ;; 'h' 83 | (assert_return (invoke $Ms "get table[0]") (i32.const 0xdead)) 84 | -------------------------------------------------------------------------------- /test/core/multi-memory/load0.wast: -------------------------------------------------------------------------------- 1 | ;; Multiple memories 2 | 3 | (module 4 | (memory $mem1 1) 5 | (memory $mem2 1) 6 | 7 | (func (export "load1") (param i32) (result i64) 8 | (i64.load $mem1 (local.get 0)) 9 | ) 10 | (func (export "load2") (param i32) (result i64) 11 | (i64.load $mem2 (local.get 0)) 12 | ) 13 | 14 | (data (memory $mem1) (i32.const 0) "\01") 15 | (data (memory $mem2) (i32.const 0) "\02") 16 | ) 17 | 18 | (assert_return (invoke "load1" (i32.const 0)) (i64.const 1)) 19 | (assert_return (invoke "load2" (i32.const 0)) (i64.const 2)) 20 | -------------------------------------------------------------------------------- /test/core/multi-memory/load1.wast: -------------------------------------------------------------------------------- 1 | (module $M 2 | (memory (export "mem") 2) 3 | 4 | (func (export "read") (param i32) (result i32) 5 | (i32.load8_u (local.get 0)) 6 | ) 7 | ) 8 | (register "M") 9 | 10 | (module 11 | (memory $mem1 (import "M" "mem") 2) 12 | (memory $mem2 3) 13 | 14 | (data (memory $mem1) (i32.const 20) "\01\02\03\04\05") 15 | (data (memory $mem2) (i32.const 50) "\0A\0B\0C\0D\0E") 16 | 17 | (func (export "read1") (param i32) (result i32) 18 | (i32.load8_u $mem1 (local.get 0)) 19 | ) 20 | (func (export "read2") (param i32) (result i32) 21 | (i32.load8_u $mem2 (local.get 0)) 22 | ) 23 | ) 24 | 25 | (assert_return (invoke $M "read" (i32.const 20)) (i32.const 1)) 26 | (assert_return (invoke $M "read" (i32.const 21)) (i32.const 2)) 27 | (assert_return (invoke $M "read" (i32.const 22)) (i32.const 3)) 28 | (assert_return (invoke $M "read" (i32.const 23)) (i32.const 4)) 29 | (assert_return (invoke $M "read" (i32.const 24)) (i32.const 5)) 30 | 31 | (assert_return (invoke "read1" (i32.const 20)) (i32.const 1)) 32 | (assert_return (invoke "read1" (i32.const 21)) (i32.const 2)) 33 | (assert_return (invoke "read1" (i32.const 22)) (i32.const 3)) 34 | (assert_return (invoke "read1" (i32.const 23)) (i32.const 4)) 35 | (assert_return (invoke "read1" (i32.const 24)) (i32.const 5)) 36 | 37 | (assert_return (invoke "read2" (i32.const 50)) (i32.const 10)) 38 | (assert_return (invoke "read2" (i32.const 51)) (i32.const 11)) 39 | (assert_return (invoke "read2" (i32.const 52)) (i32.const 12)) 40 | (assert_return (invoke "read2" (i32.const 53)) (i32.const 13)) 41 | (assert_return (invoke "read2" (i32.const 54)) (i32.const 14)) 42 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_copy0.wast: -------------------------------------------------------------------------------- 1 | ;; memory.copy 2 | (module 3 | (memory $mem0 (data "\ff\11\44\ee")) 4 | (memory $mem1 (data "\ee\22\55\ff")) 5 | (memory $mem2 (data "\dd\33\66\00")) 6 | (memory $mem3 (data "\aa\bb\cc\dd")) 7 | 8 | (func (export "copy") (param i32 i32 i32) 9 | (memory.copy $mem3 $mem3 10 | (local.get 0) 11 | (local.get 1) 12 | (local.get 2))) 13 | 14 | (func (export "load8_u") (param i32) (result i32) 15 | (i32.load8_u $mem3 (local.get 0))) 16 | ) 17 | 18 | ;; Non-overlapping copy. 19 | (invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4)) 20 | 21 | (assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) 22 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa)) 23 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb)) 24 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) 25 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) 26 | (assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) 27 | 28 | ;; Overlap, source > dest 29 | (invoke "copy" (i32.const 8) (i32.const 10) (i32.const 4)) 30 | (assert_return (invoke "load8_u" (i32.const 8)) (i32.const 0xaa)) 31 | (assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0xbb)) 32 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xcc)) 33 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xdd)) 34 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) 35 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) 36 | 37 | ;; Overlap, source < dest 38 | (invoke "copy" (i32.const 10) (i32.const 7) (i32.const 6)) 39 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0)) 40 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xaa)) 41 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xbb)) 42 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xcc)) 43 | (assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0xdd)) 44 | (assert_return (invoke "load8_u" (i32.const 15)) (i32.const 0xcc)) 45 | (assert_return (invoke "load8_u" (i32.const 16)) (i32.const 0)) 46 | 47 | ;; Copy ending at memory limit is ok. 48 | (invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100)) 49 | (invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100)) 50 | 51 | ;; Succeed when copying 0 bytes at the end of the region. 52 | (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 53 | (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) 54 | 55 | ;; Copying 0 bytes outside the memory traps. 56 | (assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 57 | "out of bounds memory access") 58 | (assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) 59 | "out of bounds memory access") 60 | 61 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_copy1.wast: -------------------------------------------------------------------------------- 1 | ;; test memory.copy across different memories. 2 | (module 3 | (memory $mem0 (data "\ff\11\44\ee")) 4 | (memory $mem1 (data "\ee\22\55\ff")) 5 | (memory $mem2 (data "\dd\33\66\00")) 6 | (memory $mem3 (data "\aa\bb\cc\dd")) 7 | 8 | (func (export "copy") (param i32 i32 i32) 9 | (memory.copy $mem0 $mem3 10 | (local.get 0) 11 | (local.get 1) 12 | (local.get 2))) 13 | 14 | (func (export "load8_u") (param i32) (result i32) 15 | (i32.load8_u $mem0 (local.get 0))) 16 | ) 17 | 18 | ;; Non-overlapping copy. 19 | (invoke "copy" (i32.const 10) (i32.const 0) (i32.const 4)) 20 | 21 | (assert_return (invoke "load8_u" (i32.const 9)) (i32.const 0)) 22 | (assert_return (invoke "load8_u" (i32.const 10)) (i32.const 0xaa)) 23 | (assert_return (invoke "load8_u" (i32.const 11)) (i32.const 0xbb)) 24 | (assert_return (invoke "load8_u" (i32.const 12)) (i32.const 0xcc)) 25 | (assert_return (invoke "load8_u" (i32.const 13)) (i32.const 0xdd)) 26 | (assert_return (invoke "load8_u" (i32.const 14)) (i32.const 0)) 27 | 28 | ;; Copy ending at memory limit is ok. 29 | (invoke "copy" (i32.const 0xff00) (i32.const 0) (i32.const 0x100)) 30 | (invoke "copy" (i32.const 0xfe00) (i32.const 0xff00) (i32.const 0x100)) 31 | 32 | ;; Succeed when copying 0 bytes at the end of the region. 33 | (invoke "copy" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 34 | (invoke "copy" (i32.const 0) (i32.const 0x10000) (i32.const 0)) 35 | 36 | ;; Copying 0 bytes outside the memory traps. 37 | (assert_trap (invoke "copy" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 38 | "out of bounds memory access") 39 | (assert_trap (invoke "copy" (i32.const 0) (i32.const 0x10001) (i32.const 0)) 40 | "out of bounds memory access") 41 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_fill0.wast: -------------------------------------------------------------------------------- 1 | ;; memory.fill 2 | (module 3 | (memory $mem0 0) 4 | (memory $mem1 0) 5 | (memory $mem2 1) 6 | 7 | (func (export "fill") (param i32 i32 i32) 8 | (memory.fill $mem2 9 | (local.get 0) 10 | (local.get 1) 11 | (local.get 2))) 12 | 13 | (func (export "load8_u") (param i32) (result i32) 14 | (i32.load8_u $mem2 (local.get 0))) 15 | ) 16 | 17 | ;; Basic fill test. 18 | (invoke "fill" (i32.const 1) (i32.const 0xff) (i32.const 3)) 19 | (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0)) 20 | (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xff)) 21 | (assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0xff)) 22 | (assert_return (invoke "load8_u" (i32.const 3)) (i32.const 0xff)) 23 | (assert_return (invoke "load8_u" (i32.const 4)) (i32.const 0)) 24 | 25 | ;; Fill value is stored as a byte. 26 | (invoke "fill" (i32.const 0) (i32.const 0xbbaa) (i32.const 2)) 27 | (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xaa)) 28 | (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xaa)) 29 | 30 | ;; Fill all of memory 31 | (invoke "fill" (i32.const 0) (i32.const 0) (i32.const 0x10000)) 32 | 33 | ;; Out-of-bounds writes trap, and nothing is written 34 | (assert_trap (invoke "fill" (i32.const 0xff00) (i32.const 1) (i32.const 0x101)) 35 | "out of bounds memory access") 36 | (assert_return (invoke "load8_u" (i32.const 0xff00)) (i32.const 0)) 37 | (assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0)) 38 | 39 | ;; Succeed when writing 0 bytes at the end of the region. 40 | (invoke "fill" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 41 | 42 | ;; Writing 0 bytes outside the memory traps. 43 | (assert_trap (invoke "fill" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 44 | "out of bounds memory access") 45 | 46 | 47 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_init0.wast: -------------------------------------------------------------------------------- 1 | ;; memory.init 2 | (module 3 | (memory $mem0 0) 4 | (memory $mem1 0) 5 | (memory $mem2 1) 6 | (memory $mem3 0) 7 | (data $mem2 "\aa\bb\cc\dd") 8 | 9 | (func (export "init") (param i32 i32 i32) 10 | (memory.init $mem2 0 11 | (local.get 0) 12 | (local.get 1) 13 | (local.get 2))) 14 | 15 | (func (export "load8_u") (param i32) (result i32) 16 | (i32.load8_u $mem2 (local.get 0))) 17 | ) 18 | 19 | (invoke "init" (i32.const 0) (i32.const 1) (i32.const 2)) 20 | (assert_return (invoke "load8_u" (i32.const 0)) (i32.const 0xbb)) 21 | (assert_return (invoke "load8_u" (i32.const 1)) (i32.const 0xcc)) 22 | (assert_return (invoke "load8_u" (i32.const 2)) (i32.const 0)) 23 | 24 | ;; Init ending at memory limit and segment limit is ok. 25 | (invoke "init" (i32.const 0xfffc) (i32.const 0) (i32.const 4)) 26 | 27 | ;; Out-of-bounds writes trap, and nothing is written. 28 | (assert_trap (invoke "init" (i32.const 0xfffe) (i32.const 0) (i32.const 3)) 29 | "out of bounds memory access") 30 | (assert_return (invoke "load8_u" (i32.const 0xfffe)) (i32.const 0xcc)) 31 | (assert_return (invoke "load8_u" (i32.const 0xffff)) (i32.const 0xdd)) 32 | 33 | ;; Succeed when writing 0 bytes at the end of either region. 34 | (invoke "init" (i32.const 0x10000) (i32.const 0) (i32.const 0)) 35 | (invoke "init" (i32.const 0) (i32.const 4) (i32.const 0)) 36 | 37 | ;; Writing 0 bytes outside the memory traps. 38 | (assert_trap (invoke "init" (i32.const 0x10001) (i32.const 0) (i32.const 0)) 39 | "out of bounds memory access") 40 | (assert_trap (invoke "init" (i32.const 0) (i32.const 5) (i32.const 0)) 41 | "out of bounds memory access") 42 | 43 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_size0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory 0) 4 | (memory 0) 5 | (memory 0) 6 | (memory $m 0) 7 | 8 | (func (export "size") (result i32) (memory.size $m)) 9 | (func (export "grow") (param $sz i32) (drop (memory.grow $m (local.get $sz)))) 10 | ) 11 | 12 | (assert_return (invoke "size") (i32.const 0)) 13 | (assert_return (invoke "grow" (i32.const 1))) 14 | (assert_return (invoke "size") (i32.const 1)) 15 | (assert_return (invoke "grow" (i32.const 4))) 16 | (assert_return (invoke "size") (i32.const 5)) 17 | (assert_return (invoke "grow" (i32.const 0))) 18 | (assert_return (invoke "size") (i32.const 5)) 19 | 20 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_size1.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory 0) 4 | (memory $n 0) 5 | (memory 0) 6 | (memory $m 0) 7 | 8 | (func (export "size") (result i32) (memory.size $m)) 9 | (func (export "grow") (param $sz i32) (drop (memory.grow $m (local.get $sz)))) 10 | 11 | (func (export "sizen") (result i32) (memory.size $n)) 12 | (func (export "grown") (param $sz i32) (drop (memory.grow $n (local.get $sz)))) 13 | ) 14 | 15 | (assert_return (invoke "size") (i32.const 0)) 16 | (assert_return (invoke "sizen") (i32.const 0)) 17 | (assert_return (invoke "grow" (i32.const 1))) 18 | (assert_return (invoke "size") (i32.const 1)) 19 | (assert_return (invoke "sizen") (i32.const 0)) 20 | (assert_return (invoke "grow" (i32.const 4))) 21 | (assert_return (invoke "size") (i32.const 5)) 22 | (assert_return (invoke "sizen") (i32.const 0)) 23 | (assert_return (invoke "grow" (i32.const 0))) 24 | (assert_return (invoke "size") (i32.const 5)) 25 | (assert_return (invoke "sizen") (i32.const 0)) 26 | 27 | (assert_return (invoke "grown" (i32.const 1))) 28 | (assert_return (invoke "size") (i32.const 5)) 29 | (assert_return (invoke "sizen") (i32.const 1)) 30 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_size2.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0 0) 3 | (memory 0 0) 4 | (memory $n 0 0) 5 | (memory $m 0 2) 6 | 7 | (func (export "size") (result i32) (memory.size $m)) 8 | (func (export "grow") (param $sz i32) (drop (memory.grow $m (local.get $sz)))) 9 | 10 | (func (export "sizen") (result i32) (memory.size $n)) 11 | (func (export "grown") (param $sz i32) (drop (memory.grow $n (local.get $sz)))) 12 | ) 13 | 14 | (assert_return (invoke "size") (i32.const 0)) 15 | (assert_return (invoke "sizen") (i32.const 0)) 16 | (assert_return (invoke "grow" (i32.const 3))) 17 | (assert_return (invoke "sizen") (i32.const 0)) 18 | (assert_return (invoke "size") (i32.const 0)) 19 | (assert_return (invoke "grow" (i32.const 1))) 20 | (assert_return (invoke "sizen") (i32.const 0)) 21 | (assert_return (invoke "size") (i32.const 1)) 22 | (assert_return (invoke "grow" (i32.const 0))) 23 | (assert_return (invoke "sizen") (i32.const 0)) 24 | (assert_return (invoke "size") (i32.const 1)) 25 | (assert_return (invoke "grow" (i32.const 4))) 26 | (assert_return (invoke "sizen") (i32.const 0)) 27 | (assert_return (invoke "size") (i32.const 1)) 28 | (assert_return (invoke "grow" (i32.const 1))) 29 | (assert_return (invoke "sizen") (i32.const 0)) 30 | (assert_return (invoke "size") (i32.const 2)) 31 | 32 | (assert_return (invoke "grown" (i32.const 1))) 33 | (assert_return (invoke "sizen") (i32.const 0)) 34 | (assert_return (invoke "size") (i32.const 2)) 35 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_size3.wast: -------------------------------------------------------------------------------- 1 | ;; Type errors 2 | 3 | (assert_invalid 4 | (module 5 | (memory 0) 6 | (memory $m 1) 7 | (memory 0) 8 | (func $type-result-i32-vs-empty 9 | (memory.size $m) 10 | ) 11 | ) 12 | "type mismatch" 13 | ) 14 | (assert_invalid 15 | (module 16 | (memory 0) 17 | (memory 0) 18 | (memory 0) 19 | (memory $m 1) 20 | (func $type-result-i32-vs-f32 (result f32) 21 | (memory.size $m) 22 | ) 23 | ) 24 | "type mismatch" 25 | ) 26 | -------------------------------------------------------------------------------- /test/core/multi-memory/memory_trap0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory 0) 4 | (memory $m 1) 5 | 6 | (func $addr_limit (result i32) 7 | (i32.mul (memory.size $m) (i32.const 0x10000)) 8 | ) 9 | 10 | (func (export "store") (param $i i32) (param $v i32) 11 | (i32.store $m (i32.add (call $addr_limit) (local.get $i)) (local.get $v)) 12 | ) 13 | 14 | (func (export "load") (param $i i32) (result i32) 15 | (i32.load $m (i32.add (call $addr_limit) (local.get $i))) 16 | ) 17 | 18 | (func (export "memory.grow") (param i32) (result i32) 19 | (memory.grow $m (local.get 0)) 20 | ) 21 | ) 22 | 23 | (assert_return (invoke "store" (i32.const -4) (i32.const 42))) 24 | (assert_return (invoke "load" (i32.const -4)) (i32.const 42)) 25 | (assert_trap (invoke "store" (i32.const -3) (i32.const 0x12345678)) "out of bounds memory access") 26 | (assert_trap (invoke "load" (i32.const -3)) "out of bounds memory access") 27 | (assert_trap (invoke "store" (i32.const -2) (i32.const 13)) "out of bounds memory access") 28 | (assert_trap (invoke "load" (i32.const -2)) "out of bounds memory access") 29 | (assert_trap (invoke "store" (i32.const -1) (i32.const 13)) "out of bounds memory access") 30 | (assert_trap (invoke "load" (i32.const -1)) "out of bounds memory access") 31 | (assert_trap (invoke "store" (i32.const 0) (i32.const 13)) "out of bounds memory access") 32 | (assert_trap (invoke "load" (i32.const 0)) "out of bounds memory access") 33 | (assert_trap (invoke "store" (i32.const 0x80000000) (i32.const 13)) "out of bounds memory access") 34 | (assert_trap (invoke "load" (i32.const 0x80000000)) "out of bounds memory access") 35 | (assert_return (invoke "memory.grow" (i32.const 0x10001)) (i32.const -1)) 36 | 37 | -------------------------------------------------------------------------------- /test/core/multi-memory/start0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory 0) 3 | (memory $m (data "A")) 4 | (memory $n 1) 5 | 6 | (func $inc 7 | (i32.store8 $m 8 | (i32.const 0) 9 | (i32.add 10 | (i32.load8_u $m (i32.const 0)) 11 | (i32.const 1) 12 | ) 13 | ) 14 | ) 15 | (func $get (result i32) 16 | (return (i32.load8_u $m (i32.const 0))) 17 | ) 18 | (func $getn (result i32) 19 | (return (i32.load8_u $n (i32.const 0))) 20 | ) 21 | (func $main 22 | (call $inc) 23 | (call $inc) 24 | (call $inc) 25 | ) 26 | 27 | (start $main) 28 | (export "inc" (func $inc)) 29 | (export "get" (func $get)) 30 | (export "getn" (func $getn)) 31 | ) 32 | (assert_return (invoke "get") (i32.const 68)) 33 | (assert_return (invoke "getn") (i32.const 0)) 34 | 35 | (invoke "inc") 36 | (assert_return (invoke "get") (i32.const 69)) 37 | (assert_return (invoke "getn") (i32.const 0)) 38 | 39 | (invoke "inc") 40 | (assert_return (invoke "get") (i32.const 70)) 41 | (assert_return (invoke "getn") (i32.const 0)) 42 | 43 | -------------------------------------------------------------------------------- /test/core/multi-memory/store0.wast: -------------------------------------------------------------------------------- 1 | ;; Multiple memories 2 | 3 | (module 4 | (memory $mem1 1) 5 | (memory $mem2 1) 6 | 7 | (func (export "load1") (param i32) (result i64) 8 | (i64.load $mem1 (local.get 0)) 9 | ) 10 | (func (export "load2") (param i32) (result i64) 11 | (i64.load $mem2 (local.get 0)) 12 | ) 13 | 14 | (func (export "store1") (param i32 i64) 15 | (i64.store $mem1 (local.get 0) (local.get 1)) 16 | ) 17 | (func (export "store2") (param i32 i64) 18 | (i64.store $mem2 (local.get 0) (local.get 1)) 19 | ) 20 | ) 21 | 22 | (invoke "store1" (i32.const 0) (i64.const 1)) 23 | (invoke "store2" (i32.const 0) (i64.const 2)) 24 | (assert_return (invoke "load1" (i32.const 0)) (i64.const 1)) 25 | (assert_return (invoke "load2" (i32.const 0)) (i64.const 2)) 26 | -------------------------------------------------------------------------------- /test/core/multi-memory/store1.wast: -------------------------------------------------------------------------------- 1 | (module $M1 2 | (memory (export "mem") 1) 3 | 4 | (func (export "load") (param i32) (result i64) 5 | (i64.load (local.get 0)) 6 | ) 7 | (func (export "store") (param i32 i64) 8 | (i64.store (local.get 0) (local.get 1)) 9 | ) 10 | ) 11 | (register "M1") 12 | 13 | (module $M2 14 | (memory (export "mem") 1) 15 | 16 | (func (export "load") (param i32) (result i64) 17 | (i64.load (local.get 0)) 18 | ) 19 | (func (export "store") (param i32 i64) 20 | (i64.store (local.get 0) (local.get 1)) 21 | ) 22 | ) 23 | (register "M2") 24 | 25 | (invoke $M1 "store" (i32.const 0) (i64.const 1)) 26 | (invoke $M2 "store" (i32.const 0) (i64.const 2)) 27 | (assert_return (invoke $M1 "load" (i32.const 0)) (i64.const 1)) 28 | (assert_return (invoke $M2 "load" (i32.const 0)) (i64.const 2)) 29 | 30 | (module 31 | (memory $mem1 (import "M1" "mem") 1) 32 | (memory $mem2 (import "M2" "mem") 1) 33 | 34 | (func (export "load1") (param i32) (result i64) 35 | (i64.load $mem1 (local.get 0)) 36 | ) 37 | (func (export "load2") (param i32) (result i64) 38 | (i64.load $mem2 (local.get 0)) 39 | ) 40 | 41 | (func (export "store1") (param i32 i64) 42 | (i64.store $mem1 (local.get 0) (local.get 1)) 43 | ) 44 | (func (export "store2") (param i32 i64) 45 | (i64.store $mem2 (local.get 0) (local.get 1)) 46 | ) 47 | ) 48 | 49 | (invoke "store1" (i32.const 0) (i64.const 1)) 50 | (invoke "store2" (i32.const 0) (i64.const 2)) 51 | (assert_return (invoke "load1" (i32.const 0)) (i64.const 1)) 52 | (assert_return (invoke "load2" (i32.const 0)) (i64.const 2)) 53 | -------------------------------------------------------------------------------- /test/core/multi-memory/traps0.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (memory $mem0 1) 3 | (memory $mem1 1) 4 | (memory $mem2 1) 5 | 6 | (func (export "no_dce.i32.load") (param $i i32) (drop (i32.load $mem1 (local.get $i)))) 7 | (func (export "no_dce.i32.load16_s") (param $i i32) (drop (i32.load16_s $mem1 (local.get $i)))) 8 | (func (export "no_dce.i32.load16_u") (param $i i32) (drop (i32.load16_u $mem1 (local.get $i)))) 9 | (func (export "no_dce.i32.load8_s") (param $i i32) (drop (i32.load8_s $mem1 (local.get $i)))) 10 | (func (export "no_dce.i32.load8_u") (param $i i32) (drop (i32.load8_u $mem1 (local.get $i)))) 11 | (func (export "no_dce.i64.load") (param $i i32) (drop (i64.load $mem1 (local.get $i)))) 12 | (func (export "no_dce.i64.load32_s") (param $i i32) (drop (i64.load32_s $mem1 (local.get $i)))) 13 | (func (export "no_dce.i64.load32_u") (param $i i32) (drop (i64.load32_u $mem2 (local.get $i)))) 14 | (func (export "no_dce.i64.load16_s") (param $i i32) (drop (i64.load16_s $mem2 (local.get $i)))) 15 | (func (export "no_dce.i64.load16_u") (param $i i32) (drop (i64.load16_u $mem2 (local.get $i)))) 16 | (func (export "no_dce.i64.load8_s") (param $i i32) (drop (i64.load8_s $mem2 (local.get $i)))) 17 | (func (export "no_dce.i64.load8_u") (param $i i32) (drop (i64.load8_u $mem2 (local.get $i)))) 18 | (func (export "no_dce.f32.load") (param $i i32) (drop (f32.load $mem2 (local.get $i)))) 19 | (func (export "no_dce.f64.load") (param $i i32) (drop (f64.load $mem2 (local.get $i)))) 20 | ) 21 | 22 | (assert_trap (invoke "no_dce.i32.load" (i32.const 65536)) "out of bounds memory access") 23 | (assert_trap (invoke "no_dce.i32.load16_s" (i32.const 65536)) "out of bounds memory access") 24 | (assert_trap (invoke "no_dce.i32.load16_u" (i32.const 65536)) "out of bounds memory access") 25 | (assert_trap (invoke "no_dce.i32.load8_s" (i32.const 65536)) "out of bounds memory access") 26 | (assert_trap (invoke "no_dce.i32.load8_u" (i32.const 65536)) "out of bounds memory access") 27 | (assert_trap (invoke "no_dce.i64.load" (i32.const 65536)) "out of bounds memory access") 28 | (assert_trap (invoke "no_dce.i64.load32_s" (i32.const 65536)) "out of bounds memory access") 29 | (assert_trap (invoke "no_dce.i64.load32_u" (i32.const 65536)) "out of bounds memory access") 30 | (assert_trap (invoke "no_dce.i64.load16_s" (i32.const 65536)) "out of bounds memory access") 31 | (assert_trap (invoke "no_dce.i64.load16_u" (i32.const 65536)) "out of bounds memory access") 32 | (assert_trap (invoke "no_dce.i64.load8_s" (i32.const 65536)) "out of bounds memory access") 33 | (assert_trap (invoke "no_dce.i64.load8_u" (i32.const 65536)) "out of bounds memory access") 34 | (assert_trap (invoke "no_dce.f32.load" (i32.const 65536)) "out of bounds memory access") 35 | (assert_trap (invoke "no_dce.f64.load" (i32.const 65536)) "out of bounds memory access") 36 | -------------------------------------------------------------------------------- /test/core/obsolete-keywords.wast: -------------------------------------------------------------------------------- 1 | ;; Renamed in https://github.com/WebAssembly/spec/pull/720 2 | (assert_malformed 3 | (module quote 4 | "(memory 1)" 5 | "(func (drop (current_memory)))" 6 | ) 7 | "unknown operator current_memory" 8 | ) 9 | 10 | (assert_malformed 11 | (module quote 12 | "(memory 1)" 13 | "(func (drop (grow_memory (i32.const 0))))" 14 | ) 15 | "unknown operator grow_memory" 16 | ) 17 | 18 | ;; Renamed in https://github.com/WebAssembly/spec/pull/926 19 | (assert_malformed 20 | (module quote 21 | "(func (local $i i32) (drop (get_local $i)))" 22 | ) 23 | "unknown operator get_local" 24 | ) 25 | 26 | (assert_malformed 27 | (module quote 28 | "(func (local $i i32) (set_local $i (i32.const 0)))" 29 | ) 30 | "unknown operator set_local" 31 | ) 32 | 33 | (assert_malformed 34 | (module quote 35 | "(func (local $i i32) (drop (tee_local $i (i32.const 0))))" 36 | ) 37 | "unknown operator tee_local" 38 | ) 39 | 40 | (assert_malformed 41 | (module quote 42 | "(global $g anyfunc (ref.null func))" 43 | ) 44 | "unknown operator anyfunc" 45 | ) 46 | 47 | (assert_malformed 48 | (module quote 49 | "(global $g i32 (i32.const 0))" 50 | "(func (drop (get_global $g)))" 51 | ) 52 | "unknown operator get_global" 53 | ) 54 | 55 | (assert_malformed 56 | (module quote 57 | "(global $g (mut i32) (i32.const 0))" 58 | "(func (set_global $g (i32.const 0)))" 59 | ) 60 | "unknown operator set_global" 61 | ) 62 | 63 | (assert_malformed 64 | (module quote 65 | "(func (drop (i32.wrap/i64 (i64.const 0))))" 66 | ) 67 | "unknown operator i32.wrap/i64" 68 | ) 69 | 70 | (assert_malformed 71 | (module quote 72 | "(func (drop (i32.trunc_s:sat/f32 (f32.const 0))))" 73 | ) 74 | "unknown operator i32.trunc_s:sat/f32" 75 | ) 76 | 77 | (assert_malformed 78 | (module quote 79 | "(func (drop (f32x4.convert_s/i32x4 (v128.const i64x2 0 0))))" 80 | ) 81 | "unknown operator f32x4.convert_s/i32x4" 82 | ) 83 | -------------------------------------------------------------------------------- /test/core/ref_is_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func $f1 (export "funcref") (param $x funcref) (result i32) 3 | (ref.is_null (local.get $x)) 4 | ) 5 | (func $f2 (export "externref") (param $x externref) (result i32) 6 | (ref.is_null (local.get $x)) 7 | ) 8 | 9 | (table $t1 2 funcref) 10 | (table $t2 2 externref) 11 | (elem (table $t1) (i32.const 1) func $dummy) 12 | (func $dummy) 13 | 14 | (func (export "init") (param $r externref) 15 | (table.set $t2 (i32.const 1) (local.get $r)) 16 | ) 17 | (func (export "deinit") 18 | (table.set $t1 (i32.const 1) (ref.null func)) 19 | (table.set $t2 (i32.const 1) (ref.null extern)) 20 | ) 21 | 22 | (func (export "funcref-elem") (param $x i32) (result i32) 23 | (call $f1 (table.get $t1 (local.get $x))) 24 | ) 25 | (func (export "externref-elem") (param $x i32) (result i32) 26 | (call $f2 (table.get $t2 (local.get $x))) 27 | ) 28 | ) 29 | 30 | (assert_return (invoke "funcref" (ref.null func)) (i32.const 1)) 31 | (assert_return (invoke "externref" (ref.null extern)) (i32.const 1)) 32 | 33 | (assert_return (invoke "externref" (ref.extern 1)) (i32.const 0)) 34 | 35 | (invoke "init" (ref.extern 0)) 36 | 37 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 38 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 39 | 40 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 0)) 41 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 0)) 42 | 43 | (invoke "deinit") 44 | 45 | (assert_return (invoke "funcref-elem" (i32.const 0)) (i32.const 1)) 46 | (assert_return (invoke "externref-elem" (i32.const 0)) (i32.const 1)) 47 | 48 | (assert_return (invoke "funcref-elem" (i32.const 1)) (i32.const 1)) 49 | (assert_return (invoke "externref-elem" (i32.const 1)) (i32.const 1)) 50 | 51 | (assert_invalid 52 | (module (func $ref-vs-num (param i32) (ref.is_null (local.get 0)))) 53 | "type mismatch" 54 | ) 55 | (assert_invalid 56 | (module (func $ref-vs-empty (ref.is_null))) 57 | "type mismatch" 58 | ) 59 | -------------------------------------------------------------------------------- /test/core/ref_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func (export "externref") (result externref) (ref.null extern)) 3 | (func (export "funcref") (result funcref) (ref.null func)) 4 | 5 | (global externref (ref.null extern)) 6 | (global funcref (ref.null func)) 7 | ) 8 | 9 | (assert_return (invoke "externref") (ref.null extern)) 10 | (assert_return (invoke "funcref") (ref.null func)) 11 | -------------------------------------------------------------------------------- /test/core/simd/meta/README.md: -------------------------------------------------------------------------------- 1 | # Generated SIMD Spec Tests from gen_tests.py 2 | 3 | `gen_tests.py` builds partial SIMD spec tests using templates in `simd_*.py`. 4 | Currently it only support following simd test files generation. 5 | 6 | - 'simd_i8x16_cmp.wast' 7 | - 'simd_i16x8_cmp.wast' 8 | - 'simd_i32x4_cmp.wast' 9 | - 'simd_f32x4_cmp.wast' 10 | - 'simd_f64x2_cmp.wast' 11 | - 'simd_i8x16_arith.wast' 12 | - 'simd_i8x16_arith2.wast' 13 | - 'simd_i16x8_arith.wast' 14 | - 'simd_i16x8_arith2.wast' 15 | - 'simd_i32x4_arith.wast' 16 | - 'simd_i32x4_arith2.wast' 17 | - 'simd_f32x4_arith.wast' 18 | - 'simd_i64x2_arith.wast' 19 | - 'simd_f64x2_arith.wast' 20 | - 'simd_bitwise.wast' 21 | - 'simd_i8x16_sat_arith.wast' 22 | - 'simd_i16x8_sat_arith.wast' 23 | - 'simd_f32x4.wast' 24 | - 'simd_f64x2.wast' 25 | - 'simd_f32x4_rounding.wast' 26 | - 'simd_f64x2_rounding.wast' 27 | - 'simd_f32x4_pmin_pmax.wast' 28 | - 'simd_f64x2_pmin_pmax.wast' 29 | - 'simd_i32x4_dot_i16x8.wast' 30 | - 'simd_load8_lane.wast' 31 | - 'simd_load16_lane.wast' 32 | - 'simd_load32_lane.wast' 33 | - 'simd_load64_lane.wast, 34 | - 'simd_store8_lane.wast' 35 | - 'simd_store16_lane.wast' 36 | - 'simd_store32_lane.wast' 37 | - 'simd_store64_lane.wast, 38 | - 'simd_i16x8_extmul_i8x16.wast' 39 | - 'simd_i32x4_extmul_i16x8.wast' 40 | - 'simd_i64x2_extmul_i32x4.wast' 41 | - 'simd_int_to_int_widen.wast' 42 | - 'simd_i32x4_trunc_sat_f32x4.wast' 43 | - 'simd_i32x4_trunc_sat_f64x2.wast' 44 | - 'simd_i16x8_q15mulr_sat_s.wast', 45 | - 'simd_i16x8_extadd_pairwise_i8x16.wast', 46 | - 'simd_i32x4_extadd_pairwise_i16x8.wast', 47 | 48 | 49 | Usage: 50 | 51 | ``` 52 | $ python gen_tests.py -a 53 | ``` 54 | 55 | This script requires Python 3.6+, more details are documented in `gen_tests.py`. 56 | -------------------------------------------------------------------------------- /test/core/simd/meta/gen_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | This script is used for generating WebAssembly SIMD test cases. 5 | It requires Python 3.6+. 6 | """ 7 | import sys 8 | import argparse 9 | import importlib 10 | 11 | 12 | SUBMODULES = ( 13 | 'simd_i8x16_cmp', 14 | 'simd_i16x8_cmp', 15 | 'simd_i32x4_cmp', 16 | 'simd_i64x2_cmp', 17 | 'simd_f32x4_cmp', 18 | 'simd_f64x2_cmp', 19 | 'simd_i8x16_arith', 20 | 'simd_i16x8_arith', 21 | 'simd_i32x4_arith', 22 | 'simd_f32x4_arith', 23 | 'simd_i64x2_arith', 24 | 'simd_f64x2_arith', 25 | 'simd_sat_arith', 26 | 'simd_bitwise', 27 | 'simd_f32x4', 28 | 'simd_f64x2', 29 | 'simd_int_arith2', 30 | 'simd_f32x4_rounding', 31 | 'simd_f64x2_rounding', 32 | 'simd_f32x4_pmin_pmax', 33 | 'simd_f64x2_pmin_pmax', 34 | 'simd_i32x4_dot_i16x8', 35 | 'simd_load_lane', 36 | 'simd_store_lane', 37 | 'simd_ext_mul', 38 | 'simd_int_to_int_extend', 39 | 'simd_int_trunc_sat_float', 40 | 'simd_i16x8_q15mulr_sat_s', 41 | 'simd_extadd_pairwise', 42 | ) 43 | 44 | 45 | def gen_group_tests(mod_name): 46 | """mod_name is the back-end script name without the.py extension. 47 | There must be a gen_test_cases() function in each module.""" 48 | mod = importlib.import_module(mod_name) 49 | mod.gen_test_cases() 50 | 51 | 52 | def main(): 53 | """ 54 | Default program entry 55 | """ 56 | 57 | parser = argparse.ArgumentParser( 58 | description='Front-end script to call other modules to generate SIMD tests') 59 | parser.add_argument('-a', '--all', dest='gen_all', action='store_true', 60 | default=False, help='Generate all the tests') 61 | parser.add_argument('-i', '--inst', dest='inst_group', choices=SUBMODULES, 62 | help='Back-end scripts that generate the SIMD tests') 63 | args = parser.parse_args() 64 | 65 | if len(sys.argv) < 2: 66 | parser.print_help() 67 | 68 | if args.inst_group: 69 | gen_group_tests(args.inst_group) 70 | if args.gen_all: 71 | for mod_name in SUBMODULES: 72 | gen_group_tests(mod_name) 73 | 74 | 75 | if __name__ == '__main__': 76 | main() 77 | print('Done.') 78 | -------------------------------------------------------------------------------- /test/core/simd/meta/simd_ext_mul.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ Base class for generating extended multiply instructions. These 4 | instructions 2 inputs of the same (narrower) lane shape, multiplies 5 | corresponding lanes with extension (no overflow/wraparound), producing 1 output 6 | of a (wider) shape. These instructions can choose to work on the low or high 7 | halves of the inputs, and perform signed or unsigned multiply. 8 | 9 | Subclasses need to define 3 attributes: 10 | - LANE_TYPE (this is the output shape) 11 | - SRC_LANE_TYPE (this is the input (narrower) shape) 12 | - BINARY_OPS (list of operations) 13 | """ 14 | 15 | from simd_arithmetic import SimdArithmeticCase 16 | 17 | 18 | class SimdExtMulCase(SimdArithmeticCase): 19 | UNARY_OPS = () 20 | 21 | @property 22 | def full_bin_test_data(self): 23 | return [] 24 | 25 | def get_combine_cases(self): 26 | return '' 27 | 28 | @property 29 | def bin_test_data(self): 30 | lane_forms = [self.SRC_LANE_TYPE, self.SRC_LANE_TYPE, self.LANE_TYPE] 31 | return [(self.normal_binary_op_test_data, lane_forms)] 32 | 33 | @property 34 | def hex_binary_op_test_data(self): 35 | return [] 36 | 37 | def gen_test_cases(self): 38 | wast_filename = '../simd_{wide}_extmul_{narrow}.wast'.format( 39 | wide=self.LANE_TYPE, narrow=self.SRC_LANE_TYPE) 40 | with open(wast_filename, 'w') as fp: 41 | fp.write(self.get_all_cases()) 42 | 43 | 44 | class SimdI16x8ExtMulCase(SimdExtMulCase): 45 | LANE_TYPE = 'i16x8' 46 | SRC_LANE_TYPE = 'i8x16' 47 | BINARY_OPS = ('extmul_low_i8x16_s', 'extmul_high_i8x16_s', 48 | 'extmul_low_i8x16_u', 'extmul_high_i8x16_u') 49 | 50 | 51 | class SimdI32x4ExtMulCase(SimdExtMulCase): 52 | LANE_TYPE = 'i32x4' 53 | SRC_LANE_TYPE = 'i16x8' 54 | BINARY_OPS = ('extmul_low_i16x8_s', 'extmul_high_i16x8_s', 55 | 'extmul_low_i16x8_u', 'extmul_high_i16x8_u') 56 | 57 | 58 | class SimdI64x2ExtMulCase(SimdExtMulCase): 59 | LANE_TYPE = 'i64x2' 60 | SRC_LANE_TYPE = 'i32x4' 61 | BINARY_OPS = ('extmul_low_i32x4_s', 'extmul_high_i32x4_s', 62 | 'extmul_low_i32x4_u', 'extmul_high_i32x4_u') 63 | 64 | 65 | def gen_test_cases(): 66 | simd_i16x8_ext_mul_case = SimdI16x8ExtMulCase() 67 | simd_i16x8_ext_mul_case.gen_test_cases() 68 | simd_i32x4_ext_mul_case = SimdI32x4ExtMulCase() 69 | simd_i32x4_ext_mul_case.gen_test_cases() 70 | simd_i64x2_ext_mul_case = SimdI64x2ExtMulCase() 71 | simd_i64x2_ext_mul_case.gen_test_cases() 72 | 73 | 74 | if __name__ == '__main__': 75 | gen_test_cases() 76 | -------------------------------------------------------------------------------- /test/core/simd/meta/simd_extadd_pairwise.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from simd_arithmetic import SimdArithmeticCase, i16 4 | from simd_integer_op import ArithmeticOp 5 | 6 | 7 | class SimdExtAddPairwise(SimdArithmeticCase): 8 | BINARY_OPS = () 9 | 10 | def unary_op(self, x, signed): 11 | # For test data we always splat a single value to the 12 | # entire v128, so doubling the input works. 13 | return ArithmeticOp.get_valid_value(x, self.src_lane, signed=signed) * 2 14 | 15 | @property 16 | def hex_unary_op_test_data(self): 17 | return [] 18 | 19 | @property 20 | def unary_test_data(self): 21 | return [ 22 | (self.normal_unary_op_test_data, [self.SRC_LANE_TYPE,self.LANE_TYPE]), 23 | ] 24 | 25 | def get_case_data(self): 26 | case_data = [] 27 | for op in self.UNARY_OPS: 28 | op_name = self.op_name(op) 29 | case_data.append(['#', op_name]) 30 | for data_group, v128_forms in self.unary_test_data: 31 | for data in data_group: 32 | case_data.append([op_name, [str(data)], 33 | str(self.unary_op(data, op.endswith('s'))), 34 | v128_forms]) 35 | return case_data 36 | 37 | def get_combine_cases(self): 38 | return '' 39 | 40 | def gen_test_cases(self): 41 | wast_filename = '../simd_{}_extadd_pairwise_{}.wast'.format(self.LANE_TYPE, self.SRC_LANE_TYPE) 42 | with open(wast_filename, 'w') as fp: 43 | fp.write(self.get_all_cases()) 44 | 45 | class SimdI16x8ExtAddPairwise(SimdExtAddPairwise): 46 | UNARY_OPS = ('extadd_pairwise_i8x16_s','extadd_pairwise_i8x16_u') 47 | LANE_TYPE = 'i16x8' 48 | SRC_LANE_TYPE = 'i8x16' 49 | 50 | class SimdI32x4ExtAddPairwise(SimdExtAddPairwise): 51 | UNARY_OPS = ('extadd_pairwise_i16x8_s','extadd_pairwise_i16x8_u') 52 | LANE_TYPE = 'i32x4' 53 | SRC_LANE_TYPE = 'i16x8' 54 | 55 | def gen_test_cases(): 56 | simd_i16x8_arith = SimdI16x8ExtAddPairwise() 57 | simd_i32x4_arith = SimdI32x4ExtAddPairwise() 58 | simd_i16x8_arith.gen_test_cases() 59 | simd_i32x4_arith.gen_test_cases() 60 | 61 | if __name__ == '__main__': 62 | gen_test_cases() 63 | -------------------------------------------------------------------------------- /test/core/simd/meta/simd_f64x2_pmin_pmax.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Generate f64x2 [pmin, pmax] cases. 5 | """ 6 | 7 | from simd_f32x4_pmin_pmax import Simdf32x4PminPmaxCase 8 | from simd_f64x2_arith import Simdf64x2ArithmeticCase 9 | from simd_float_op import FloatingPointSimpleOp 10 | from simd import SIMD 11 | from test_assert import AssertReturn 12 | 13 | 14 | class Simdf64x2PminPmaxCase(Simdf32x4PminPmaxCase): 15 | LANE_TYPE = 'f64x2' 16 | FLOAT_NUMBERS = Simdf64x2ArithmeticCase.FLOAT_NUMBERS 17 | LITERAL_NUMBERS = Simdf64x2ArithmeticCase.LITERAL_NUMBERS 18 | NAN_NUMBERS = Simdf64x2ArithmeticCase.NAN_NUMBERS 19 | 20 | 21 | def gen_test_cases(): 22 | simd_f64x2_pmin_pmax_case = Simdf64x2PminPmaxCase() 23 | simd_f64x2_pmin_pmax_case.gen_test_cases() 24 | 25 | 26 | if __name__ == '__main__': 27 | gen_test_cases() 28 | -------------------------------------------------------------------------------- /test/core/simd/meta/simd_f64x2_rounding.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | Generate f64x2 [ceil, floor, trunc, nearest] cases. 5 | """ 6 | 7 | from simd_f32x4_rounding import Simdf32x4RoundingCase 8 | from simd_f64x2 import Simdf64x2Case 9 | from simd_f64x2_arith import Simdf64x2ArithmeticCase 10 | from simd_float_op import FloatingPointRoundingOp 11 | from simd import SIMD 12 | from test_assert import AssertReturn 13 | 14 | 15 | class Simdf64x2RoundingCase(Simdf32x4RoundingCase): 16 | 17 | LANE_TYPE = 'f64x2' 18 | FLOAT_NUMBERS = Simdf64x2ArithmeticCase.FLOAT_NUMBERS 19 | LITERAL_NUMBERS = Simdf64x2ArithmeticCase.LITERAL_NUMBERS 20 | NAN_NUMBERS = Simdf64x2ArithmeticCase.NAN_NUMBERS 21 | 22 | 23 | def gen_test_cases(): 24 | simd_f64x2_case = Simdf64x2RoundingCase() 25 | simd_f64x2_case.gen_test_cases() 26 | 27 | 28 | if __name__ == '__main__': 29 | gen_test_cases() 30 | -------------------------------------------------------------------------------- /test/core/simd/meta/simd_i16x8_q15mulr_sat_s.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from simd_arithmetic import SimdArithmeticCase 4 | 5 | 6 | """Generate test cases for i16x8.mulr_sat_s 7 | """ 8 | class SimdI16x8Q15MulRSatS(SimdArithmeticCase): 9 | LANE_TYPE = 'i16x8' 10 | UNARY_OPS = () 11 | BINARY_OPS = ('q15mulr_sat_s',) 12 | 13 | @property 14 | def full_bin_test_data(self): 15 | return [] 16 | 17 | @property 18 | def hex_binary_op_test_data(self): 19 | return [] 20 | 21 | def get_combine_cases(self): 22 | return '' 23 | 24 | def gen_test_cases(self): 25 | wast_filename = '../simd_i16x8_q15mulr_sat_s.wast' 26 | with open(wast_filename, 'w') as fp: 27 | fp.write(self.get_all_cases()) 28 | 29 | 30 | def gen_test_cases(): 31 | simd_i16x8_q16mulr_sat_s = SimdI16x8Q15MulRSatS() 32 | simd_i16x8_q16mulr_sat_s.gen_test_cases() 33 | 34 | 35 | if __name__ == '__main__': 36 | gen_test_cases() 37 | -------------------------------------------------------------------------------- /test/core/simd/meta/simd_i32x4_dot_i16x8.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from simd_arithmetic import SimdArithmeticCase, i16 4 | from simd_integer_op import ArithmeticOp 5 | 6 | 7 | class SimdI32x4DotI16x8TestCase(SimdArithmeticCase): 8 | LANE_TYPE = 'i32x4' 9 | UNARY_OPS = () 10 | BINARY_OPS = ('dot_i16x8_s',) 11 | 12 | @property 13 | def lane(self): 14 | return i16 15 | 16 | def binary_op(self, x, y, lane): 17 | # For test data we always splat a single value to the 18 | # entire v128, so '* 2' will work here. 19 | return ArithmeticOp.get_valid_value(x, i16) * ArithmeticOp.get_valid_value(y, i16) * 2 20 | 21 | @property 22 | def hex_binary_op_test_data(self): 23 | return [] 24 | 25 | @property 26 | def bin_test_data(self): 27 | return [ 28 | (self.normal_binary_op_test_data, ['i16x8', 'i16x8', 'i32x4']), 29 | (self.hex_binary_op_test_data, ['i16x8', 'i16x8', 'i32x4']) 30 | ] 31 | 32 | def get_case_data(self): 33 | case_data = [] 34 | op_name = 'i32x4.dot_i16x8_s' 35 | case_data.append(['#', op_name]) 36 | for data_group, v128_forms in self.bin_test_data: 37 | for data in data_group: 38 | case_data.append([op_name, [str(data[0]), str(data[1])], 39 | str(self.binary_op(data[0], data[1], self.lane)), 40 | v128_forms]) 41 | return case_data 42 | 43 | def get_combine_cases(self): 44 | return '' 45 | 46 | def gen_test_cases(self): 47 | wast_filename = '../simd_i32x4_dot_i16x8.wast' 48 | with open(wast_filename, 'w') as fp: 49 | fp.write(self.get_all_cases()) 50 | 51 | def gen_test_cases(): 52 | simd_i16x8_arith = SimdI32x4DotI16x8TestCase() 53 | simd_i16x8_arith.gen_test_cases() 54 | 55 | if __name__ == '__main__': 56 | gen_test_cases() 57 | -------------------------------------------------------------------------------- /test/core/simd/meta/simd_lane_value.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | 4 | class LaneValue: 5 | """This class stands for the value of signed integer represented by a lane in v128. 6 | Suppose a bit number of the lane is n, then: 7 | For signed integer: 8 | minimum = -pow(2, n - 1), maximum = pow(2, n - 1) - 1 9 | The bit number of the lane can be 8, 16, 32, 64""" 10 | def __init__(self, lane_width): 11 | """lane_width: bit number of each lane in SIMD v128""" 12 | self.lane_width = lane_width 13 | 14 | @property 15 | def min(self): 16 | return -pow(2, self.lane_width - 1) 17 | 18 | @property 19 | def max(self): 20 | return pow(2, self.lane_width - 1) - 1 21 | 22 | @property 23 | def mask(self): 24 | return pow(2, self.lane_width) - 1 25 | 26 | @property 27 | def mod(self): 28 | return pow(2, self.lane_width) 29 | 30 | @property 31 | def quarter(self): 32 | return pow(2, self.lane_width - 2) 33 | 34 | def sat_s(self, v): 35 | return max(self.min, min(v, self.max)) 36 | 37 | def sat_u(self, v): 38 | return max(0, min(v, self.mask)) 39 | -------------------------------------------------------------------------------- /test/core/simd/simd_linking.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (global (export "g-v128") v128 (v128.const i64x2 0 0)) 3 | (global (export "mg-v128") (mut v128) (v128.const i64x2 0 0)) 4 | ) 5 | (register "Mv128") 6 | 7 | (module 8 | ;; TODO: Reactivate once the fix for https://bugs.chromium.org/p/v8/issues/detail?id=13732 9 | ;; has made it to the downstream node.js that we use on CI. 10 | ;; (import "Mv128" "g-v128" (global v128)) 11 | (import "Mv128" "mg-v128" (global (mut v128))) 12 | ) 13 | -------------------------------------------------------------------------------- /test/core/simd/simd_memory-multi.wast: -------------------------------------------------------------------------------- 1 | ;; From wasmtime misc_testsuite/multi-memory/simple.wast 2 | 3 | ;; Test syntax for load/store_lane immediates 4 | 5 | (module 6 | (memory 1) 7 | (memory $m 1) 8 | 9 | (func 10 | (local $v v128) 11 | 12 | (drop (v128.load8_lane 1 (i32.const 0) (local.get $v))) 13 | (drop (v128.load8_lane 1 offset=0 1 (i32.const 0) (local.get $v))) 14 | (drop (v128.load8_lane 1 offset=0 align=1 1 (i32.const 0) (local.get $v))) 15 | (drop (v128.load8_lane 1 align=1 1 (i32.const 0) (local.get $v))) 16 | 17 | (drop (v128.load8_lane $m 1 (i32.const 0) (local.get $v))) 18 | (drop (v128.load8_lane $m offset=0 1 (i32.const 0) (local.get $v))) 19 | (drop (v128.load8_lane $m offset=0 align=1 1 (i32.const 0) (local.get $v))) 20 | (drop (v128.load8_lane $m align=1 1 (i32.const 0) (local.get $v))) 21 | 22 | (drop (v128.load8_lane 1 1 (i32.const 0) (local.get $v))) 23 | (drop (v128.load8_lane 1 offset=0 1 (i32.const 0) (local.get $v))) 24 | (drop (v128.load8_lane 1 offset=0 align=1 1 (i32.const 0) (local.get $v))) 25 | (drop (v128.load8_lane 1 align=1 1 (i32.const 0) (local.get $v))) 26 | 27 | (v128.store8_lane 1 (i32.const 0) (local.get $v)) 28 | (v128.store8_lane offset=0 1 (i32.const 0) (local.get $v)) 29 | (v128.store8_lane offset=0 align=1 1 (i32.const 0) (local.get $v)) 30 | (v128.store8_lane align=1 1 (i32.const 0) (local.get $v)) 31 | 32 | (v128.store8_lane $m 1 (i32.const 0) (local.get $v)) 33 | (v128.store8_lane $m offset=0 1 (i32.const 0) (local.get $v)) 34 | (v128.store8_lane $m offset=0 align=1 1 (i32.const 0) (local.get $v)) 35 | (v128.store8_lane $m align=1 1 (i32.const 0) (local.get $v)) 36 | 37 | (v128.store8_lane 1 1 (i32.const 0) (local.get $v)) 38 | (v128.store8_lane 1 offset=0 1 (i32.const 0) (local.get $v)) 39 | (v128.store8_lane 1 offset=0 align=1 1 (i32.const 0) (local.get $v)) 40 | (v128.store8_lane 1 align=1 1 (i32.const 0) (local.get $v)) 41 | ) 42 | ) 43 | -------------------------------------------------------------------------------- /test/core/start.wast: -------------------------------------------------------------------------------- 1 | (assert_invalid 2 | (module (func) (start 1)) 3 | "unknown function" 4 | ) 5 | 6 | (assert_invalid 7 | (module 8 | (func $main (result i32) (return (i32.const 0))) 9 | (start $main) 10 | ) 11 | "start function" 12 | ) 13 | (assert_invalid 14 | (module 15 | (func $main (param $a i32)) 16 | (start $main) 17 | ) 18 | "start function" 19 | ) 20 | 21 | (module 22 | (memory (data "A")) 23 | (func $inc 24 | (i32.store8 25 | (i32.const 0) 26 | (i32.add 27 | (i32.load8_u (i32.const 0)) 28 | (i32.const 1) 29 | ) 30 | ) 31 | ) 32 | (func $get (result i32) 33 | (return (i32.load8_u (i32.const 0))) 34 | ) 35 | (func $main 36 | (call $inc) 37 | (call $inc) 38 | (call $inc) 39 | ) 40 | 41 | (start $main) 42 | (export "inc" (func $inc)) 43 | (export "get" (func $get)) 44 | ) 45 | (assert_return (invoke "get") (i32.const 68)) 46 | (invoke "inc") 47 | (assert_return (invoke "get") (i32.const 69)) 48 | (invoke "inc") 49 | (assert_return (invoke "get") (i32.const 70)) 50 | 51 | (module 52 | (memory (data "A")) 53 | (func $inc 54 | (i32.store8 55 | (i32.const 0) 56 | (i32.add 57 | (i32.load8_u (i32.const 0)) 58 | (i32.const 1) 59 | ) 60 | ) 61 | ) 62 | (func $get (result i32) 63 | (return (i32.load8_u (i32.const 0))) 64 | ) 65 | (func $main 66 | (call $inc) 67 | (call $inc) 68 | (call $inc) 69 | ) 70 | (start 2) 71 | (export "inc" (func $inc)) 72 | (export "get" (func $get)) 73 | ) 74 | (assert_return (invoke "get") (i32.const 68)) 75 | (invoke "inc") 76 | (assert_return (invoke "get") (i32.const 69)) 77 | (invoke "inc") 78 | (assert_return (invoke "get") (i32.const 70)) 79 | 80 | (module 81 | (func $print_i32 (import "spectest" "print_i32") (param i32)) 82 | (func $main (call $print_i32 (i32.const 1))) 83 | (start 1) 84 | ) 85 | 86 | (module 87 | (func $print_i32 (import "spectest" "print_i32") (param i32)) 88 | (func $main (call $print_i32 (i32.const 2))) 89 | (start $main) 90 | ) 91 | 92 | (module 93 | (func $print (import "spectest" "print")) 94 | (start $print) 95 | ) 96 | 97 | (assert_trap 98 | (module (func $main (unreachable)) (start $main)) 99 | "unreachable" 100 | ) 101 | 102 | (assert_malformed 103 | (module quote "(module (func $a (unreachable)) (func $b (unreachable)) (start $a) (start $b))") 104 | "multiple start sections" 105 | ) 106 | -------------------------------------------------------------------------------- /test/core/table-sub.wast: -------------------------------------------------------------------------------- 1 | (assert_invalid 2 | (module 3 | (table $t1 10 funcref) 4 | (table $t2 10 externref) 5 | (func $f 6 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 7 | ) 8 | ) 9 | "type mismatch" 10 | ) 11 | 12 | (assert_invalid 13 | (module 14 | (table $t 10 funcref) 15 | (elem $el externref) 16 | (func $f 17 | (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) 18 | ) 19 | ) 20 | "type mismatch" 21 | ) 22 | -------------------------------------------------------------------------------- /test/core/table.wast: -------------------------------------------------------------------------------- 1 | ;; Test table section structure 2 | 3 | (module (table 0 funcref)) 4 | (module (table 1 funcref)) 5 | (module (table 0 0 funcref)) 6 | (module (table 0 1 funcref)) 7 | (module (table 1 256 funcref)) 8 | (module (table 0 65536 funcref)) 9 | (module (table 0 0xffff_ffff funcref)) 10 | 11 | (module (table 0 funcref) (table 0 funcref)) 12 | (module (table (import "spectest" "table") 0 funcref) (table 0 funcref)) 13 | 14 | (assert_invalid (module (elem (i32.const 0))) "unknown table") 15 | (assert_invalid (module (elem (i32.const 0) $f) (func $f)) "unknown table") 16 | 17 | 18 | (assert_invalid 19 | (module (table 1 0 funcref)) 20 | "size minimum must not be greater than maximum" 21 | ) 22 | (assert_invalid 23 | (module (table 0xffff_ffff 0 funcref)) 24 | "size minimum must not be greater than maximum" 25 | ) 26 | 27 | (assert_malformed 28 | (module quote "(table 0x1_0000_0000 funcref)") 29 | "i32 constant out of range" 30 | ) 31 | (assert_malformed 32 | (module quote "(table 0x1_0000_0000 0x1_0000_0000 funcref)") 33 | "i32 constant out of range" 34 | ) 35 | (assert_malformed 36 | (module quote "(table 0 0x1_0000_0000 funcref)") 37 | "i32 constant out of range" 38 | ) 39 | 40 | 41 | ;; Duplicate table identifiers 42 | 43 | (assert_malformed (module quote 44 | "(table $foo 1 funcref)" 45 | "(table $foo 1 funcref)") 46 | "duplicate table") 47 | (assert_malformed (module quote 48 | "(import \"\" \"\" (table $foo 1 funcref))" 49 | "(table $foo 1 funcref)") 50 | "duplicate table") 51 | (assert_malformed (module quote 52 | "(import \"\" \"\" (table $foo 1 funcref))" 53 | "(import \"\" \"\" (table $foo 1 funcref))") 54 | "duplicate table") 55 | -------------------------------------------------------------------------------- /test/core/table_get.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (table $t2 2 externref) 3 | (table $t3 3 funcref) 4 | (elem (table $t3) (i32.const 1) func $dummy) 5 | (func $dummy) 6 | 7 | (func (export "init") (param $r externref) 8 | (table.set $t2 (i32.const 1) (local.get $r)) 9 | (table.set $t3 (i32.const 2) (table.get $t3 (i32.const 1))) 10 | ) 11 | 12 | (func (export "get-externref") (param $i i32) (result externref) 13 | (table.get (local.get $i)) 14 | ) 15 | (func $f3 (export "get-funcref") (param $i i32) (result funcref) 16 | (table.get $t3 (local.get $i)) 17 | ) 18 | 19 | (func (export "is_null-funcref") (param $i i32) (result i32) 20 | (ref.is_null (call $f3 (local.get $i))) 21 | ) 22 | ) 23 | 24 | (invoke "init" (ref.extern 1)) 25 | 26 | (assert_return (invoke "get-externref" (i32.const 0)) (ref.null extern)) 27 | (assert_return (invoke "get-externref" (i32.const 1)) (ref.extern 1)) 28 | 29 | (assert_return (invoke "get-funcref" (i32.const 0)) (ref.null func)) 30 | (assert_return (invoke "is_null-funcref" (i32.const 1)) (i32.const 0)) 31 | (assert_return (invoke "is_null-funcref" (i32.const 2)) (i32.const 0)) 32 | 33 | (assert_trap (invoke "get-externref" (i32.const 2)) "out of bounds table access") 34 | (assert_trap (invoke "get-funcref" (i32.const 3)) "out of bounds table access") 35 | (assert_trap (invoke "get-externref" (i32.const -1)) "out of bounds table access") 36 | (assert_trap (invoke "get-funcref" (i32.const -1)) "out of bounds table access") 37 | 38 | 39 | ;; Type errors 40 | 41 | (assert_invalid 42 | (module 43 | (table $t 10 externref) 44 | (func $type-index-empty-vs-i32 (result externref) 45 | (table.get $t) 46 | ) 47 | ) 48 | "type mismatch" 49 | ) 50 | (assert_invalid 51 | (module 52 | (table $t 10 externref) 53 | (func $type-index-f32-vs-i32 (result externref) 54 | (table.get $t (f32.const 1)) 55 | ) 56 | ) 57 | "type mismatch" 58 | ) 59 | 60 | (assert_invalid 61 | (module 62 | (table $t 10 externref) 63 | (func $type-result-externref-vs-empty 64 | (table.get $t (i32.const 0)) 65 | ) 66 | ) 67 | "type mismatch" 68 | ) 69 | (assert_invalid 70 | (module 71 | (table $t 10 externref) 72 | (func $type-result-externref-vs-funcref (result funcref) 73 | (table.get $t (i32.const 1)) 74 | ) 75 | ) 76 | "type mismatch" 77 | ) 78 | 79 | (assert_invalid 80 | (module 81 | (table $t1 1 funcref) 82 | (table $t2 1 externref) 83 | (func $type-result-externref-vs-funcref-multi (result funcref) 84 | (table.get $t2 (i32.const 0)) 85 | ) 86 | ) 87 | "type mismatch" 88 | ) 89 | -------------------------------------------------------------------------------- /test/core/type.wast: -------------------------------------------------------------------------------- 1 | ;; Test type definitions 2 | 3 | (module 4 | (type (func)) 5 | (type $t (func)) 6 | 7 | (type (func (param i32))) 8 | (type (func (param $x i32))) 9 | (type (func (result i32))) 10 | (type (func (param i32) (result i32))) 11 | (type (func (param $x i32) (result i32))) 12 | 13 | (type (func (param f32 f64))) 14 | (type (func (result i64 f32))) 15 | (type (func (param i32 i64) (result f32 f64))) 16 | 17 | (type (func (param f32) (param f64))) 18 | (type (func (param $x f32) (param f64))) 19 | (type (func (param f32) (param $y f64))) 20 | (type (func (param $x f32) (param $y f64))) 21 | (type (func (result i64) (result f32))) 22 | (type (func (param i32) (param i64) (result f32) (result f64))) 23 | (type (func (param $x i32) (param $y i64) (result f32) (result f64))) 24 | 25 | (type (func (param f32 f64) (param $x i32) (param f64 i32 i32))) 26 | (type (func (result i64 i64 f32) (result f32 i32))) 27 | (type 28 | (func (param i32 i32) (param i64 i32) (result f32 f64) (result f64 i32)) 29 | ) 30 | 31 | (type (func (param) (param $x f32) (param) (param) (param f64 i32) (param))) 32 | (type 33 | (func (result) (result) (result i64 i64) (result) (result f32) (result)) 34 | ) 35 | (type 36 | (func 37 | (param i32 i32) (param i64 i32) (param) (param $x i32) (param) 38 | (result) (result f32 f64) (result f64 i32) (result) 39 | ) 40 | ) 41 | ) 42 | 43 | (assert_malformed 44 | (module quote "(type (func (result i32) (param i32)))") 45 | "unexpected token" 46 | ) 47 | (assert_malformed 48 | (module quote "(type (func (result $x i32)))") 49 | "unexpected token" 50 | ) 51 | -------------------------------------------------------------------------------- /test/core/unreached-valid.wast: -------------------------------------------------------------------------------- 1 | (module 2 | 3 | ;; Check that both sides of the select are evaluated 4 | (func (export "select-trap-left") (param $cond i32) (result i32) 5 | (select (unreachable) (i32.const 0) (local.get $cond)) 6 | ) 7 | (func (export "select-trap-right") (param $cond i32) (result i32) 8 | (select (i32.const 0) (unreachable) (local.get $cond)) 9 | ) 10 | 11 | (func (export "select-unreached") 12 | (unreachable) (select) 13 | (unreachable) (i32.const 0) (select) 14 | (unreachable) (i32.const 0) (i32.const 0) (select) 15 | (unreachable) (i32.const 0) (i32.const 0) (i32.const 0) (select) 16 | (unreachable) (f32.const 0) (i32.const 0) (select) 17 | (unreachable) 18 | ) 19 | 20 | (func (export "select_unreached_result_1") (result i32) 21 | (unreachable) (i32.add (select)) 22 | ) 23 | 24 | (func (export "select_unreached_result_2") (result i64) 25 | (unreachable) (i64.add (select (i64.const 0) (i32.const 0))) 26 | ) 27 | 28 | (func (export "unreachable-num") 29 | (unreachable) 30 | (select) 31 | (i32.eqz) 32 | (drop) 33 | ) 34 | (func (export "unreachable-ref") 35 | (unreachable) 36 | (select) 37 | (ref.is_null) 38 | (drop) 39 | ) 40 | ) 41 | 42 | (assert_trap (invoke "select-trap-left" (i32.const 1)) "unreachable") 43 | (assert_trap (invoke "select-trap-left" (i32.const 0)) "unreachable") 44 | (assert_trap (invoke "select-trap-right" (i32.const 1)) "unreachable") 45 | (assert_trap (invoke "select-trap-right" (i32.const 0)) "unreachable") 46 | 47 | ;; Validation after unreachable 48 | 49 | (module 50 | (func (export "meet-bottom") 51 | (block (result f64) 52 | (block (result f32) 53 | (unreachable) 54 | (br_table 0 1 1 (i32.const 1)) 55 | ) 56 | (drop) 57 | (f64.const 0) 58 | ) 59 | (drop) 60 | ) 61 | ) 62 | 63 | (assert_trap (invoke "meet-bottom") "unreachable") 64 | -------------------------------------------------------------------------------- /test/harness/testharness.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family:DejaVu Sans, Bitstream Vera Sans, Arial, Sans; 3 | } 4 | 5 | #log .warning, 6 | #log .warning a { 7 | color: black; 8 | background: yellow; 9 | } 10 | 11 | #log .error, 12 | #log .error a { 13 | color: white; 14 | background: red; 15 | } 16 | 17 | section#summary { 18 | margin-bottom:1em; 19 | } 20 | 21 | table#results { 22 | border-collapse:collapse; 23 | table-layout:fixed; 24 | width:100%; 25 | } 26 | 27 | table#results th:first-child, 28 | table#results td:first-child { 29 | width:4em; 30 | } 31 | 32 | table#results th:last-child, 33 | table#results td:last-child { 34 | width:50%; 35 | } 36 | 37 | table#results.assertions th:last-child, 38 | table#results.assertions td:last-child { 39 | width:35%; 40 | } 41 | 42 | table#results th { 43 | padding:0; 44 | padding-bottom:0.5em; 45 | border-bottom:medium solid black; 46 | } 47 | 48 | table#results td { 49 | padding:1em; 50 | padding-bottom:0.5em; 51 | border-bottom:thin solid black; 52 | } 53 | 54 | tr.pass > td:first-child { 55 | color:green; 56 | } 57 | 58 | tr.fail > td:first-child { 59 | color:red; 60 | } 61 | 62 | tr.timeout > td:first-child { 63 | color:red; 64 | } 65 | 66 | tr.notrun > td:first-child { 67 | color:blue; 68 | } 69 | 70 | .pass > td:first-child, .fail > td:first-child, .timeout > td:first-child, .notrun > td:first-child { 71 | font-variant:small-caps; 72 | } 73 | 74 | table#results span { 75 | display:block; 76 | } 77 | 78 | table#results span.expected { 79 | font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace; 80 | white-space:pre; 81 | } 82 | 83 | table#results span.actual { 84 | font-family:DejaVu Sans Mono, Bitstream Vera Sans Mono, Monospace; 85 | white-space:pre; 86 | } 87 | 88 | span.ok { 89 | color:green; 90 | } 91 | 92 | tr.error { 93 | color:red; 94 | } 95 | 96 | span.timeout { 97 | color:red; 98 | } 99 | 100 | span.ok, span.timeout, span.error { 101 | font-variant:small-caps; 102 | } -------------------------------------------------------------------------------- /test/harness/testharnessreport.js: -------------------------------------------------------------------------------- 1 | /* This Source Code Form is subject to the terms of the Mozilla Public 2 | * License, v. 2.0. If a copy of the MPL was not distributed with this 3 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 | 5 | var props = {output: true, 6 | explicit_timeout: true, 7 | message_events: ["completion"]}; 8 | 9 | if (window.opener && "timeout_multiplier" in window.opener) { 10 | props["timeout_multiplier"] = window.opener.timeout_multiplier; 11 | } 12 | 13 | if (window.opener && window.opener.explicit_timeout) { 14 | props["explicit_timeout"] = window.opener.explicit_timeout; 15 | } 16 | 17 | setup(props); 18 | -------------------------------------------------------------------------------- /test/js-api/constructor/compile.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | function assert_Module(module) { 5 | assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype, 6 | "Prototype"); 7 | assert_true(Object.isExtensible(module), "Extensibility"); 8 | } 9 | 10 | let emptyModuleBinary; 11 | setup(() => { 12 | emptyModuleBinary = new WasmModuleBuilder().toBuffer(); 13 | }); 14 | 15 | promise_test(t => { 16 | return promise_rejects_js(t, TypeError, WebAssembly.compile()); 17 | }, "Missing argument"); 18 | 19 | promise_test(t => { 20 | const invalidArguments = [ 21 | undefined, 22 | null, 23 | true, 24 | "", 25 | Symbol(), 26 | 1, 27 | {}, 28 | ArrayBuffer, 29 | ArrayBuffer.prototype, 30 | Array.from(emptyModuleBinary), 31 | ]; 32 | return Promise.all(invalidArguments.map(argument => { 33 | return promise_rejects_js(t, TypeError, WebAssembly.compile(argument), 34 | `compile(${format_value(argument)})`); 35 | })); 36 | }, "Invalid arguments"); 37 | 38 | promise_test(() => { 39 | const fn = WebAssembly.compile; 40 | const thisValues = [ 41 | undefined, 42 | null, 43 | true, 44 | "", 45 | Symbol(), 46 | 1, 47 | {}, 48 | WebAssembly, 49 | ]; 50 | return Promise.all(thisValues.map(thisValue => { 51 | return fn.call(thisValue, emptyModuleBinary).then(assert_Module); 52 | })); 53 | }, "Branding"); 54 | 55 | test(() => { 56 | const promise = WebAssembly.compile(emptyModuleBinary); 57 | assert_equals(Object.getPrototypeOf(promise), Promise.prototype, "prototype"); 58 | assert_true(Object.isExtensible(promise), "extensibility"); 59 | }, "Promise type"); 60 | 61 | promise_test(t => { 62 | const buffer = new Uint8Array(); 63 | return promise_rejects_js(t, WebAssembly.CompileError, WebAssembly.compile(buffer)); 64 | }, "Empty buffer"); 65 | 66 | promise_test(t => { 67 | const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0])); 68 | return promise_rejects_js(t, WebAssembly.CompileError, WebAssembly.compile(buffer)); 69 | }, "Invalid code"); 70 | 71 | promise_test(() => { 72 | return WebAssembly.compile(emptyModuleBinary).then(assert_Module); 73 | }, "Result type"); 74 | 75 | promise_test(() => { 76 | return WebAssembly.compile(emptyModuleBinary, {}).then(assert_Module); 77 | }, "Stray argument"); 78 | 79 | promise_test(() => { 80 | const buffer = new WasmModuleBuilder().toBuffer(); 81 | assert_equals(buffer[0], 0); 82 | const promise = WebAssembly.compile(buffer); 83 | buffer[0] = 1; 84 | return promise.then(assert_Module); 85 | }, "Changing the buffer"); 86 | -------------------------------------------------------------------------------- /test/js-api/constructor/instantiate-bad-imports.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | // META: script=/wasm/jsapi/bad-imports.js 4 | 5 | test_bad_imports((name, error, build, ...arguments) => { 6 | promise_test(t => { 7 | const builder = new WasmModuleBuilder(); 8 | build(builder); 9 | const buffer = builder.toBuffer(); 10 | const module = new WebAssembly.Module(buffer); 11 | return promise_rejects_js(t, error, WebAssembly.instantiate(module, ...arguments)); 12 | }, `WebAssembly.instantiate(module): ${name}`); 13 | }); 14 | 15 | test_bad_imports((name, error, build, ...arguments) => { 16 | promise_test(t => { 17 | const builder = new WasmModuleBuilder(); 18 | build(builder); 19 | const buffer = builder.toBuffer(); 20 | return promise_rejects_js(t, error, WebAssembly.instantiate(buffer, ...arguments)); 21 | }, `WebAssembly.instantiate(buffer): ${name}`); 22 | }); 23 | -------------------------------------------------------------------------------- /test/js-api/constructor/toStringTag.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | 3 | "use strict"; 4 | // https://webidl.spec.whatwg.org/#es-namespaces 5 | // https://webassembly.github.io/spec/js-api/#namespacedef-webassembly 6 | 7 | test(() => { 8 | assert_own_property(WebAssembly, Symbol.toStringTag); 9 | 10 | const propDesc = Object.getOwnPropertyDescriptor(WebAssembly, Symbol.toStringTag); 11 | assert_equals(propDesc.value, "WebAssembly", "value"); 12 | assert_equals(propDesc.writable, false, "writable"); 13 | assert_equals(propDesc.enumerable, false, "enumerable"); 14 | assert_equals(propDesc.configurable, true, "configurable"); 15 | }, "@@toStringTag exists on the namespace object with the appropriate descriptor"); 16 | 17 | test(() => { 18 | assert_equals(WebAssembly.toString(), "[object WebAssembly]"); 19 | assert_equals(Object.prototype.toString.call(WebAssembly), "[object WebAssembly]"); 20 | }, "Object.prototype.toString applied to the namespace object"); 21 | 22 | test(t => { 23 | assert_own_property(WebAssembly, Symbol.toStringTag, "Precondition: @@toStringTag on the namespace object"); 24 | t.add_cleanup(() => { 25 | Object.defineProperty(WebAssembly, Symbol.toStringTag, { value: "WebAssembly" }); 26 | }); 27 | 28 | Object.defineProperty(WebAssembly, Symbol.toStringTag, { value: "Test" }); 29 | assert_equals(WebAssembly.toString(), "[object Test]"); 30 | assert_equals(Object.prototype.toString.call(WebAssembly), "[object Test]"); 31 | }, "Object.prototype.toString applied after modifying the namespace object's @@toStringTag"); 32 | 33 | test(t => { 34 | assert_own_property(WebAssembly, Symbol.toStringTag, "Precondition: @@toStringTag on the namespace object"); 35 | t.add_cleanup(() => { 36 | Object.defineProperty(WebAssembly, Symbol.toStringTag, { value: "WebAssembly" }); 37 | }); 38 | 39 | assert_true(delete WebAssembly[Symbol.toStringTag]); 40 | assert_equals(WebAssembly.toString(), "[object Object]"); 41 | assert_equals(Object.prototype.toString.call(WebAssembly), "[object Object]"); 42 | }, "Object.prototype.toString applied after deleting @@toStringTag"); 43 | -------------------------------------------------------------------------------- /test/js-api/error-interfaces-no-symbol-tostringtag.js: -------------------------------------------------------------------------------- 1 | // META: global=jsshell 2 | 3 | test(() => { 4 | assert_not_own_property(WebAssembly.CompileError.prototype, Symbol.toStringTag); 5 | }, "WebAssembly.CompileError"); 6 | 7 | test(() => { 8 | assert_not_own_property(WebAssembly.LinkError.prototype, Symbol.toStringTag); 9 | }, "WebAssembly.LinkError"); 10 | 11 | test(() => { 12 | assert_not_own_property(WebAssembly.RuntimeError.prototype, Symbol.toStringTag); 13 | }, "WebAssembly.RuntimeError"); 14 | -------------------------------------------------------------------------------- /test/js-api/functions/helper.js: -------------------------------------------------------------------------------- 1 | function call_later(f) { 2 | const builder = new WasmModuleBuilder(); 3 | const functionIndex = builder.addImport("module", "imported", kSig_v_v); 4 | builder.addStart(functionIndex); 5 | const buffer = builder.toBuffer(); 6 | 7 | WebAssembly.instantiate(buffer, { 8 | "module": { 9 | "imported": f, 10 | } 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /test/js-api/global/toString.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | 3 | test(() => { 4 | const argument = { "value": "i32" }; 5 | const global = new WebAssembly.Global(argument); 6 | assert_class_string(global, "WebAssembly.Global"); 7 | }, "Object.prototype.toString on an Global"); 8 | 9 | test(() => { 10 | assert_own_property(WebAssembly.Global.prototype, Symbol.toStringTag); 11 | 12 | const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Global.prototype, Symbol.toStringTag); 13 | assert_equals(propDesc.value, "WebAssembly.Global", "value"); 14 | assert_equals(propDesc.configurable, true, "configurable"); 15 | assert_equals(propDesc.enumerable, false, "enumerable"); 16 | assert_equals(propDesc.writable, false, "writable"); 17 | }, "@@toStringTag exists on the prototype with the appropriate descriptor"); 18 | -------------------------------------------------------------------------------- /test/js-api/global/valueOf.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | 3 | test(() => { 4 | const argument = { "value": "i32" }; 5 | const thisValues = [ 6 | undefined, 7 | null, 8 | true, 9 | "", 10 | Symbol(), 11 | 1, 12 | {}, 13 | WebAssembly.Global, 14 | WebAssembly.Global.prototype, 15 | ]; 16 | 17 | const fn = WebAssembly.Global.prototype.valueOf; 18 | 19 | for (const thisValue of thisValues) { 20 | assert_throws_js(TypeError, () => fn.call(thisValue), `this=${format_value(thisValue)}`); 21 | } 22 | }, "Branding"); 23 | 24 | test(() => { 25 | const argument = { "value": "i32" }; 26 | const global = new WebAssembly.Global(argument, 0); 27 | assert_equals(global.valueOf({}), 0); 28 | }, "Stray argument"); 29 | -------------------------------------------------------------------------------- /test/js-api/instance/constructor-bad-imports.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | // META: script=/wasm/jsapi/bad-imports.js 4 | 5 | test_bad_imports((name, error, build, ...arguments) => { 6 | test(() => { 7 | const builder = new WasmModuleBuilder(); 8 | build(builder); 9 | const buffer = builder.toBuffer(); 10 | const module = new WebAssembly.Module(buffer); 11 | assert_throws_js(error, () => new WebAssembly.Instance(module, ...arguments)); 12 | }, `new WebAssembly.Instance(module): ${name}`); 13 | }); 14 | -------------------------------------------------------------------------------- /test/js-api/instance/constructor-caching.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | function getExports() { 5 | const builder = new WasmModuleBuilder(); 6 | builder 7 | .addFunction("fn", kSig_v_d) 8 | .addBody([]) 9 | .exportFunc(); 10 | 11 | builder.setTableBounds(1); 12 | builder.addExportOfKind("table", kExternalTable, 0); 13 | builder.addGlobal(kWasmI32, false).exportAs("global"); 14 | builder.addMemory(4, 8, true); 15 | 16 | const buffer = builder.toBuffer(); 17 | const module = new WebAssembly.Module(buffer); 18 | const instance = new WebAssembly.Instance(module); 19 | return instance.exports; 20 | } 21 | 22 | test(() => { 23 | const exports = getExports(); 24 | 25 | const builder = new WasmModuleBuilder(); 26 | const functionIndex = builder.addImport("module", "imported", kSig_v_d); 27 | builder.addExport("exportedFunction", functionIndex); 28 | 29 | const globalIndex = builder.addImportedGlobal("module", "global", kWasmI32); 30 | builder.addExportOfKind("exportedGlobal", kExternalGlobal, globalIndex); 31 | 32 | builder.addImportedMemory("module", "memory", 4); 33 | builder.exportMemoryAs("exportedMemory"); 34 | 35 | const tableIndex = builder.addImportedTable("module", "table", 1); 36 | builder.addExportOfKind("exportedTable", kExternalTable, tableIndex); 37 | 38 | const buffer = builder.toBuffer(); 39 | 40 | const module = new WebAssembly.Module(buffer); 41 | const instance = new WebAssembly.Instance(module, { 42 | "module": { 43 | "imported": exports.fn, 44 | "global": exports.global, 45 | "memory": exports.memory, 46 | "table": exports.table, 47 | } 48 | }); 49 | 50 | assert_equals(instance.exports.exportedFunction, exports.fn); 51 | assert_equals(instance.exports.exportedGlobal, exports.global); 52 | assert_equals(instance.exports.exportedMemory, exports.memory); 53 | assert_equals(instance.exports.exportedTable, exports.table); 54 | }); 55 | -------------------------------------------------------------------------------- /test/js-api/instance/constructor.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | // META: script=/wasm/jsapi/assertions.js 4 | // META: script=/wasm/jsapi/instanceTestFactory.js 5 | 6 | let emptyModuleBinary; 7 | setup(() => { 8 | emptyModuleBinary = new WasmModuleBuilder().toBuffer(); 9 | }); 10 | 11 | test(() => { 12 | assert_function_name(WebAssembly.Instance, "Instance", "WebAssembly.Instance"); 13 | }, "name"); 14 | 15 | test(() => { 16 | assert_function_length(WebAssembly.Instance, 1, "WebAssembly.Instance"); 17 | }, "length"); 18 | 19 | test(() => { 20 | assert_throws_js(TypeError, () => new WebAssembly.Instance()); 21 | }, "No arguments"); 22 | 23 | test(() => { 24 | const invalidArguments = [ 25 | undefined, 26 | null, 27 | true, 28 | "", 29 | Symbol(), 30 | 1, 31 | {}, 32 | WebAssembly.Module, 33 | WebAssembly.Module.prototype, 34 | ]; 35 | for (const argument of invalidArguments) { 36 | assert_throws_js(TypeError, () => new WebAssembly.Instance(argument), 37 | `new Instance(${format_value(argument)})`); 38 | } 39 | }, "Non-Module arguments"); 40 | 41 | test(() => { 42 | const module = new WebAssembly.Module(emptyModuleBinary); 43 | assert_throws_js(TypeError, () => WebAssembly.Instance(module)); 44 | }, "Calling"); 45 | 46 | for (const [name, fn] of instanceTestFactory) { 47 | test(() => { 48 | const { buffer, args, exports, verify } = fn(); 49 | const module = new WebAssembly.Module(buffer); 50 | const instance = new WebAssembly.Instance(module, ...args); 51 | assert_Instance(instance, exports); 52 | verify(instance); 53 | }, name); 54 | } 55 | -------------------------------------------------------------------------------- /test/js-api/instance/exports.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | let emptyModuleBinary; 5 | setup(() => { 6 | emptyModuleBinary = new WasmModuleBuilder().toBuffer(); 7 | }); 8 | 9 | test(() => { 10 | const thisValues = [ 11 | undefined, 12 | null, 13 | true, 14 | "", 15 | Symbol(), 16 | 1, 17 | {}, 18 | WebAssembly.Instance, 19 | WebAssembly.Instance.prototype, 20 | ]; 21 | 22 | const desc = Object.getOwnPropertyDescriptor(WebAssembly.Instance.prototype, "exports"); 23 | assert_equals(typeof desc, "object"); 24 | 25 | const getter = desc.get; 26 | assert_equals(typeof getter, "function"); 27 | 28 | assert_equals(typeof desc.set, "undefined"); 29 | 30 | for (const thisValue of thisValues) { 31 | assert_throws_js(TypeError, () => getter.call(thisValue), `this=${format_value(thisValue)}`); 32 | } 33 | }, "Branding"); 34 | 35 | test(() => { 36 | const module = new WebAssembly.Module(emptyModuleBinary); 37 | const instance = new WebAssembly.Instance(module); 38 | const exports = instance.exports; 39 | 40 | const desc = Object.getOwnPropertyDescriptor(WebAssembly.Instance.prototype, "exports"); 41 | assert_equals(typeof desc, "object"); 42 | 43 | const getter = desc.get; 44 | assert_equals(typeof getter, "function"); 45 | 46 | assert_equals(getter.call(instance, {}), exports); 47 | }, "Stray argument"); 48 | 49 | test(() => { 50 | const module = new WebAssembly.Module(emptyModuleBinary); 51 | const instance = new WebAssembly.Instance(module); 52 | const exports = instance.exports; 53 | instance.exports = {}; 54 | assert_equals(instance.exports, exports, "Should not change the exports"); 55 | }, "Setting (sloppy mode)"); 56 | 57 | test(() => { 58 | const module = new WebAssembly.Module(emptyModuleBinary); 59 | const instance = new WebAssembly.Instance(module); 60 | const exports = instance.exports; 61 | assert_throws_js(TypeError, () => { 62 | "use strict"; 63 | instance.exports = {}; 64 | }); 65 | assert_equals(instance.exports, exports, "Should not change the exports"); 66 | }, "Setting (strict mode)"); 67 | -------------------------------------------------------------------------------- /test/js-api/instance/toString.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | test(() => { 5 | const emptyModuleBinary = new WasmModuleBuilder().toBuffer(); 6 | const module = new WebAssembly.Module(emptyModuleBinary); 7 | const instance = new WebAssembly.Instance(module); 8 | assert_class_string(instance, "WebAssembly.Instance"); 9 | }, "Object.prototype.toString on an Instance"); 10 | 11 | test(() => { 12 | assert_own_property(WebAssembly.Instance.prototype, Symbol.toStringTag); 13 | 14 | const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Instance.prototype, Symbol.toStringTag); 15 | assert_equals(propDesc.value, "WebAssembly.Instance", "value"); 16 | assert_equals(propDesc.configurable, true, "configurable"); 17 | assert_equals(propDesc.enumerable, false, "enumerable"); 18 | assert_equals(propDesc.writable, false, "writable"); 19 | }, "@@toStringTag exists on the prototype with the appropriate descriptor"); 20 | -------------------------------------------------------------------------------- /test/js-api/memory/assertions.js: -------------------------------------------------------------------------------- 1 | function assert_ArrayBuffer(actual, { size=0, shared=false, detached=false }, message) { 2 | // https://github.com/WebAssembly/spec/issues/840 3 | // See https://github.com/whatwg/html/issues/5380 for why not `self.SharedArrayBuffer` 4 | const isShared = !("isView" in actual.constructor); 5 | assert_equals(isShared, shared, `${message}: constructor`); 6 | const sharedString = shared ? "Shared" : ""; 7 | assert_equals(actual.toString(), `[object ${sharedString}ArrayBuffer]`, `${message}: toString()`); 8 | assert_equals(Object.getPrototypeOf(actual).toString(), `[object ${sharedString}ArrayBuffer]`, `${message}: prototype toString()`); 9 | if (detached) { 10 | // https://github.com/tc39/ecma262/issues/678 11 | let byteLength; 12 | try { 13 | byteLength = actual.byteLength; 14 | } catch (e) { 15 | byteLength = 0; 16 | } 17 | assert_equals(byteLength, 0, `${message}: detached size`); 18 | } else { 19 | assert_equals(actual.byteLength, 0x10000 * size, `${message}: size`); 20 | if (size > 0) { 21 | const array = new Uint8Array(actual); 22 | assert_equals(array[0], 0, `${message}: first element`); 23 | assert_equals(array[array.byteLength - 1], 0, `${message}: last element`); 24 | } 25 | } 26 | assert_equals(Object.isFrozen(actual), shared, "buffer frozen"); 27 | assert_equals(Object.isExtensible(actual), !shared, "buffer extensibility"); 28 | } 29 | 30 | function assert_Memory(memory, { size=0, shared=false }) { 31 | assert_equals(Object.getPrototypeOf(memory), WebAssembly.Memory.prototype, 32 | "prototype"); 33 | assert_true(Object.isExtensible(memory), "extensible"); 34 | 35 | // https://github.com/WebAssembly/spec/issues/840 36 | assert_equals(memory.buffer, memory.buffer, "buffer should be idempotent"); 37 | assert_ArrayBuffer(memory.buffer, { size, shared }); 38 | } 39 | -------------------------------------------------------------------------------- /test/js-api/memory/buffer.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | 3 | test(() => { 4 | const thisValues = [ 5 | undefined, 6 | null, 7 | true, 8 | "", 9 | Symbol(), 10 | 1, 11 | {}, 12 | WebAssembly.Memory, 13 | WebAssembly.Memory.prototype, 14 | ]; 15 | 16 | const desc = Object.getOwnPropertyDescriptor(WebAssembly.Memory.prototype, "buffer"); 17 | assert_equals(typeof desc, "object"); 18 | 19 | const getter = desc.get; 20 | assert_equals(typeof getter, "function"); 21 | 22 | assert_equals(typeof desc.set, "undefined"); 23 | 24 | for (const thisValue of thisValues) { 25 | assert_throws_js(TypeError, () => getter.call(thisValue), `this=${format_value(thisValue)}`); 26 | } 27 | }, "Branding"); 28 | 29 | test(() => { 30 | const argument = { "initial": 0 }; 31 | const memory = new WebAssembly.Memory(argument); 32 | const buffer = memory.buffer; 33 | 34 | const desc = Object.getOwnPropertyDescriptor(WebAssembly.Memory.prototype, "buffer"); 35 | assert_equals(typeof desc, "object"); 36 | 37 | const getter = desc.get; 38 | assert_equals(typeof getter, "function"); 39 | 40 | assert_equals(getter.call(memory, {}), buffer); 41 | }, "Stray argument"); 42 | 43 | test(() => { 44 | const argument = { "initial": 0 }; 45 | const memory = new WebAssembly.Memory(argument); 46 | const memory2 = new WebAssembly.Memory(argument); 47 | const buffer = memory.buffer; 48 | assert_not_equals(buffer, memory2.buffer, "Need two distinct buffers"); 49 | memory.buffer = memory2.buffer; 50 | assert_equals(memory.buffer, buffer, "Should not change the buffer"); 51 | }, "Setting (sloppy mode)"); 52 | 53 | test(() => { 54 | const argument = { "initial": 0 }; 55 | const memory = new WebAssembly.Memory(argument); 56 | const memory2 = new WebAssembly.Memory(argument); 57 | const buffer = memory.buffer; 58 | assert_not_equals(buffer, memory2.buffer, "Need two distinct buffers"); 59 | assert_throws_js(TypeError, () => { 60 | "use strict"; 61 | memory.buffer = memory2.buffer; 62 | }); 63 | assert_equals(memory.buffer, buffer, "Should not change the buffer"); 64 | }, "Setting (strict mode)"); 65 | -------------------------------------------------------------------------------- /test/js-api/memory/toString.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | 3 | test(() => { 4 | const argument = { "initial": 0 }; 5 | const memory = new WebAssembly.Memory(argument); 6 | assert_class_string(memory, "WebAssembly.Memory"); 7 | }, "Object.prototype.toString on an Memory"); 8 | 9 | test(() => { 10 | assert_own_property(WebAssembly.Memory.prototype, Symbol.toStringTag); 11 | 12 | const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Memory.prototype, Symbol.toStringTag); 13 | assert_equals(propDesc.value, "WebAssembly.Memory", "value"); 14 | assert_equals(propDesc.configurable, true, "configurable"); 15 | assert_equals(propDesc.enumerable, false, "enumerable"); 16 | assert_equals(propDesc.writable, false, "writable"); 17 | }, "@@toStringTag exists on the prototype with the appropriate descriptor"); 18 | -------------------------------------------------------------------------------- /test/js-api/module/constructor.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | // META: script=/wasm/jsapi/assertions.js 4 | 5 | let emptyModuleBinary; 6 | setup(() => { 7 | emptyModuleBinary = new WasmModuleBuilder().toBuffer(); 8 | }); 9 | 10 | test(() => { 11 | assert_function_name(WebAssembly.Module, "Module", "WebAssembly.Module"); 12 | }, "name"); 13 | 14 | test(() => { 15 | assert_function_length(WebAssembly.Module, 1, "WebAssembly.Module"); 16 | }, "length"); 17 | 18 | test(() => { 19 | assert_throws_js(TypeError, () => new WebAssembly.Module()); 20 | }, "No arguments"); 21 | 22 | test(() => { 23 | assert_throws_js(TypeError, () => WebAssembly.Module(emptyModuleBinary)); 24 | }, "Calling"); 25 | 26 | test(() => { 27 | const invalidArguments = [ 28 | undefined, 29 | null, 30 | true, 31 | "test", 32 | Symbol(), 33 | 7, 34 | NaN, 35 | {}, 36 | ArrayBuffer, 37 | ArrayBuffer.prototype, 38 | Array.from(emptyModuleBinary), 39 | ]; 40 | for (const argument of invalidArguments) { 41 | assert_throws_js(TypeError, () => new WebAssembly.Module(argument), 42 | `new Module(${format_value(argument)})`); 43 | } 44 | }, "Invalid arguments"); 45 | 46 | test(() => { 47 | const buffer = new Uint8Array(); 48 | assert_throws_js(WebAssembly.CompileError, () => new WebAssembly.Module(buffer)); 49 | }, "Empty buffer"); 50 | 51 | test(() => { 52 | const buffer = new Uint8Array(Array.from(emptyModuleBinary).concat([0, 0])); 53 | assert_throws_js(WebAssembly.CompileError, () => new WebAssembly.Module(buffer)); 54 | }, "Invalid code"); 55 | 56 | test(() => { 57 | const module = new WebAssembly.Module(emptyModuleBinary); 58 | assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype); 59 | }, "Prototype"); 60 | 61 | test(() => { 62 | const module = new WebAssembly.Module(emptyModuleBinary); 63 | assert_true(Object.isExtensible(module)); 64 | }, "Extensibility"); 65 | 66 | test(() => { 67 | const module = new WebAssembly.Module(emptyModuleBinary, {}); 68 | assert_equals(Object.getPrototypeOf(module), WebAssembly.Module.prototype); 69 | }, "Stray argument"); 70 | -------------------------------------------------------------------------------- /test/js-api/module/toString.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | test(() => { 5 | const emptyModuleBinary = new WasmModuleBuilder().toBuffer(); 6 | const module = new WebAssembly.Module(emptyModuleBinary); 7 | assert_class_string(module, "WebAssembly.Module"); 8 | }, "Object.prototype.toString on an Module"); 9 | 10 | test(() => { 11 | assert_own_property(WebAssembly.Module.prototype, Symbol.toStringTag); 12 | 13 | const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Module.prototype, Symbol.toStringTag); 14 | assert_equals(propDesc.value, "WebAssembly.Module", "value"); 15 | assert_equals(propDesc.configurable, true, "configurable"); 16 | assert_equals(propDesc.enumerable, false, "enumerable"); 17 | assert_equals(propDesc.writable, false, "writable"); 18 | }, "@@toStringTag exists on the prototype with the appropriate descriptor"); 19 | -------------------------------------------------------------------------------- /test/js-api/prototypes.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/assertions.js 3 | // META: script=/wasm/jsapi/wasm-module-builder.js 4 | 5 | let emptyModuleBinary; 6 | setup(() => { 7 | emptyModuleBinary = new WasmModuleBuilder().toBuffer(); 8 | }); 9 | 10 | test(() => { 11 | class _Module extends WebAssembly.Module {} 12 | let module = new _Module(emptyModuleBinary); 13 | assert_true(module instanceof _Module, "_Module instanceof _Module"); 14 | assert_true(module instanceof WebAssembly.Module, "_Module instanceof WebAssembly.Module"); 15 | }, "_Module"); 16 | 17 | test(() => { 18 | class _Instance extends WebAssembly.Instance {} 19 | let instance = new _Instance(new WebAssembly.Module(emptyModuleBinary)); 20 | assert_true(instance instanceof _Instance, "_Instance instanceof _Instance"); 21 | assert_true(instance instanceof WebAssembly.Instance, "_Instance instanceof WebAssembly.Instance"); 22 | }, "_Instance"); 23 | 24 | test(() => { 25 | class _Memory extends WebAssembly.Memory {} 26 | let memory = new _Memory({initial: 0, maximum: 1}); 27 | assert_true(memory instanceof _Memory, "_Memory instanceof _Memory"); 28 | assert_true(memory instanceof WebAssembly.Memory, "_Memory instanceof WebAssembly.Memory"); 29 | }, "_Memory"); 30 | 31 | test(() => { 32 | class _Table extends WebAssembly.Table {} 33 | let table = new _Table({initial: 0, element: "anyfunc"}); 34 | assert_true(table instanceof _Table, "_Table instanceof _Table"); 35 | assert_true(table instanceof WebAssembly.Table, "_Table instanceof WebAssembly.Table"); 36 | }, "_Table"); 37 | 38 | test(() => { 39 | class _Global extends WebAssembly.Global {} 40 | let global = new _Global({value: "i32", mutable: false}, 0); 41 | assert_true(global instanceof _Global, "_Global instanceof _Global"); 42 | assert_true(global instanceof WebAssembly.Global, "_Global instanceof WebAssembly.Global"); 43 | }, "_Global"); 44 | -------------------------------------------------------------------------------- /test/js-api/table/assertions.js: -------------------------------------------------------------------------------- 1 | function assert_equal_to_array(table, expected, message) { 2 | assert_equals(table.length, expected.length, `${message}: length`); 3 | // The argument check in get() happens before the range check, and negative numbers 4 | // are illegal, hence will throw TypeError per spec. 5 | assert_throws_js(TypeError, () => table.get(-1), `${message}: table.get(-1)`); 6 | for (let i = 0; i < expected.length; ++i) { 7 | assert_equals(table.get(i), expected[i], `${message}: table.get(${i} of ${expected.length})`); 8 | } 9 | assert_throws_js(RangeError, () => table.get(expected.length), 10 | `${message}: table.get(${expected.length} of ${expected.length})`); 11 | assert_throws_js(RangeError, () => table.get(expected.length + 1), 12 | `${message}: table.get(${expected.length + 1} of ${expected.length})`); 13 | } 14 | 15 | function assert_Table(actual, expected) { 16 | assert_equals(Object.getPrototypeOf(actual), WebAssembly.Table.prototype, 17 | "prototype"); 18 | assert_true(Object.isExtensible(actual), "extensible"); 19 | 20 | assert_equals(actual.length, expected.length, "length"); 21 | for (let i = 0; i < expected.length; ++i) { 22 | assert_equals(actual.get(i), null, `actual.get(${i})`); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/js-api/table/length.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | 3 | test(() => { 4 | const thisValues = [ 5 | undefined, 6 | null, 7 | true, 8 | "", 9 | Symbol(), 10 | 1, 11 | {}, 12 | WebAssembly.Table, 13 | WebAssembly.Table.prototype, 14 | ]; 15 | 16 | const desc = Object.getOwnPropertyDescriptor(WebAssembly.Table.prototype, "length"); 17 | assert_equals(typeof desc, "object"); 18 | 19 | const getter = desc.get; 20 | assert_equals(typeof getter, "function"); 21 | 22 | assert_equals(typeof desc.set, "undefined"); 23 | 24 | for (const thisValue of thisValues) { 25 | assert_throws_js(TypeError, () => getter.call(thisValue), `this=${format_value(thisValue)}`); 26 | } 27 | }, "Branding"); 28 | 29 | test(() => { 30 | const argument = { "element": "anyfunc", "initial": 2 }; 31 | const table = new WebAssembly.Table(argument); 32 | assert_equals(table.length, 2, "Initial length"); 33 | 34 | const desc = Object.getOwnPropertyDescriptor(WebAssembly.Table.prototype, "length"); 35 | assert_equals(typeof desc, "object"); 36 | 37 | const getter = desc.get; 38 | assert_equals(typeof getter, "function"); 39 | 40 | assert_equals(getter.call(table, {}), 2); 41 | }, "Stray argument"); 42 | 43 | test(() => { 44 | const argument = { "element": "anyfunc", "initial": 2 }; 45 | const table = new WebAssembly.Table(argument); 46 | assert_equals(table.length, 2, "Initial length"); 47 | table.length = 4; 48 | assert_equals(table.length, 2, "Should not change the length"); 49 | }, "Setting (sloppy mode)"); 50 | 51 | test(() => { 52 | const argument = { "element": "anyfunc", "initial": 2 }; 53 | const table = new WebAssembly.Table(argument); 54 | assert_equals(table.length, 2, "Initial length"); 55 | assert_throws_js(TypeError, () => { 56 | "use strict"; 57 | table.length = 4; 58 | }); 59 | assert_equals(table.length, 2, "Should not change the length"); 60 | }, "Setting (strict mode)"); 61 | -------------------------------------------------------------------------------- /test/js-api/table/toString.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | 3 | test(() => { 4 | const argument = { "element": "anyfunc", "initial": 0 }; 5 | const table = new WebAssembly.Table(argument); 6 | assert_class_string(table, "WebAssembly.Table"); 7 | }, "Object.prototype.toString on an Table"); 8 | 9 | test(() => { 10 | assert_own_property(WebAssembly.Table.prototype, Symbol.toStringTag); 11 | 12 | const propDesc = Object.getOwnPropertyDescriptor(WebAssembly.Table.prototype, Symbol.toStringTag); 13 | assert_equals(propDesc.value, "WebAssembly.Table", "value"); 14 | assert_equals(propDesc.configurable, true, "configurable"); 15 | assert_equals(propDesc.enumerable, false, "enumerable"); 16 | assert_equals(propDesc.writable, false, "writable"); 17 | }, "@@toStringTag exists on the prototype with the appropriate descriptor"); 18 | -------------------------------------------------------------------------------- /test/meta/Makefile: -------------------------------------------------------------------------------- 1 | SHARED_MEM=false 2 | 3 | # SpiderMonkey shell 4 | #JSSHELL=~/mozilla-central/js/src/build-debug/dist/bin/js -e 'const WITH_SHARED_MEMORY=$(SHARED_MEM);' -f common.js 5 | 6 | # Node.js 7 | JSSHELL=./noderun.sh $(SHARED_MEM) 8 | 9 | TARGETDIR=../core 10 | 11 | .PHONY: all 12 | 13 | all: $(TARGETDIR)/memory_copy.wast \ 14 | $(TARGETDIR)/memory_init.wast \ 15 | $(TARGETDIR)/memory_fill.wast \ 16 | $(TARGETDIR)/table_copy.wast \ 17 | $(TARGETDIR)/table_init.wast 18 | 19 | $(TARGETDIR)/memory_copy.wast: generate_memory_copy.js common.js Makefile 20 | $(JSSHELL) $< > $@ 21 | 22 | $(TARGETDIR)/memory_init.wast: generate_memory_init.js common.js Makefile 23 | $(JSSHELL) $< > $@ 24 | 25 | $(TARGETDIR)/memory_fill.wast: generate_memory_fill.js common.js Makefile 26 | $(JSSHELL) $< > $@ 27 | 28 | $(TARGETDIR)/table_copy.wast: generate_table_copy.js common.js Makefile 29 | $(JSSHELL) $< > $@ 30 | 31 | $(TARGETDIR)/table_init.wast: generate_table_init.js common.js Makefile 32 | $(JSSHELL) $< > $@ 33 | -------------------------------------------------------------------------------- /test/meta/README.md: -------------------------------------------------------------------------------- 1 | These programs generate test cases. See Makefile for details. 2 | -------------------------------------------------------------------------------- /test/meta/common.js: -------------------------------------------------------------------------------- 1 | const PAGESIZE = 65536; 2 | 3 | function print_origin(origin) { 4 | print(";;"); 5 | print(";; Generated by ../meta/" + origin); 6 | print(";; DO NOT EDIT THIS FILE. CHANGE THE SOURCE AND REGENERATE."); 7 | print(";;"); 8 | } 9 | 10 | function checkRangeCode() { 11 | return ` 12 | (func (export "checkRange") (param $from i32) (param $to i32) (param $expected i32) (result i32) 13 | (loop $cont 14 | (if (i32.eq (local.get $from) (local.get $to)) 15 | (then 16 | (return (i32.const -1)))) 17 | (if (i32.eq (i32.load8_u (local.get $from)) (local.get $expected)) 18 | (then 19 | (local.set $from (i32.add (local.get $from) (i32.const 1))) 20 | (br $cont)))) 21 | (return (local.get $from))) 22 | `; 23 | } 24 | 25 | function checkRange(from, to, expected) { 26 | print( 27 | `(assert_return (invoke "checkRange" (i32.const ${from}) (i32.const ${to}) (i32.const ${expected})) 28 | (i32.const -1))`); 29 | } 30 | -------------------------------------------------------------------------------- /test/meta/noderun.sh: -------------------------------------------------------------------------------- 1 | if [ $# -ne 2 ]; then 2 | echo "Bad args" 3 | exit 1 4 | fi 5 | 6 | rm -f nodeprog.js 7 | cat <> nodeprog.js 8 | const WITH_SHARED_MEMORY=$1; 9 | function print(x) { 10 | console.log(x); 11 | } 12 | EOF 13 | cat common.js >> nodeprog.js 14 | cat $2 >> nodeprog.js 15 | node nodeprog.js 16 | rm nodeprog.js 17 | -------------------------------------------------------------------------------- /test/sync-js-api.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import glob 4 | import os 5 | import shutil 6 | import subprocess 7 | 8 | LOCAL_FILES = [ 9 | "LICENSE.md", 10 | "README.md", 11 | 12 | # Currently doesn't pass the stability checker in wpt. 13 | "limits.any.js", 14 | ] 15 | 16 | 17 | def copy_from_local(local_dir, out): 18 | for local_file in LOCAL_FILES: 19 | shutil.copy(os.path.join(local_dir, local_file), out) 20 | 21 | 22 | def copy_from_upstream(upstream, out): 23 | upstream = os.path.abspath(upstream) 24 | paths = glob.glob(os.path.join(upstream, "**", "*.js"), recursive=True) 25 | for path in paths: 26 | relpath = os.path.relpath(path, upstream) 27 | 28 | # Tests for proposals that have not merged here yet. 29 | if ".tentative" in relpath: 30 | continue 31 | 32 | # Requires `fetch()` and various wpt infrastructure. 33 | if os.path.basename(relpath) == "idlharness.any.js": 34 | continue 35 | 36 | dest = os.path.join(out, relpath) 37 | os.makedirs(os.path.dirname(dest), exist_ok=True) 38 | shutil.copy(path, dest) 39 | 40 | 41 | def main(upstream): 42 | local_dir = os.path.join("test", "js-api") 43 | scratch = os.path.join("test", "js-api-temp") 44 | os.mkdir(scratch) 45 | copy_from_local(local_dir, scratch) 46 | copy_from_upstream(os.path.join(upstream, "wasm", "jsapi"), scratch) 47 | shutil.rmtree(local_dir) 48 | os.rename(scratch, local_dir) 49 | subprocess.check_call(["git", "add", local_dir]) 50 | 51 | 52 | if __name__ == "__main__": 53 | import sys 54 | main(*sys.argv[1:]) 55 | -------------------------------------------------------------------------------- /w3c.json: -------------------------------------------------------------------------------- 1 | { 2 | "group": [78073] 3 | , "contacts": ["ericprud"] 4 | , "repo-type": "cg-report" 5 | } 6 | -------------------------------------------------------------------------------- /wasm-specs.bib: -------------------------------------------------------------------------------- 1 | @report{WebAssemblyCoreSpecification1, 2 | title = {{WebAssembly Core Specification}}, 3 | version = {1.0}, 4 | editor = {Rossberg, Andreas}, 5 | date = {2019-12-05}, 6 | institution = {{W3C}}, 7 | url = {https://www.w3.org/TR/wasm-core-1/}, 8 | langid = {english} 9 | } 10 | 11 | @report{WebAssemblyCoreSpecification2, 12 | title = {{WebAssembly Core Specification}}, 13 | version = {2.0}, 14 | editor = {Rossberg, Andreas}, 15 | date = {2022-04-19}, 16 | institution = {{W3C}}, 17 | url = {https://www.w3.org/TR/wasm-core-2/}, 18 | langid = {english}, 19 | note = {https://webassembly.github.io/spec/core/_download/WebAssembly.pdf} 20 | } 21 | --------------------------------------------------------------------------------