├── .gitattributes ├── .github └── workflows │ ├── ci-interpreter.yml │ ├── ci-spec.yml │ └── w3c-publish.yml ├── .gitignore ├── .gitmodules ├── Contributing.md ├── LICENSE ├── README.md ├── document ├── 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 │ │ ├── types.rst │ │ └── values.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 │ │ ├── matching.rst │ │ ├── modules.rst │ │ └── types.rst ├── deploy.sh ├── index.html ├── js-api │ ├── Makefile │ └── index.bs ├── legacy │ └── exceptions │ │ ├── .gitignore │ │ ├── core │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── appendix │ │ │ └── index-instructions.py │ │ ├── binary.rst │ │ ├── conf.py │ │ ├── exec.rst │ │ ├── index.rst │ │ ├── intro.rst │ │ ├── static │ │ │ ├── custom.css │ │ │ └── webassembly.png │ │ ├── syntax.rst │ │ ├── text.rst │ │ ├── util │ │ │ ├── macros.def │ │ │ ├── mathdef.py │ │ │ └── pseudo-lexer.py │ │ └── valid.rst │ │ └── js-api │ │ ├── Makefile │ │ └── index.bs ├── metadata │ └── code │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── binary.rst │ │ ├── conf.py │ │ ├── index.rst │ │ ├── intro.rst │ │ ├── static │ │ ├── custom.css │ │ └── webassembly.png │ │ ├── text.rst │ │ └── util │ │ ├── macros.def │ │ └── mathdef.py ├── 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 ├── custom │ ├── custom.ml │ ├── handler_branch_hint.ml │ ├── handler_custom.ml │ ├── handler_custom.mli │ ├── handler_name.ml │ └── handler_name.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 │ ├── aggr.ml │ ├── aggr.mli │ ├── data.ml │ ├── data.mli │ ├── elem.ml │ ├── elem.mli │ ├── exn.ml │ ├── exn.mli │ ├── extern.ml │ ├── extern.mli │ ├── func.ml │ ├── func.mli │ ├── global.ml │ ├── global.mli │ ├── i31.ml │ ├── i31.mli │ ├── instance.ml │ ├── memory.ml │ ├── memory.mli │ ├── table.ml │ ├── table.mli │ ├── tag.ml │ ├── tag.mli │ └── value.ml ├── script │ ├── import.ml │ ├── import.mli │ ├── js.ml │ ├── js.mli │ ├── run.ml │ ├── run.mli │ └── script.ml ├── syntax │ ├── ast.ml │ ├── free.ml │ ├── free.mli │ ├── operators.ml │ ├── pack.ml │ └── types.ml ├── text │ ├── annot.ml │ ├── annot.mli │ ├── 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 │ ├── match.ml │ ├── match.mli │ ├── valid.ml │ └── valid.mli └── wasm.opam ├── papers ├── LICENSE ├── README.md ├── oopsla2019.pdf └── pldi2017.pdf ├── proposals ├── README.md ├── annotations │ └── Overview.md ├── branch-hinting │ ├── Motivation.md │ └── Overview.md ├── bulk-memory-operations │ └── Overview.md ├── exception-handling │ ├── Exceptions.md │ ├── legacy │ │ ├── Exceptions-formal-examples.md │ │ ├── Exceptions-formal-overview.md │ │ └── Exceptions.md │ └── pre-legacy │ │ ├── Exceptions-v1.md │ │ ├── Exceptions-v2-Level-1+N.md │ │ ├── Exceptions-v2-Level-1.md │ │ └── Exceptions-v2.md ├── extended-const │ └── Overview.md ├── function-references │ └── Overview.md ├── gc │ ├── Charter.md │ ├── MVP-JS.md │ ├── MVP.md │ ├── Overview.md │ └── Post-MVP.md ├── js-string-builtins │ └── 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 └── tail-call │ └── Overview.md ├── test ├── LICENSE ├── README.md ├── Todo.md ├── build.py ├── core │ ├── .gitignore │ ├── README.md │ ├── address.wast │ ├── align.wast │ ├── annotations.wast │ ├── binary-leb128.wast │ ├── binary.wast │ ├── block.wast │ ├── br.wast │ ├── br_if.wast │ ├── br_on_non_null.wast │ ├── br_on_null.wast │ ├── br_table.wast │ ├── bulk.wast │ ├── call.wast │ ├── call_indirect.wast │ ├── call_ref.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 │ ├── gc │ │ ├── array.wast │ │ ├── array_copy.wast │ │ ├── array_fill.wast │ │ ├── array_init_data.wast │ │ ├── array_init_elem.wast │ │ ├── binary-gc.wast │ │ ├── br_on_cast.wast │ │ ├── br_on_cast_fail.wast │ │ ├── extern.wast │ │ ├── i31.wast │ │ ├── ref_cast.wast │ │ ├── ref_eq.wast │ │ ├── ref_test.wast │ │ ├── struct.wast │ │ └── type-subtyping.wast │ ├── global.wast │ ├── i32.wast │ ├── i64.wast │ ├── id.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_init.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.wast │ ├── ref_as_non_null.wast │ ├── ref_func.wast │ ├── ref_is_null.wast │ ├── ref_null.wast │ ├── return.wast │ ├── return_call.wast │ ├── return_call_indirect.wast │ ├── return_call_ref.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 │ ├── tag.wast │ ├── throw.wast │ ├── throw_ref.wast │ ├── token.wast │ ├── traps.wast │ ├── try_table.wast │ ├── type-canon.wast │ ├── type-equivalence.wast │ ├── type-rec.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 ├── custom │ ├── custom │ │ └── custom_annot.wast │ ├── metadata.code.branch_hint │ │ └── branch_hint.wast │ └── name │ │ └── name_annot.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 │ ├── exception │ │ ├── basic.tentative.any.js │ │ ├── constructor.tentative.any.js │ │ ├── getArg.tentative.any.js │ │ ├── identity.tentative.any.js │ │ ├── is.tentative.any.js │ │ ├── jsTag.tentative.any.js │ │ └── toString.tentative.any.js │ ├── functions │ │ └── helper.js │ ├── gc │ │ ├── casts.tentative.any.js │ │ ├── default-value.tentative.any.js │ │ ├── exported-object.tentative.any.js │ │ └── i31.tentative.any.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 │ ├── js-string │ │ ├── basic.tentative.any.js │ │ ├── constants.tentative.any.js │ │ ├── imports.tentative.any.js │ │ └── polyfill.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 │ ├── tag │ │ ├── constructor.tentative.any.js │ │ └── toString.tentative.any.js │ └── wasm-module-builder.js ├── legacy │ └── exceptions │ │ ├── core │ │ ├── rethrow.wast │ │ ├── run.py │ │ ├── throw.wast │ │ ├── try_catch.wast │ │ └── try_delegate.wast │ │ └── js-api │ │ ├── basic.tentative.any.js │ │ └── identity.tentative.any.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.14.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: 19.x 31 | - name: Build interpreter 32 | run: cd interpreter && opam exec make 33 | - name: Run tests 34 | # TODO: reactiate node once it supports all of Wasm 3.0 35 | # run: cd interpreter && opam exec make JS=node ci 36 | run: cd interpreter && opam exec make ci 37 | -------------------------------------------------------------------------------- /.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 | 11 | jobs: 12 | publish-to-w3c-TR: 13 | if: github.repository == 'WebAssembly/spec' 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repo 17 | uses: actions/checkout@v2 18 | with: 19 | submodules: "recursive" 20 | - name: Setup Node.js 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: 16 24 | - name: Setup Bikeshed 25 | run: pip install bikeshed && bikeshed update 26 | - name: Setup TexLive 27 | run: sudo apt-get update -y && sudo apt-get install -y latexmk texlive-latex-recommended texlive-latex-extra texlive-fonts-recommended 28 | - name: Setup Sphinx 29 | run: pip install six && pip install sphinx==5.1.0 30 | - name: Publish all specs to their https://www.w3.org/TR/ URLs 31 | run: cd document && make -e WD-echidna-CI 32 | env: 33 | STATUS: --md-status=WD 34 | W3C_ECHIDNA_TOKEN_CORE: ${{ secrets.W3C_ECHIDNA_TOKEN_CORE }} 35 | W3C_ECHIDNA_TOKEN_JSAPI: ${{ secrets.W3C_ECHIDNA_TOKEN_JSAPI }} 36 | W3C_ECHIDNA_TOKEN_WEBAPI: ${{ secrets.W3C_ECHIDNA_TOKEN_WEBAPI }} 37 | YARN_ENABLE_IMMUTABLE_INSTALLS: false 38 | -------------------------------------------------------------------------------- /.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/spec/actions/workflows/ci-spec.yml/badge.svg)](https://github.com/WebAssembly/spec/actions/workflows/ci-spec.yml) 2 | [![CI for interpreter & tests](https://github.com/WebAssembly/spec/actions/workflows/ci-interpreter.yml/badge.svg)](https://github.com/WebAssembly/spec/actions/workflows/ci-interpreter.yml) 3 | 4 | # JS String Builtins 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 8 | add support for efficient access to JS string operations to WebAssembly. 9 | 10 | * See the [overview](proposals/js-string-builtins/Overview.md) for a summary of the proposal. 11 | 12 | * See the [modified spec](https://webassembly.github.io/js-string-builtins/) for details. 13 | 14 | Original `README` from upstream repository follows... 15 | 16 | # spec 17 | 18 | This repository holds the sources for the WebAssembly specification, 19 | a reference implementation, and the official test suite. 20 | 21 | A formatted version of the spec is available here: 22 | [webassembly.github.io/spec](https://webassembly.github.io/spec/), 23 | 24 | Participation is welcome. Discussions about new features, significant semantic 25 | changes, or any specification change likely to generate substantial discussion 26 | should take place in 27 | [the WebAssembly design repository](https://github.com/WebAssembly/design) 28 | first, so that this spec repository can remain focused. And please follow the 29 | [guidelines for contributing](Contributing.md). 30 | 31 | # citing 32 | 33 | For citing WebAssembly in LaTeX, use [this bibtex file](wasm-specs.bib). 34 | -------------------------------------------------------------------------------- /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.rst: -------------------------------------------------------------------------------- 1 | .. _appendix: 2 | 3 | Appendix 4 | ======== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | embedding 10 | implementation 11 | properties 12 | algorithm 13 | custom 14 | changes 15 | 16 | index-types 17 | index-instructions 18 | index-rules 19 | -------------------------------------------------------------------------------- /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 | types 13 | values 14 | instructions 15 | modules 16 | -------------------------------------------------------------------------------- /document/core/exec/types.rst: -------------------------------------------------------------------------------- 1 | .. index:: type, dynamic type 2 | .. _exec-type: 3 | 4 | Types 5 | ----- 6 | 7 | Execution has to check and compare :ref:`types ` in a few places, such as :ref:`executing ` |CALLINDIRECT| or :ref:`instantiating ` :ref:`modules `. 8 | 9 | It is an invariant of the semantics that all types occurring during execution are :ref:`closed `. 10 | 11 | .. note:: 12 | Runtime type checks generally involve types from multiple modules or types not defined by a module at all, such that module-local :ref:`type indices ` are not meaningful. 13 | 14 | 15 | 16 | .. index:: type index, defined type, type instantiation, module instance, dynamic type 17 | 18 | .. _type-inst: 19 | 20 | Instantiation 21 | ~~~~~~~~~~~~~ 22 | 23 | Any form of :ref:`type ` can be *instantiated* into a :ref:`closed ` type inside a :ref:`module instance ` by :ref:`substituting ` each :ref:`type index ` :math:`x` occurring in it with the corresponding :ref:`defined type ` :math:`\moduleinst.\MITYPES[x]`. 24 | 25 | .. math:: 26 | \insttype_{\moduleinst}(t) = t[\subst \moduleinst.\MITYPES] 27 | 28 | .. note:: 29 | This is the runtime equivalent to :ref:`type closure `. 30 | -------------------------------------------------------------------------------- /document/core/index.bs: -------------------------------------------------------------------------------- 1 | 17 | 18 |
19 | {
20 |   "WEBASSEMBLY": {
21 |     "href": "https://webassembly.github.io/spec/",
22 |     "title": "WebAssembly Specification",
23 |     "publisher": "W3C WebAssembly Community Group",
24 |     "status": "Draft"
25 |   }
26 | }
27 | 
28 | 29 |
30 | path: _build/bikeshed_singlehtml/index_fixed.html
31 | 
32 | -------------------------------------------------------------------------------- /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 { width: 1000px; } 19 | div.bodywrapper { margin: 0 0 0 200px; } 20 | div.body { padding: 0 10px 0 10px; } 21 | div.footer { width: 1000px; } 22 | 23 | div.body h1 { font-size: 200%; } 24 | div.body h2 { font-size: 150%; } 25 | div.body h3 { font-size: 120%; } 26 | div.body h4 { font-size: 110%; } 27 | 28 | div.note { 29 | border: 0px; 30 | font-size: 90%; 31 | background-color: #F6F8FF; 32 | } 33 | 34 | div.admonition { 35 | padding: 10px; 36 | } 37 | 38 | div.admonition p.admonition-title { 39 | margin: 0px 0px 0px 0px; 40 | font-size: 100%; 41 | font-weight: bold; 42 | } 43 | 44 | div.math { 45 | background-color: #F0F0F0; 46 | padding: 3px 0 3px 0; 47 | overflow-x: auto; 48 | overflow-y: hidden; 49 | } 50 | 51 | div.relations { 52 | display: block; 53 | } 54 | 55 | div.sphinxsidebar { 56 | z-index: 1; 57 | background: #FFF; 58 | margin-top: -30px; 59 | font-size: 13px; 60 | width: 200px; 61 | height: 100%; 62 | } 63 | 64 | div.sphinxsidebarwrapper p.logo { 65 | padding: 30px 40px 10px 0px; 66 | } 67 | 68 | div.sphinxsidebar h3 { 69 | font-size: 0px; 70 | } 71 | 72 | div.sphinxsidebar a { 73 | border-bottom: 0px; 74 | } 75 | 76 | div.sphinxsidebar a:hover { 77 | border-bottom: 1px dotted; 78 | } 79 | -------------------------------------------------------------------------------- /document/core/static/webassembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssembly/js-string-builtins/dd601fb2f298119e1cc0f64c44cbcf45ab6d3ef7/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"(?`_ with additional instructions for exception handling. 8 | These instructions were never standardized and are deprecated, but they may still be available in some engines, especially in web browsers. 9 | -------------------------------------------------------------------------------- /document/legacy/exceptions/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 { width: 1000px; } 19 | div.bodywrapper { margin: 0 0 0 200px; } 20 | div.body { padding: 0 10px 0 10px; } 21 | div.footer { width: 1000px; } 22 | 23 | div.body h1 { font-size: 200%; } 24 | div.body h2 { font-size: 150%; } 25 | div.body h3 { font-size: 120%; } 26 | div.body h4 { font-size: 110%; } 27 | 28 | div.note { 29 | border: 0px; 30 | font-size: 90%; 31 | background-color: #F6F8FF; 32 | } 33 | 34 | div.admonition { 35 | padding: 10px; 36 | } 37 | 38 | div.admonition p.admonition-title { 39 | margin: 0px 0px 0px 0px; 40 | font-size: 100%; 41 | font-weight: bold; 42 | } 43 | 44 | div.math { 45 | background-color: #F0F0F0; 46 | padding: 3px 0 3px 0; 47 | overflow-x: auto; 48 | overflow-y: hidden; 49 | } 50 | 51 | div.relations { 52 | display: block; 53 | } 54 | 55 | div.sphinxsidebar { 56 | z-index: 1; 57 | background: #FFF; 58 | margin-top: -30px; 59 | font-size: 13px; 60 | width: 200px; 61 | height: 100%; 62 | } 63 | 64 | div.sphinxsidebarwrapper p.logo { 65 | padding: 30px 40px 10px 0px; 66 | } 67 | 68 | div.sphinxsidebar h3 { 69 | font-size: 0px; 70 | } 71 | 72 | div.sphinxsidebar a { 73 | border-bottom: 0px; 74 | } 75 | 76 | div.sphinxsidebar a:hover { 77 | border-bottom: 1px dotted; 78 | } 79 | -------------------------------------------------------------------------------- /document/legacy/exceptions/core/static/webassembly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssembly/js-string-builtins/dd601fb2f298119e1cc0f64c44cbcf45ab6d3ef7/document/legacy/exceptions/core/static/webassembly.png -------------------------------------------------------------------------------- /document/legacy/exceptions/core/syntax.rst: -------------------------------------------------------------------------------- 1 | .. _syntax: 2 | 3 | Structure 4 | ========= 5 | 6 | .. _syntax-instr: 7 | 8 | Instructions 9 | ------------ 10 | 11 | .. _syntax-try: 12 | .. _syntax-try-catch: 13 | .. _syntax-try-delegate: 14 | .. _syntax-rethrow: 15 | .. _syntax-instr-control: 16 | 17 | Control Instructions 18 | ~~~~~~~~~~~~~~~~~~~~ 19 | 20 | The set of recognised instructions is extended with the following: 21 | 22 | .. math:: 23 | \begin{array}{llcl} 24 | \production{instruction} & \instr &::=& 25 | \dots \\&&|& 26 | \TRY~\blocktype~\instr^\ast~(\CATCH~\tagidx~\instr^\ast)^\ast~(\CATCHALL~\instr^\ast)^?~\END \\ &&|& 27 | \TRY~\blocktype~\instr^\ast~\DELEGATE~\labelidx \\ &&|& 28 | \RETHROW~\labelidx \\ 29 | \end{array} 30 | 31 | The instructions |TRY| and |RETHROW|, are concerned with exceptions. 32 | The |TRY| instruction installs an exception handler, and may either handle exceptions in the case of |CATCH| and |CATCHALL|, 33 | or rethrow them in an outer block in the case of |DELEGATE|. 34 | 35 | The |RETHROW| instruction is only allowed inside a |CATCH| or |CATCHALL| clause and allows rethrowing the caught exception by lexically referring to a the corresponding |TRY|. 36 | 37 | When |TRY|-|DELEGATE| handles an exception, it also behaves similar to a forward jump, 38 | effectively rethrowing the caught exception right before the matching |END|. 39 | -------------------------------------------------------------------------------- /document/legacy/exceptions/core/text.rst: -------------------------------------------------------------------------------- 1 | .. _text: 2 | 3 | Text Format 4 | =========== 5 | 6 | .. _text-instr: 7 | 8 | Instructions 9 | ------------ 10 | 11 | .. _text-blockinstr: 12 | .. _text-plaininstr: 13 | .. _text-instr-control: 14 | 15 | Control Instructions 16 | ~~~~~~~~~~~~~~~~~~~~ 17 | 18 | .. _text-try: 19 | 20 | The label identifier on a structured control instruction may optionally be repeated after the corresponding :math:`\T{end}`, :math:`\T{else}`, :math:`\T{catch}`, :math:`\T{catch\_all}`, and :math:`\T{delegate}` 21 | pseudo instructions, to indicate the matching delimiters. 22 | 23 | .. math:: 24 | \begin{array}{@{}llclll} 25 | \production{block instruction} & \Tblockinstr_I &::=& \dots \\ &&|& 26 | \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~\\&&& 27 | (\text{catch}~~\Tid_1^?~~x{:}\Ttagidx_I~~(\X{in}_2{:}\Tinstr_{I'})^\ast)^\ast~~ \\&&& 28 | (\text{catch\_all}~~\Tid_1^?~~(\X{in}_3{:}\Tinstr_{I'})^\ast)^?~~ \\&&& 29 | \text{end}~~\Tid_2^? 30 | \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~(\CATCH~x~\X{in}_2^\ast)^\ast~(\CATCHALL~\X{in}_3^\ast)^?~\END 31 | \\ &&&\qquad\qquad (\iff \Tid_1^? = \epsilon \vee \Tid_1^? = \Tlabel, \Tid_2^? = \epsilon \vee \Tid_2^? = \Tlabel) \\ &&|& 32 | \text{try}~~I'{:}\Tlabel_I~~\X{bt}{:}\Tblocktype~~(\X{in}_1{:}\Tinstr_{I'})^\ast~~ \\&&& 33 | \text{delegate}~~l{:}\Tlabelidx_I~~\X{l}{:}\Tlabelidx_I 34 | \\ &&&\qquad \Rightarrow\quad \TRY~\X{bt}~\X{in}_1^\ast~\DELEGATE~l 35 | \qquad\quad~~ (\iff \Tid^? = \epsilon \vee \Tid^? = \Tlabel) \\ 36 | \production{plain instruction} & \Tplaininstr_I &::=& \dots \\ &&|& 37 | \text{rethrow}~~l{:}\Tlabelidx_I \quad\Rightarrow\quad \RETHROW~l \\ 38 | \end{array} 39 | -------------------------------------------------------------------------------- /document/legacy/exceptions/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 | val decode_with_custom : string -> string -> Ast.module_ * Custom.section list (* raises Code *) 5 | -------------------------------------------------------------------------------- /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_with_custom : Ast.module_ * Custom.section list -> 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/custom/handler_custom.mli: -------------------------------------------------------------------------------- 1 | include Custom.Handler with type format' = Custom.custom' 2 | -------------------------------------------------------------------------------- /interpreter/custom/handler_name.mli: -------------------------------------------------------------------------------- 1 | include Custom.Handler 2 | -------------------------------------------------------------------------------- /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 Value 2 | open Instance 3 | 4 | exception Link of Source.region * string 5 | exception Trap of Source.region * string 6 | exception Exception of Source.region * string 7 | exception Crash of Source.region * string 8 | exception Exhaustion of Source.region * string 9 | 10 | val init : Ast.module_ -> extern list -> module_inst (* raises Link, Trap *) 11 | val invoke : func_inst -> value list -> value list (* raises Trap *) 12 | -------------------------------------------------------------------------------- /interpreter/exec/eval_num.mli: -------------------------------------------------------------------------------- 1 | open Value 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 Value 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.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 Types 8 | open Value 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_val_type t ^ 17 | ", got " ^ string_of_val_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 (NumT I32T) 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 et = 43 | match Utf8.encode name, et with 44 | | "abort", ExternFuncT ct -> ExternFunc (Func.alloc_host ct abort) 45 | | "exit", ExternFuncT ct -> ExternFunc (Func.alloc_host ct 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 Value 7 | open Instance 8 | 9 | 10 | let global (GlobalT (_, t) as gt) = 11 | let v = 12 | match t with 13 | | NumT I32T -> Num (I32 666l) 14 | | NumT I64T -> Num (I64 666L) 15 | | NumT F32T -> Num (F32 (F32.of_float 666.6)) 16 | | NumT F64T -> Num (F64 (F64.of_float 666.6)) 17 | | VecT V128T -> Vec (V128 (V128.I32x4.of_lanes [666l; 666l; 666l; 666l])) 18 | | RefT (_, t) -> Ref (NullRef t) 19 | | BotT -> assert false 20 | in ExternGlobal (Global.alloc gt v) 21 | 22 | let table = 23 | let tt = TableT ({min = 10l; max = Some 20l}, (Null, FuncHT)) in 24 | ExternTable (Table.alloc tt (NullRef FuncHT)) 25 | 26 | let memory = 27 | let mt = MemoryT {min = 1l; max = Some 2l} in 28 | ExternMemory (Memory.alloc mt) 29 | 30 | let func f ft = 31 | let dt = DefT (RecT [SubT (Final, [], DefFuncT ft)], 0l) in 32 | ExternFunc (Func.alloc_host dt (f ft)) 33 | 34 | let print_value v = 35 | Printf.printf "%s : %s\n" 36 | (string_of_value v) (string_of_val_type (type_of_value v)) 37 | 38 | let print _ vs = 39 | List.iter print_value vs; 40 | flush_all (); 41 | [] 42 | 43 | 44 | let lookup name t = 45 | match Utf8.encode name, t with 46 | | "print", _ -> func print (FuncT ([], [])) 47 | | "print_i32", _ -> func print (FuncT ([NumT I32T], [])) 48 | | "print_i64", _ -> func print (FuncT ([NumT I64T], [])) 49 | | "print_f32", _ -> func print (FuncT ([NumT F32T], [])) 50 | | "print_f64", _ -> func print (FuncT ([NumT F64T], [])) 51 | | "print_i32_f32", _ -> func print (FuncT ([NumT I32T; NumT F32T], [])) 52 | | "print_f64_f64", _ -> func print (FuncT ([NumT F64T; NumT F64T], [])) 53 | | "global_i32", _ -> global (GlobalT (Cons, NumT I32T)) 54 | | "global_i64", _ -> global (GlobalT (Cons, NumT I64T)) 55 | | "global_f32", _ -> global (GlobalT (Cons, NumT F32T)) 56 | | "global_f64", _ -> global (GlobalT (Cons, NumT F64T)) 57 | | "table", _ -> table 58 | | "memory", _ -> memory 59 | | _ -> raise Not_found 60 | -------------------------------------------------------------------------------- /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, cs) -> Encode.encode_with_custom (m, cs) 16 | | Script.Encoded (_, bs) -> bs.Source.it 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 custom_reject = ref false 9 | let budget = ref 256 10 | -------------------------------------------------------------------------------- /interpreter/runtime/aggr.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 3 | 4 | type field = 5 | | ValField of value ref 6 | | PackField of Pack.pack_size * int ref 7 | 8 | type struct_ = Struct of def_type * field list 9 | type array = Array of def_type * field list 10 | 11 | type ref_ += StructRef of struct_ 12 | type ref_ += ArrayRef of array 13 | 14 | val alloc_struct : def_type -> value list -> struct_ 15 | val alloc_array : def_type -> value list -> array 16 | 17 | val type_of_struct : struct_ -> def_type 18 | val type_of_array : array -> def_type 19 | 20 | val read_field : field -> Pack.extension option -> value (* raises Failure *) 21 | val write_field : field -> value -> unit (* raises Falure *) 22 | 23 | val array_length : array -> int32 24 | -------------------------------------------------------------------------------- /interpreter/runtime/data.ml: -------------------------------------------------------------------------------- 1 | type data = string ref 2 | type t = data 3 | type address = Memory.address 4 | 5 | exception Bounds 6 | 7 | let alloc bs = ref bs 8 | 9 | let size seg = I64.of_int_u (String.length !seg) 10 | 11 | let drop seg = seg := "" 12 | 13 | let load_byte seg a = 14 | let i = Int64.to_int a in 15 | if i < 0 || i >= String.length !seg then raise Bounds; 16 | !seg.[i] 17 | 18 | let load_bytes seg a n = 19 | let i = Int64.to_int a in 20 | if i < 0 || i + n < 0 || i + n > String.length !seg then raise Bounds; 21 | String.sub !seg i n 22 | 23 | 24 | (* Typed accessors *) 25 | 26 | let load_num seg a nt = 27 | let bs = load_bytes seg a (Types.num_size nt) in 28 | Value.num_of_bits nt bs 29 | 30 | let load_num_packed sz ext seg a nt = 31 | let bs = load_bytes seg a (Pack.packed_size sz) in 32 | Value.num_of_packed_bits nt sz ext bs 33 | 34 | let load_vec seg a vt = 35 | let bs = load_bytes seg a (Types.vec_size vt) in 36 | Value.vec_of_bits vt bs 37 | 38 | let load_vec_packed sz ext seg a t = 39 | let bs = load_bytes seg a (Pack.packed_size sz) in 40 | Value.vec_of_packed_bits t sz ext bs 41 | 42 | let load_val seg a t = 43 | let bs = load_bytes seg a (Types.val_size t) in 44 | Value.val_of_bits t bs 45 | 46 | let load_val_storage seg a st = 47 | let bs = load_bytes seg a (Types.storage_size st) in 48 | Value.val_of_storage_bits st bs 49 | -------------------------------------------------------------------------------- /interpreter/runtime/data.mli: -------------------------------------------------------------------------------- 1 | type data 2 | type t = data 3 | type address = Memory.address 4 | 5 | exception Bounds 6 | 7 | val alloc : string -> data 8 | val size : data -> address 9 | val drop : data -> unit 10 | 11 | val load_byte : data -> address -> char (* raises Bounds *) 12 | val load_bytes : data -> address -> int -> string (* raises Bounds *) 13 | 14 | 15 | (* Typed accessors *) 16 | 17 | open Types 18 | open Value 19 | 20 | val load_num : data -> address -> num_type -> num (* raises Bounds *) 21 | val load_vec : data -> address -> vec_type -> vec (* raises Bounds *) 22 | val load_val : data -> address -> val_type -> value (* raises Type, Bounds *) 23 | 24 | val load_num_packed : 25 | Pack.pack_size -> Pack.extension -> data -> address -> num_type -> num 26 | (* raises Type, Bounds *) 27 | val load_vec_packed : 28 | Pack.pack_size -> Pack.vec_extension -> data -> address -> vec_type -> vec 29 | (* raises Type, Bounds *) 30 | val load_val_storage : 31 | data -> address -> storage_type -> value (* raises Type, Bounds *) 32 | -------------------------------------------------------------------------------- /interpreter/runtime/elem.ml: -------------------------------------------------------------------------------- 1 | type elem = Value.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 Value 2 | 3 | type elem 4 | type t = elem 5 | 6 | exception Bounds 7 | 8 | val alloc : ref_ list -> elem 9 | val size : elem -> Table.size 10 | val load : elem -> Table.index -> ref_ (* raises Bounds *) 11 | val drop : elem -> unit 12 | -------------------------------------------------------------------------------- /interpreter/runtime/exn.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 3 | 4 | type exn_ = Exn of Tag.t * value list 5 | 6 | type ref_ += ExnRef of exn_ 7 | 8 | let alloc_exn tag vs = 9 | let TagT dt = Tag.type_of tag in 10 | assert Free.((def_type dt).types = Set.empty); 11 | let FuncT (ts1, ts2) = as_func_str_type (expand_def_type dt) in 12 | assert (List.length vs = List.length ts1); 13 | assert (ts2 = []); 14 | Exn (tag, vs) 15 | 16 | let type_of (Exn (tag, _)) = 17 | let TagT dt = Tag.type_of tag in 18 | dt 19 | 20 | let () = 21 | let eq_ref' = !Value.eq_ref' in 22 | Value.eq_ref' := fun r1 r2 -> 23 | match r1, r2 with 24 | | ExnRef _, ExnRef _ -> failwith "eq_ref" 25 | | _, _ -> eq_ref' r1 r2 26 | 27 | let () = 28 | let type_of_ref' = !Value.type_of_ref' in 29 | Value.type_of_ref' := function 30 | | ExnRef e -> DefHT (type_of e) 31 | | r -> type_of_ref' r 32 | 33 | let () = 34 | let string_of_ref' = !Value.string_of_ref' in 35 | Value.string_of_ref' := function 36 | | ExnRef (Exn (_tag, vs)) -> 37 | "(tag " ^ String.concat " " (List.map string_of_value vs) ^ ")" 38 | | r -> string_of_ref' r 39 | -------------------------------------------------------------------------------- /interpreter/runtime/exn.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 3 | 4 | type exn_ = Exn of Tag.t * value list 5 | 6 | type ref_ += ExnRef of exn_ 7 | 8 | val alloc_exn : Tag.t -> value list -> exn_ 9 | 10 | val type_of : exn_ -> def_type 11 | -------------------------------------------------------------------------------- /interpreter/runtime/extern.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 3 | 4 | type extern = ref_ 5 | type t = extern 6 | 7 | type ref_ += ExternRef of extern 8 | 9 | let () = 10 | let eq_ref' = !Value.eq_ref' in 11 | Value.eq_ref' := fun r1 r2 -> 12 | match r1, r2 with 13 | | ExternRef r1', ExternRef r2' -> Value.eq_ref r1' r2' 14 | | _, _ -> eq_ref' r1 r2 15 | 16 | let () = 17 | let type_of_ref' = !Value.type_of_ref' in 18 | Value.type_of_ref' := function 19 | | ExternRef _ -> ExternHT 20 | | r -> type_of_ref' r 21 | 22 | let () = 23 | let string_of_ref' = !Value.string_of_ref' in 24 | Value.string_of_ref' := function 25 | | ExternRef r -> "(extern " ^ string_of_ref r ^ ")" 26 | | r -> string_of_ref' r 27 | -------------------------------------------------------------------------------- /interpreter/runtime/extern.mli: -------------------------------------------------------------------------------- 1 | open Value 2 | 3 | type extern = ref_ 4 | type t = extern 5 | 6 | type ref_ += ExternRef of extern 7 | -------------------------------------------------------------------------------- /interpreter/runtime/func.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 3 | 4 | type 'inst t = 'inst func 5 | and 'inst func = 6 | | AstFunc of def_type * 'inst * Ast.func 7 | | HostFunc of def_type * (value list -> value list) 8 | 9 | let alloc dt inst f = 10 | ignore (as_func_str_type (expand_def_type dt)); 11 | assert Free.((def_type dt).types = Set.empty); 12 | AstFunc (dt, inst, f) 13 | 14 | let alloc_host dt f = 15 | ignore (as_func_str_type (expand_def_type dt)); 16 | HostFunc (dt, f) 17 | 18 | let type_of = function 19 | | AstFunc (dt, _, _) -> dt 20 | | HostFunc (dt, _) -> dt 21 | -------------------------------------------------------------------------------- /interpreter/runtime/func.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 3 | 4 | type 'inst t = 'inst func 5 | and 'inst func = 6 | | AstFunc of def_type * 'inst * Ast.func 7 | | HostFunc of def_type * (value list -> value list) 8 | 9 | val alloc : def_type -> 'inst -> Ast.func -> 'inst func 10 | val alloc_host : def_type -> (value list -> value list) -> 'inst func 11 | 12 | val type_of : 'inst func -> def_type 13 | -------------------------------------------------------------------------------- /interpreter/runtime/global.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 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 (GlobalT (_mut, t) as ty) v = 11 | assert Free.((val_type t).types = Set.empty); 12 | if not (Match.match_val_type [] (type_of_value v) t) then raise Type; 13 | {ty; content = v} 14 | 15 | let type_of glob = 16 | glob.ty 17 | 18 | let load glob = 19 | glob.content 20 | 21 | let store glob v = 22 | let GlobalT (mut, t) = glob.ty in 23 | if mut <> Var then raise NotMutable; 24 | if not (Match.match_val_type [] (type_of_value v) t) then raise Type; 25 | glob.content <- v 26 | -------------------------------------------------------------------------------- /interpreter/runtime/global.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 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/i31.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 3 | 4 | type i31 = int 5 | type t = i31 6 | 7 | type ref_ += I31Ref of i31 8 | 9 | let of_i32 i = Int32.to_int i land 0x7fff_ffff 10 | let to_i32 ext i = 11 | let i' = Int32.of_int i in 12 | match ext with 13 | | Pack.ZX -> i' 14 | | Pack.SX -> Int32.(shift_right (shift_left i' 1) 1) 15 | 16 | let () = 17 | let eq_ref' = !Value.eq_ref' in 18 | Value.eq_ref' := fun r1 r2 -> 19 | match r1, r2 with 20 | | I31Ref i1, I31Ref i2 -> i1 = i2 21 | | _, _ -> eq_ref' r1 r2 22 | 23 | let () = 24 | let type_of_ref' = !Value.type_of_ref' in 25 | Value.type_of_ref' := function 26 | | I31Ref f -> I31HT 27 | | r -> type_of_ref' r 28 | 29 | let () = 30 | let string_of_ref' = !Value.string_of_ref' in 31 | Value.string_of_ref' := function 32 | | I31Ref i -> "(i31 " ^ string_of_int i ^ ")" 33 | | r -> string_of_ref' r 34 | -------------------------------------------------------------------------------- /interpreter/runtime/i31.mli: -------------------------------------------------------------------------------- 1 | open Value 2 | 3 | type i31 = int 4 | type t = i31 5 | 6 | type ref_ += I31Ref of i31 7 | 8 | val of_i32 : int32 -> i31 9 | val to_i32 : Pack.extension -> i31 -> int32 10 | -------------------------------------------------------------------------------- /interpreter/runtime/memory.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | 3 | type memory 4 | type t = memory 5 | 6 | type size = int32 (* number of pages *) 7 | type address = int64 8 | type offset = int32 9 | type count = int32 10 | 11 | exception Type 12 | exception Bounds 13 | exception SizeOverflow 14 | exception SizeLimit 15 | exception OutOfMemory 16 | 17 | val page_size : int64 18 | 19 | val alloc : memory_type -> memory (* raises Type, SizeOverflow, OutOfMemory *) 20 | val type_of : memory -> memory_type 21 | val size : memory -> size 22 | val bound : memory -> address 23 | val grow : memory -> size -> unit 24 | (* raises SizeLimit, SizeOverflow, OutOfMemory *) 25 | 26 | val load_byte : memory -> address -> int (* raises Bounds *) 27 | val store_byte : memory -> address -> int -> unit (* raises Bounds *) 28 | val load_bytes : memory -> address -> int -> string (* raises Bounds *) 29 | val store_bytes : memory -> address -> string -> unit (* raises Bounds *) 30 | 31 | 32 | (* Typed accessors *) 33 | 34 | open Value 35 | 36 | val load_num : 37 | memory -> address -> offset -> num_type -> num (* raises Bounds *) 38 | val store_num : 39 | memory -> address -> offset -> num -> unit (* raises Bounds *) 40 | val load_num_packed : 41 | Pack.pack_size -> Pack.extension -> memory -> address -> offset -> num_type -> num 42 | (* raises Type, Bounds *) 43 | val store_num_packed : 44 | Pack.pack_size -> memory -> address -> offset -> num -> unit 45 | (* raises Type, Bounds *) 46 | 47 | val load_vec : 48 | memory -> address -> offset -> vec_type -> vec (* raises Bounds *) 49 | val store_vec : 50 | memory -> address -> offset -> vec -> unit 51 | (* raises Type, Bounds *) 52 | val load_vec_packed : 53 | Pack.pack_size -> Pack.vec_extension -> memory -> address -> offset -> vec_type -> vec 54 | (* raises Type, Bounds *) 55 | 56 | val load_val : 57 | memory -> address -> offset -> val_type -> value (* raises Type, Bounds *) 58 | val store_val : 59 | memory -> address -> offset -> value -> unit (* raises Type, Bounds *) 60 | val load_val_storage : 61 | memory -> address -> offset -> storage_type -> value (* raises Type, Bounds *) 62 | val store_val_storage : 63 | memory -> address -> offset -> storage_type -> value -> unit (* raises Type, Bounds *) 64 | -------------------------------------------------------------------------------- /interpreter/runtime/table.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 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 (TableT (lim, t) as ty) r = 27 | assert Free.((ref_type t).types = Set.empty); 28 | if not (valid_limits lim) then raise Type; 29 | {ty; content = create lim.min r} 30 | 31 | let size tab = 32 | Lib.Array32.length tab.content 33 | 34 | let type_of tab = 35 | tab.ty 36 | 37 | let grow tab delta r = 38 | let TableT (lim, t) = tab.ty in 39 | assert (lim.min = size tab); 40 | let old_size = lim.min in 41 | let new_size = Int32.add old_size delta in 42 | if I32.gt_u old_size new_size then raise SizeOverflow else 43 | let lim' = {lim with min = new_size} in 44 | if not (valid_limits lim') then raise SizeLimit else 45 | let after = create new_size r in 46 | Array.blit tab.content 0 after 0 (Array.length tab.content); 47 | tab.ty <- TableT (lim', t); 48 | tab.content <- after 49 | 50 | let load tab i = 51 | if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; 52 | Lib.Array32.get tab.content i 53 | 54 | let store tab i r = 55 | let TableT (lim, t) = tab.ty in 56 | if not (Match.match_ref_type [] (type_of_ref r) t) then raise Type; 57 | if i < 0l || i >= Lib.Array32.length tab.content then raise Bounds; 58 | Lib.Array32.set tab.content i r 59 | 60 | let blit tab offset rs = 61 | let data = Array.of_list rs in 62 | let len = Lib.Array32.length data in 63 | if offset < 0l || offset > Int32.sub (Lib.Array32.length tab.content) len then raise Bounds; 64 | Lib.Array32.blit data 0l tab.content offset len 65 | -------------------------------------------------------------------------------- /interpreter/runtime/table.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | open Value 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/runtime/tag.ml: -------------------------------------------------------------------------------- 1 | open Types 2 | 3 | type tag = {ty : tag_type} 4 | type t = tag 5 | 6 | let alloc ty = 7 | {ty} 8 | 9 | let type_of tg = 10 | tg.ty 11 | -------------------------------------------------------------------------------- /interpreter/runtime/tag.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | 3 | type tag 4 | type t = tag 5 | 6 | val alloc : tag_type -> tag 7 | val type_of : tag -> tag_type 8 | -------------------------------------------------------------------------------- /interpreter/script/import.ml: -------------------------------------------------------------------------------- 1 | open Source 2 | open Ast 3 | open Types 4 | 5 | module Unknown = Error.Make () 6 | exception Unknown = Unknown.Error (* indicates unknown import name *) 7 | 8 | module Registry = Map.Make(struct type t = Ast.name let compare = compare end) 9 | let registry = ref Registry.empty 10 | 11 | let register name lookup = registry := Registry.add name lookup !registry 12 | 13 | let lookup (ImportT (et, module_name, item_name)) at : Instance.extern = 14 | try Registry.find module_name !registry item_name et with Not_found -> 15 | Unknown.error at 16 | ("unknown import \"" ^ Types.string_of_name module_name ^ 17 | "\".\"" ^ Types.string_of_name item_name ^ "\"") 18 | 19 | let link m = 20 | let ModuleT (its, _) = module_type_of m in 21 | List.map2 lookup its (List.map Source.at m.it.imports) 22 | -------------------------------------------------------------------------------- /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/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 | tags : Set.t; 10 | funcs : Set.t; 11 | elems : Set.t; 12 | datas : Set.t; 13 | locals : Set.t; 14 | labels : Set.t; 15 | } 16 | 17 | val empty : t 18 | val union : t -> t -> t 19 | 20 | val num_type : Types.num_type -> t 21 | val vec_type : Types.vec_type -> t 22 | val ref_type : Types.ref_type -> t 23 | val val_type : Types.val_type -> t 24 | 25 | val func_type : Types.func_type -> t 26 | val global_type : Types.global_type -> t 27 | val table_type : Types.table_type -> t 28 | val memory_type : Types.memory_type -> t 29 | val tag_type : Types.tag_type -> t 30 | val extern_type : Types.extern_type -> t 31 | 32 | val str_type : Types.str_type -> t 33 | val sub_type : Types.sub_type -> t 34 | val rec_type : Types.rec_type -> t 35 | val def_type : Types.def_type -> t 36 | 37 | val instr : Ast.instr -> t 38 | val block : Ast.instr list -> t 39 | val const : Ast.const -> t 40 | 41 | val type_ : Ast.type_ -> t 42 | val global : Ast.global -> t 43 | val func : Ast.func -> t 44 | val table : Ast.table -> t 45 | val memory : Ast.memory -> t 46 | val tag : Ast.tag -> t 47 | val elem : Ast.elem_segment -> t 48 | val data : Ast.data_segment -> t 49 | val export : Ast.export -> t 50 | val import : Ast.import -> t 51 | val start : Ast.start -> t 52 | 53 | val module_ : Ast.module_ -> t 54 | 55 | val opt : ('a -> t) -> 'a option -> t 56 | val list : ('a -> t) -> 'a list -> t 57 | -------------------------------------------------------------------------------- /interpreter/syntax/pack.ml: -------------------------------------------------------------------------------- 1 | type pack_size = Pack8 | Pack16 | Pack32 | Pack64 2 | type extension = SX | ZX 3 | 4 | type pack_shape = Pack8x8 | Pack16x4 | Pack32x2 5 | type vec_extension = 6 | | ExtLane of pack_shape * extension 7 | | ExtSplat 8 | | ExtZero 9 | 10 | let packed_size = function 11 | | Pack8 -> 1 12 | | Pack16 -> 2 13 | | Pack32 -> 4 14 | | Pack64 -> 8 15 | 16 | let packed_shape_size = function 17 | | Pack8x8 | Pack16x4 | Pack32x2 -> 8 18 | -------------------------------------------------------------------------------- /interpreter/text/annot.ml: -------------------------------------------------------------------------------- 1 | open Source 2 | 3 | type annot = annot' Source.phrase 4 | and annot' = {name : Ast.name; items : item list} 5 | 6 | and item = item' Source.phrase 7 | and item' = 8 | | Atom of string 9 | | Var of string 10 | | String of string 11 | | Nat of string 12 | | Int of string 13 | | Float of string 14 | | Parens of item list 15 | | Annot of annot 16 | 17 | 18 | (* Stateful recorder for annotations *) 19 | (* I wish this could be encapsulated in the parser somehow *) 20 | 21 | module NameMap = Map.Make(struct type t = Ast.name let compare = compare end) 22 | type map = annot list NameMap.t 23 | 24 | let current : map ref = ref NameMap.empty 25 | let current_source : Buffer.t = Buffer.create 512 26 | 27 | let reset () = 28 | current := NameMap.empty; 29 | Buffer.clear current_source 30 | 31 | let get_source () = 32 | Buffer.contents current_source 33 | 34 | let extend_source s = 35 | Buffer.add_string current_source s 36 | 37 | let record annot = 38 | let old = Option.value (NameMap.find_opt annot.it.name !current) ~default:[] in 39 | current := NameMap.add annot.it.name (annot::old) !current 40 | 41 | let is_contained r1 r2 = r1.left >= r2.left && r1.right <= r2.right 42 | 43 | let get_all () = 44 | let all = !current in 45 | current := NameMap.empty; 46 | all 47 | 48 | let filter f map = 49 | NameMap.filter (fun _ annots -> annots <> []) 50 | (NameMap.map (List.filter f) map) 51 | 52 | let get r = 53 | let sub = filter (fun annot -> is_contained annot.at r) !current in 54 | let map' = filter (fun annot -> not (is_contained annot.at r)) !current in 55 | current := map'; 56 | sub 57 | -------------------------------------------------------------------------------- /interpreter/text/annot.mli: -------------------------------------------------------------------------------- 1 | type annot = annot' Source.phrase 2 | and annot' = {name : Ast.name; items : item list} 3 | 4 | and item = item' Source.phrase 5 | and item' = 6 | | Atom of string 7 | | Var of string 8 | | String of string 9 | | Nat of string 10 | | Int of string 11 | | Float of string 12 | | Parens of item list 13 | | Annot of annot 14 | 15 | module NameMap : Map.S with type key = Ast.name 16 | type map = annot list NameMap.t 17 | 18 | val reset : unit -> unit 19 | val record : annot -> unit 20 | 21 | val get : Source.region -> map 22 | val get_all : unit -> map 23 | 24 | val get_source : unit -> string 25 | val extend_source : string -> unit 26 | -------------------------------------------------------------------------------- /interpreter/text/arrange.mli: -------------------------------------------------------------------------------- 1 | open Sexpr 2 | 3 | val bytes : string -> string 4 | val string : string -> string 5 | val name : Ast.name -> string 6 | 7 | val break_bytes : string -> sexpr list 8 | val break_string : string -> sexpr list 9 | 10 | val instr : Ast.instr -> sexpr 11 | val func : Ast.func -> sexpr 12 | val module_ : Ast.module_ -> sexpr 13 | val module_with_custom : Ast.module_ * Custom.section list -> sexpr 14 | val script : [`Textual | `Binary] -> Script.script -> sexpr list 15 | -------------------------------------------------------------------------------- /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.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 (* raises Syntax *) 7 | val parse_file : string -> t (* raises Syntax *) 8 | val parse_string : ?offset:Source.region -> string -> t (* raises Syntax *) 9 | val parse_channel : in_channel -> t (* raises Syntax *) 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 module_with_custom oc width m_cs = Sexpr.output oc width (Arrange.module_with_custom m_cs) 5 | let script oc width mode s = 6 | List.iter (Sexpr.output oc width) (Arrange.script mode s) 7 | -------------------------------------------------------------------------------- /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 module_with_custom : out_channel -> int -> Ast.module_ * Custom.section list -> unit 5 | val script : out_channel -> int -> [`Textual | `Binary] -> Script.script -> unit 6 | -------------------------------------------------------------------------------- /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 it phrase = phrase.it 7 | let at phrase = phrase.at 8 | 9 | 10 | (* Positions and regions *) 11 | 12 | let no_pos = {file = ""; line = 0; column = 0} 13 | let no_region = {left = no_pos; right = no_pos} 14 | let all_region file = 15 | { left = {file; line = 0; column = 0}; 16 | right = {file; line = Int.max_int; column = Int.max_int} 17 | } 18 | 19 | let string_of_pos pos = 20 | if pos.line = -1 then 21 | Printf.sprintf "0x%x" pos.column 22 | else 23 | string_of_int pos.line ^ "." ^ string_of_int (pos.column + 1) 24 | 25 | let string_of_region r = 26 | r.left.file ^ ":" ^ string_of_pos r.left ^ 27 | (if r.right = r.left then "" else "-" ^ string_of_pos r.right) 28 | -------------------------------------------------------------------------------- /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 | val all_region : string -> region 8 | 9 | val string_of_pos : pos -> string 10 | val string_of_region : region -> string 11 | 12 | val (@@) : 'a -> region -> 'a phrase 13 | val it : 'a phrase -> 'a 14 | val at : 'a phrase -> region 15 | -------------------------------------------------------------------------------- /interpreter/valid/match.mli: -------------------------------------------------------------------------------- 1 | open Types 2 | 3 | 4 | (* Context *) 5 | 6 | type context = def_type list 7 | 8 | 9 | (* Extremas *) 10 | 11 | val top_of_heap_type : context -> heap_type -> heap_type 12 | val bot_of_heap_type : context -> heap_type -> heap_type 13 | val top_of_str_type : context -> str_type -> heap_type 14 | val bot_of_str_type : context -> str_type -> heap_type 15 | 16 | 17 | (* Subtyping *) 18 | 19 | val match_num_type : context -> num_type -> num_type -> bool 20 | val match_ref_type : context -> ref_type -> ref_type -> bool 21 | val match_val_type : context -> val_type -> val_type -> bool 22 | 23 | val match_result_type : context -> result_type -> result_type -> bool 24 | 25 | val match_storage_type : context -> storage_type -> storage_type -> bool 26 | 27 | val match_str_type : context -> str_type -> str_type -> bool 28 | val match_def_type : context -> def_type -> def_type -> bool 29 | 30 | val match_func_type : context -> func_type -> func_type -> bool 31 | 32 | val match_table_type : context -> table_type -> table_type -> bool 33 | val match_memory_type : context -> memory_type -> memory_type -> bool 34 | val match_global_type : context -> global_type -> global_type -> bool 35 | 36 | val match_extern_type : context -> extern_type -> extern_type -> bool 37 | -------------------------------------------------------------------------------- /interpreter/valid/valid.mli: -------------------------------------------------------------------------------- 1 | exception Invalid of Source.region * string 2 | 3 | val check_module : Ast.module_ -> unit (* raises Invalid *) 4 | val check_module_with_custom : Ast.module_ * Custom.section list -> unit (* raises Invalid, Custom.Check *) 5 | -------------------------------------------------------------------------------- /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/js-string-builtins/dd601fb2f298119e1cc0f64c44cbcf45ab6d3ef7/papers/oopsla2019.pdf -------------------------------------------------------------------------------- /papers/pldi2017.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WebAssembly/js-string-builtins/dd601fb2f298119e1cc0f64c44cbcf45ab6d3ef7/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/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/js-string-builtins/dd601fb2f298119e1cc0f64c44cbcf45ab6d3ef7/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/gc/binary-gc.wast: -------------------------------------------------------------------------------- 1 | (assert_malformed 2 | (module binary 3 | "\00asm" "\01\00\00\00" 4 | "\01" ;; Type section id 5 | "\04" ;; Type section length 6 | "\01" ;; Types vector length 7 | "\5e" ;; Array type, -0x22 8 | "\78" ;; Storage type: i8 or -0x08 9 | "\02" ;; Mutability, should be 0 or 1, but isn't 10 | ) 11 | "malformed mutability" 12 | ) 13 | -------------------------------------------------------------------------------- /test/core/id.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (func $fg) (func (call $fg)) 3 | (func $03) (func (call $03)) 4 | (func $!?@#a$%^&*b-+_.:9'`|/\<=>~) (func (call $!?@#a$%^&*b-+_.:9'`|/\<=>~)) 5 | (func $" random \t \n stuff ") (func (call $" random \t \n stuff ")) 6 | (func $" ") (func (call $" ")) 7 | 8 | (func $fh) (func (call $"fh")) 9 | (func $"fi") (func (call $fi)) 10 | (func $!?@#a$%^&*-+_.:9'`|/\<=>~) (func (call $"!?@#a$%^&*-+_.:9'`|/\\<=>~")) 11 | 12 | (func $"\41B") (func (call $"AB") (call $"A\42") (call $"\41\42") (call $"\u{41}\u{42}")) 13 | (func $"\t") (func (call $"\09") (call $"\u{09}")) 14 | (func $"") (func (call $"\ef\98\9a\ef\92\a9") (call $"\u{f61a}\u{f4a9}")) 15 | 16 | (func 17 | block $l1 (br $"l1") end $"l1" 18 | block $007 (br $"007") end $"007" 19 | block $!?@#a$%^&*-+_.:9'`|/\<=>~ end $"!?@#a$%^&*-+_.:9'`|/\\<=>~" 20 | (i32.const 0) if $"\41B" (br $AB) else $"A\42" end $"\u{41}\u{42}" 21 | (i32.const 0) if $"\t" else $"\09" end $"\u{09}" 22 | (i32.const 0) if $" " else $"\ef\98\9a\ef\92\a9 " end $"\u{f61a}\u{f4a9} " 23 | ) 24 | ) 25 | 26 | (assert_malformed (module quote "(func $)") "empty identifier") 27 | (assert_malformed (module quote "(func $\"\")") "empty identifier") 28 | (assert_malformed (module quote "(func $ \"a\")") "empty identifier") 29 | (assert_malformed (module quote "(func $\"a\nb\")") "empty identifier") 30 | (assert_malformed (module quote "(func $\"a\tb\")") "empty identifier") 31 | (assert_malformed (module quote "(func $\"\\ef\")") "malformed UTF-8") 32 | -------------------------------------------------------------------------------- /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/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/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/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/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/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_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/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.wast: -------------------------------------------------------------------------------- 1 | ;; Syntax 2 | 3 | (module 4 | (type $t (func)) 5 | 6 | (func 7 | (param 8 | funcref 9 | externref 10 | (ref func) 11 | (ref extern) 12 | (ref 0) 13 | (ref $t) 14 | (ref 0) 15 | (ref $t) 16 | (ref null func) 17 | (ref null extern) 18 | (ref null 0) 19 | (ref null $t) 20 | ) 21 | ) 22 | ) 23 | 24 | 25 | ;; Undefined type index. 26 | 27 | (assert_invalid 28 | (module (type $type-func-param-invalid (func (param (ref 1))))) 29 | "unknown type" 30 | ) 31 | (assert_invalid 32 | (module (type $type-func-result-invalid (func (result (ref 1))))) 33 | "unknown type" 34 | ) 35 | 36 | (assert_invalid 37 | (module (global $global-invalid (ref null 1) (ref.null 1))) 38 | "unknown type" 39 | ) 40 | 41 | (assert_invalid 42 | (module (table $table-invalid 10 (ref null 1))) 43 | "unknown type" 44 | ) 45 | 46 | (assert_invalid 47 | (module (elem $elem-invalid (ref 1))) 48 | "unknown type" 49 | ) 50 | 51 | (assert_invalid 52 | (module (func $func-param-invalid (param (ref 1)))) 53 | "unknown type" 54 | ) 55 | (assert_invalid 56 | (module (func $func-result-invalid (result (ref 1)))) 57 | "unknown type" 58 | ) 59 | (assert_invalid 60 | (module (func $func-local-invalid (local (ref null 1)))) 61 | "unknown type" 62 | ) 63 | 64 | (assert_invalid 65 | (module (func $block-result-invalid (drop (block (result (ref 1)) (unreachable))))) 66 | "unknown type" 67 | ) 68 | (assert_invalid 69 | (module (func $loop-result-invalid (drop (loop (result (ref 1)) (unreachable))))) 70 | "unknown type" 71 | ) 72 | (assert_invalid 73 | (module (func $if-invalid (drop (if (result (ref 1)) (then) (else))))) 74 | "unknown type" 75 | ) 76 | 77 | (assert_invalid 78 | (module (func $select-result-invalid (drop (select (result (ref 1)) (unreachable))))) 79 | "unknown type" 80 | ) 81 | -------------------------------------------------------------------------------- /test/core/ref_as_non_null.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func (result i32))) 3 | 4 | (func $nn (param $r (ref $t)) (result i32) 5 | (call_ref $t (ref.as_non_null (local.get $r))) 6 | ) 7 | (func $n (param $r (ref null $t)) (result i32) 8 | (call_ref $t (ref.as_non_null (local.get $r))) 9 | ) 10 | 11 | (elem func $f) 12 | (func $f (result i32) (i32.const 7)) 13 | 14 | (func (export "nullable-null") (result i32) (call $n (ref.null $t))) 15 | (func (export "nonnullable-f") (result i32) (call $nn (ref.func $f))) 16 | (func (export "nullable-f") (result i32) (call $n (ref.func $f))) 17 | 18 | (func (export "unreachable") (result i32) 19 | (unreachable) 20 | (ref.as_non_null) 21 | (call $nn) 22 | ) 23 | ) 24 | 25 | (assert_trap (invoke "unreachable") "unreachable") 26 | 27 | (assert_trap (invoke "nullable-null") "null reference") 28 | (assert_return (invoke "nonnullable-f") (i32.const 7)) 29 | (assert_return (invoke "nullable-f") (i32.const 7)) 30 | 31 | (assert_invalid 32 | (module 33 | (type $t (func (result i32))) 34 | (func $g (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) 35 | (func (call $g (ref.null $t))) 36 | ) 37 | "type mismatch" 38 | ) 39 | 40 | 41 | (module 42 | (type $t (func)) 43 | (func (param $r (ref $t)) (drop (ref.as_non_null (local.get $r)))) 44 | (func (param $r (ref func)) (drop (ref.as_non_null (local.get $r)))) 45 | (func (param $r (ref extern)) (drop (ref.as_non_null (local.get $r)))) 46 | ) 47 | -------------------------------------------------------------------------------- /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_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/table-sub.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (type $t (func)) 3 | (table $t1 10 (ref null func)) 4 | (table $t2 10 (ref null $t)) 5 | (elem $el funcref) 6 | (func $f 7 | (table.init $t1 $el (i32.const 0) (i32.const 1) (i32.const 2)) 8 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 9 | ) 10 | ) 11 | 12 | (assert_invalid 13 | (module 14 | (table $t1 10 funcref) 15 | (table $t2 10 externref) 16 | (func $f 17 | (table.copy $t1 $t2 (i32.const 0) (i32.const 1) (i32.const 2)) 18 | ) 19 | ) 20 | "type mismatch" 21 | ) 22 | 23 | (assert_invalid 24 | (module 25 | (table $t 10 funcref) 26 | (elem $el externref) 27 | (func $f 28 | (table.init $t $el (i32.const 0) (i32.const 1) (i32.const 2)) 29 | ) 30 | ) 31 | "type mismatch" 32 | ) 33 | -------------------------------------------------------------------------------- /test/core/tag.wast: -------------------------------------------------------------------------------- 1 | ;; Test tag section 2 | 3 | (module 4 | (tag) 5 | (tag (param i32)) 6 | (tag (export "t2") (param i32)) 7 | (tag $t3 (param i32 f32)) 8 | (export "t3" (tag 3)) 9 | ) 10 | 11 | (register "test") 12 | 13 | (module 14 | (tag $t0 (import "test" "t2") (param i32)) 15 | (import "test" "t3" (tag $t1 (param i32 f32))) 16 | ) 17 | 18 | (assert_invalid 19 | (module (tag (result i32))) 20 | "non-empty tag result type" 21 | ) 22 | 23 | 24 | ;; Link-time typing 25 | 26 | (module 27 | (rec 28 | (type $t1 (func)) 29 | (type $t2 (func)) 30 | ) 31 | (tag (export "tag") (type $t1)) 32 | ) 33 | 34 | (register "M") 35 | 36 | (module 37 | (rec 38 | (type $t1 (func)) 39 | (type $t2 (func)) 40 | ) 41 | (tag (import "M" "tag") (type $t1)) 42 | ) 43 | 44 | (assert_unlinkable 45 | (module 46 | (rec 47 | (type $t1 (func)) 48 | (type $t2 (func)) 49 | ) 50 | (tag (import "M" "tag") (type $t2)) 51 | ) 52 | "incompatible import" 53 | ) 54 | 55 | (assert_unlinkable 56 | (module 57 | (type $t (func)) 58 | (tag (import "M" "tag") (type $t)) 59 | ) 60 | "incompatible import" 61 | ) 62 | -------------------------------------------------------------------------------- /test/core/throw.wast: -------------------------------------------------------------------------------- 1 | ;; Test throw instruction. 2 | 3 | (module 4 | (tag $e0) 5 | (tag $e-i32 (param i32)) 6 | (tag $e-f32 (param f32)) 7 | (tag $e-i64 (param i64)) 8 | (tag $e-f64 (param f64)) 9 | (tag $e-i32-i32 (param i32 i32)) 10 | 11 | (func $throw-if (export "throw-if") (param i32) (result i32) 12 | (local.get 0) 13 | (i32.const 0) (if (i32.ne) (then (throw $e0))) 14 | (i32.const 0) 15 | ) 16 | 17 | (func (export "throw-param-f32") (param f32) (local.get 0) (throw $e-f32)) 18 | 19 | (func (export "throw-param-i64") (param i64) (local.get 0) (throw $e-i64)) 20 | 21 | (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) 22 | 23 | (func (export "throw-polymorphic") (throw $e0) (throw $e-i32)) 24 | 25 | (func (export "throw-polymorphic-block") (block (result i32) (throw $e0)) (throw $e-i32)) 26 | 27 | (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) 28 | (func (export "test-throw-1-2") 29 | (block $h (result i32 i32) 30 | (try_table (catch $e-i32-i32 $h) (call $throw-1-2)) 31 | (return) 32 | ) 33 | (if (i32.ne (i32.const 2)) (then (unreachable))) 34 | (if (i32.ne (i32.const 1)) (then (unreachable))) 35 | ) 36 | ) 37 | 38 | (assert_return (invoke "throw-if" (i32.const 0)) (i32.const 0)) 39 | (assert_exception (invoke "throw-if" (i32.const 10))) 40 | (assert_exception (invoke "throw-if" (i32.const -1))) 41 | 42 | (assert_exception (invoke "throw-param-f32" (f32.const 5.0))) 43 | (assert_exception (invoke "throw-param-i64" (i64.const 5))) 44 | (assert_exception (invoke "throw-param-f64" (f64.const 5.0))) 45 | 46 | (assert_exception (invoke "throw-polymorphic")) 47 | (assert_exception (invoke "throw-polymorphic-block")) 48 | 49 | (assert_return (invoke "test-throw-1-2")) 50 | 51 | (assert_invalid (module (func (throw 0))) "unknown tag 0") 52 | (assert_invalid (module (tag (param i32)) (func (throw 0))) 53 | "type mismatch: instruction requires [i32] but stack has []") 54 | (assert_invalid (module (tag (param i32)) (func (i64.const 5) (throw 0))) 55 | "type mismatch: instruction requires [i32] but stack has [i64]") 56 | -------------------------------------------------------------------------------- /test/core/type-canon.wast: -------------------------------------------------------------------------------- 1 | (module 2 | (rec 3 | (type $t1 (func (param i32 (ref $t3)))) 4 | (type $t2 (func (param i32 (ref $t1)))) 5 | (type $t3 (func (param i32 (ref $t2)))) 6 | ) 7 | ) 8 | 9 | (module 10 | (rec 11 | (type $t0 (func (param i32 (ref $t2) (ref $t3)))) 12 | (type $t1 (func (param i32 (ref $t0) i32 (ref $t4)))) 13 | (type $t2 (func (param i32 (ref $t2) (ref $t1)))) 14 | (type $t3 (func (param i32 (ref $t2) i32 (ref $t4)))) 15 | (type $t4 (func (param (ref $t0) (ref $t2)))) 16 | ) 17 | ) 18 | -------------------------------------------------------------------------------- /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/custom/name/name_annot.wast: -------------------------------------------------------------------------------- 1 | ;; Module names 2 | 3 | (module (@name "Modül")) 4 | 5 | (module $moduel (@name "Modül")) 6 | 7 | (assert_malformed_custom 8 | (module quote "(module (@name \"M1\") (@name \"M2\"))") 9 | "@name annotation: multiple module" 10 | ) 11 | 12 | (assert_malformed_custom 13 | (module quote "(module (func) (@name \"M\"))") 14 | "misplaced @name annotation" 15 | ) 16 | 17 | (assert_malformed_custom 18 | (module quote "(module (start $f (@name \"M\")) (func $f))") 19 | "misplaced @name annotation" 20 | ) 21 | 22 | 23 | ;; Function names 24 | 25 | (module 26 | (type $t (func)) 27 | (func (@name "λ") (type $t)) 28 | (func $lambda (@name "λ") (type $t)) 29 | ) 30 | 31 | 32 | ;; Tag names 33 | 34 | (module 35 | (type $t (func)) 36 | (tag (@name "θ") (type $t)) 37 | (tag $theta (@name "θ") (type $t)) 38 | ) 39 | -------------------------------------------------------------------------------- /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/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/exception/constructor.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | // META: script=/wasm/jsapi/assertions.js 3 | 4 | test(() => { 5 | assert_function_name( 6 | WebAssembly.Exception, 7 | "Exception", 8 | "WebAssembly.Exception" 9 | ); 10 | }, "name"); 11 | 12 | test(() => { 13 | assert_function_length(WebAssembly.Exception, 1, "WebAssembly.Exception"); 14 | }, "length"); 15 | 16 | test(() => { 17 | assert_throws_js(TypeError, () => new WebAssembly.Exception()); 18 | }, "No arguments"); 19 | 20 | test(() => { 21 | const tag = new WebAssembly.Tag({ parameters: [] }); 22 | assert_throws_js(TypeError, () => WebAssembly.Exception(tag)); 23 | }, "Calling"); 24 | 25 | test(() => { 26 | const invalidArguments = [ 27 | undefined, 28 | null, 29 | false, 30 | true, 31 | "", 32 | "test", 33 | Symbol(), 34 | 1, 35 | NaN, 36 | {}, 37 | ]; 38 | for (const invalidArgument of invalidArguments) { 39 | assert_throws_js( 40 | TypeError, 41 | () => new WebAssembly.Exception(invalidArgument), 42 | `new Exception(${format_value(invalidArgument)})` 43 | ); 44 | } 45 | }, "Invalid descriptor argument"); 46 | 47 | test(() => { 48 | const typesAndArgs = [ 49 | ["i32", 123n], 50 | ["i32", Symbol()], 51 | ["f32", 123n], 52 | ["f64", 123n], 53 | ["i64", undefined], 54 | ]; 55 | for (const typeAndArg of typesAndArgs) { 56 | const tag = new WebAssembly.Tag({ parameters: [typeAndArg[0]] }); 57 | assert_throws_js( 58 | TypeError, 59 | () => new WebAssembly.Exception(tag, typeAndArg[1]) 60 | ); 61 | } 62 | }, "Invalid exception argument"); 63 | -------------------------------------------------------------------------------- /test/js-api/exception/getArg.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | // META: script=/wasm/jsapi/memory/assertions.js 3 | 4 | test(() => { 5 | const tag = new WebAssembly.Tag({ parameters: [] }); 6 | const exn = new WebAssembly.Exception(tag, []); 7 | assert_throws_js(TypeError, () => exn.getArg()); 8 | assert_throws_js(TypeError, () => exn.getArg(tag)); 9 | }, "Missing arguments"); 10 | 11 | test(() => { 12 | const invalidValues = [undefined, null, true, "", Symbol(), 1, {}]; 13 | const tag = new WebAssembly.Tag({ parameters: [] }); 14 | const exn = new WebAssembly.Exception(tag, []); 15 | for (argument of invalidValues) { 16 | assert_throws_js(TypeError, () => exn.getArg(argument, 0)); 17 | } 18 | }, "Invalid exception argument"); 19 | 20 | test(() => { 21 | const tag = new WebAssembly.Tag({ parameters: [] }); 22 | const exn = new WebAssembly.Exception(tag, []); 23 | assert_throws_js(RangeError, () => exn.getArg(tag, 1)); 24 | }, "Index out of bounds"); 25 | 26 | test(() => { 27 | const outOfRangeValues = [ 28 | undefined, 29 | NaN, 30 | Infinity, 31 | -Infinity, 32 | -1, 33 | 0x100000000, 34 | 0x1000000000, 35 | "0x100000000", 36 | { 37 | valueOf() { 38 | return 0x100000000; 39 | }, 40 | }, 41 | ]; 42 | 43 | const tag = new WebAssembly.Tag({ parameters: [] }); 44 | const exn = new WebAssembly.Exception(tag, []); 45 | for (const value of outOfRangeValues) { 46 | assert_throws_js(TypeError, () => exn.getArg(tag, value)); 47 | } 48 | }, "Getting out-of-range argument"); 49 | 50 | test(() => { 51 | const tag = new WebAssembly.Tag({ parameters: ["i32"] }); 52 | const exn = new WebAssembly.Exception(tag, [42]); 53 | assert_equals(exn.getArg(tag, 0), 42); 54 | }, "getArg"); 55 | -------------------------------------------------------------------------------- /test/js-api/exception/is.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | // META: script=/wasm/jsapi/memory/assertions.js 3 | 4 | test(() => { 5 | const tag = new WebAssembly.Tag({ parameters: [] }); 6 | const exn = new WebAssembly.Exception(tag, []); 7 | assert_throws_js(TypeError, () => exn.is()); 8 | }, "Missing arguments"); 9 | 10 | test(() => { 11 | const invalidValues = [undefined, null, true, "", Symbol(), 1, {}]; 12 | const tag = new WebAssembly.Tag({ parameters: [] }); 13 | const exn = new WebAssembly.Exception(tag, []); 14 | for (argument of invalidValues) { 15 | assert_throws_js(TypeError, () => exn.is(argument)); 16 | } 17 | }, "Invalid exception argument"); 18 | 19 | test(() => { 20 | const tag1 = new WebAssembly.Tag({ parameters: ["i32"] }); 21 | const tag2 = new WebAssembly.Tag({ parameters: ["i32"] }); 22 | const exn = new WebAssembly.Exception(tag1, [42]); 23 | assert_true(exn.is(tag1)); 24 | assert_false(exn.is(tag2)); 25 | }, "is"); 26 | -------------------------------------------------------------------------------- /test/js-api/exception/toString.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | 3 | test(() => { 4 | const argument = { parameters: [] }; 5 | const tag = new WebAssembly.Tag(argument); 6 | const exn = new WebAssembly.Exception(tag, []); 7 | assert_class_string(exn, "WebAssembly.Exception"); 8 | }, "Object.prototype.toString on an Exception"); 9 | 10 | test(() => { 11 | assert_own_property(WebAssembly.Exception.prototype, Symbol.toStringTag); 12 | 13 | const propDesc = Object.getOwnPropertyDescriptor( 14 | WebAssembly.Exception.prototype, 15 | Symbol.toStringTag 16 | ); 17 | assert_equals(propDesc.value, "WebAssembly.Exception", "value"); 18 | assert_equals(propDesc.configurable, true, "configurable"); 19 | assert_equals(propDesc.enumerable, false, "enumerable"); 20 | assert_equals(propDesc.writable, false, "writable"); 21 | }, "@@toStringTag exists on the prototype with the appropriate descriptor"); 22 | -------------------------------------------------------------------------------- /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/gc/default-value.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | let exports = {}; 5 | setup(() => { 6 | const builder = new WasmModuleBuilder(); 7 | 8 | builder.addTable(wasmRefType(kWasmAnyRef), 10, 20, [...wasmI32Const(42), ...GCInstr(kExprRefI31)]) 9 | .exportAs("tableAnyNonNullable"); 10 | builder.addTable(wasmRefNullType(kWasmAnyRef), 10, 20) 11 | .exportAs("tableAnyNullable"); 12 | 13 | const buffer = builder.toBuffer(); 14 | const module = new WebAssembly.Module(buffer); 15 | const instance = new WebAssembly.Instance(module, {}); 16 | exports = instance.exports; 17 | }); 18 | 19 | test(() => { 20 | exports.tableAnyNullable.grow(5); 21 | for (let i = 0; i < 5; i++) 22 | assert_equals(exports.tableAnyNullable.get(10 + i), null); 23 | }, "grow (nullable anyref)"); 24 | 25 | test(() => { 26 | assert_throws_js(TypeError, () => { exports.tableAnyNonNullable.grow(5); }); 27 | exports.tableAnyNonNullable.grow(5, "foo"); 28 | for (let i = 0; i < 5; i++) 29 | assert_equals(exports.tableAnyNonNullable.get(10 + i), "foo"); 30 | }, "grow (non-nullable anyref)"); 31 | 32 | test(() => { 33 | for (let i = 0; i < exports.tableAnyNullable.length; i++) { 34 | exports.tableAnyNullable.set(i); 35 | assert_equals(exports.tableAnyNullable.get(i), null); 36 | } 37 | }, "set (nullable anyref)"); 38 | 39 | test(() => { 40 | for (let i = 0; i < exports.tableAnyNonNullable.length; i++) { 41 | assert_throws_js(TypeError, () => { exports.tableAnyNonNullable.set(i); }); 42 | } 43 | }, "set (non-nullable anyref)"); 44 | -------------------------------------------------------------------------------- /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/js-string/constants.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | // Instantiate a module with an imported global and return the global. 5 | function instantiateImportedGlobal(module, name, type, mutable, importedStringConstants) { 6 | let builder = new WasmModuleBuilder(); 7 | builder.addImportedGlobal(module, name, type, mutable); 8 | builder.addExportOfKind("global", kExternalGlobal, 0); 9 | let bytes = builder.toBuffer(); 10 | let mod = new WebAssembly.Module(bytes, { importedStringConstants }); 11 | let instance = new WebAssembly.Instance(mod, {}); 12 | return instance.exports["global"]; 13 | } 14 | 15 | const badGlobalTypes = [ 16 | [kWasmAnyRef, false], 17 | [kWasmAnyRef, true], 18 | [wasmRefType(kWasmAnyRef), false], 19 | [wasmRefType(kWasmAnyRef), true], 20 | [kWasmFuncRef, false], 21 | [kWasmFuncRef, true], 22 | [wasmRefType(kWasmFuncRef), false], 23 | [wasmRefType(kWasmFuncRef), true], 24 | [kWasmExternRef, true], 25 | [wasmRefType(kWasmExternRef), true], 26 | ]; 27 | for ([type, mutable] of badGlobalTypes) { 28 | test(() => { 29 | assert_throws_js(WebAssembly.CompileError, 30 | () => instantiateImportedGlobal("'", "constant", type, mutable, "'"), 31 | "type mismatch"); 32 | }); 33 | } 34 | 35 | const goodGlobalTypes = [ 36 | [kWasmExternRef, false], 37 | [wasmRefType(kWasmExternRef), false], 38 | ]; 39 | const constants = [ 40 | '', 41 | '\0', 42 | '0', 43 | '0'.repeat(100000), 44 | '\uD83D\uDE00', 45 | ]; 46 | const namespaces = [ 47 | "", 48 | "'", 49 | "strings" 50 | ]; 51 | 52 | for (let namespace of namespaces) { 53 | for (let constant of constants) { 54 | for ([type, mutable] of goodGlobalTypes) { 55 | test(() => { 56 | let result = instantiateImportedGlobal(namespace, constant, type, mutable, namespace); 57 | assert_equals(result.value, constant); 58 | }); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/js-api/js-string/imports.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | // META: script=/wasm/jsapi/wasm-module-builder.js 3 | 4 | test(() => { 5 | let builder = new WasmModuleBuilder(); 6 | 7 | // Import a string constant 8 | builder.addImportedGlobal("constants", "constant", kWasmExternRef, false); 9 | 10 | // Import a builtin function 11 | builder.addImport( 12 | "wasm:js-string", 13 | "test", 14 | {params: [kWasmExternRef], results: [kWasmI32]}); 15 | 16 | let buffer = builder.toBuffer(); 17 | let module = new WebAssembly.Module(buffer, { 18 | builtins: ["js-string"], 19 | importedStringConstants: "constants" 20 | }); 21 | let imports = WebAssembly.Module.imports(module); 22 | 23 | // All imports that refer to a builtin module are suppressed from import 24 | // reflection. 25 | assert_equals(imports.length, 0); 26 | }); 27 | -------------------------------------------------------------------------------- /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/js-api/tag/constructor.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | // META: script=/wasm/jsapi/assertions.js 3 | 4 | test(() => { 5 | assert_function_name(WebAssembly.Tag, "Tag", "WebAssembly.Tag"); 6 | }, "name"); 7 | 8 | test(() => { 9 | assert_function_length(WebAssembly.Tag, 1, "WebAssembly.Tag"); 10 | }, "length"); 11 | 12 | test(() => { 13 | assert_throws_js(TypeError, () => new WebAssembly.Tag()); 14 | }, "No arguments"); 15 | 16 | test(() => { 17 | const argument = { parameters: [] }; 18 | assert_throws_js(TypeError, () => WebAssembly.Tag(argument)); 19 | }, "Calling"); 20 | 21 | test(() => { 22 | const invalidArguments = [ 23 | undefined, 24 | null, 25 | false, 26 | true, 27 | "", 28 | "test", 29 | Symbol(), 30 | 1, 31 | NaN, 32 | {}, 33 | ]; 34 | for (const invalidArgument of invalidArguments) { 35 | assert_throws_js( 36 | TypeError, 37 | () => new WebAssembly.Tag(invalidArgument), 38 | `new Tag(${format_value(invalidArgument)})` 39 | ); 40 | } 41 | }, "Invalid descriptor argument"); 42 | 43 | test(() => { 44 | const invalidTypes = ["i16", "i128", "f16", "f128", "u32", "u64", "i32\0"]; 45 | for (const value of invalidTypes) { 46 | const argument = { parameters: [value] }; 47 | assert_throws_js(TypeError, () => new WebAssembly.Tag(argument)); 48 | } 49 | }, "Invalid type parameter"); 50 | -------------------------------------------------------------------------------- /test/js-api/tag/toString.tentative.any.js: -------------------------------------------------------------------------------- 1 | // META: global=window,dedicatedworker,jsshell,shadowrealm 2 | 3 | test(() => { 4 | const argument = { parameters: [] }; 5 | const tag = new WebAssembly.Tag(argument); 6 | assert_class_string(tag, "WebAssembly.Tag"); 7 | }, "Object.prototype.toString on a Tag"); 8 | 9 | test(() => { 10 | assert_own_property(WebAssembly.Tag.prototype, Symbol.toStringTag); 11 | 12 | const propDesc = Object.getOwnPropertyDescriptor( 13 | WebAssembly.Tag.prototype, 14 | Symbol.toStringTag 15 | ); 16 | assert_equals(propDesc.value, "WebAssembly.Tag", "value"); 17 | assert_equals(propDesc.configurable, true, "configurable"); 18 | assert_equals(propDesc.enumerable, false, "enumerable"); 19 | assert_equals(propDesc.writable, false, "writable"); 20 | }, "@@toStringTag exists on the prototype with the appropriate descriptor"); 21 | -------------------------------------------------------------------------------- /test/legacy/exceptions/core/throw.wast: -------------------------------------------------------------------------------- 1 | ;; Test throw instruction. 2 | 3 | (module 4 | (tag $e0) 5 | (tag $e-i32 (param i32)) 6 | (tag $e-f32 (param f32)) 7 | (tag $e-i64 (param i64)) 8 | (tag $e-f64 (param f64)) 9 | (tag $e-i32-i32 (param i32 i32)) 10 | 11 | (func $throw-if (export "throw-if") (param i32) (result i32) 12 | (local.get 0) 13 | (i32.const 0) (if (i32.ne) (then (throw $e0))) 14 | (i32.const 0) 15 | ) 16 | 17 | (func (export "throw-param-f32") (param f32) (local.get 0) (throw $e-f32)) 18 | 19 | (func (export "throw-param-i64") (param i64) (local.get 0) (throw $e-i64)) 20 | 21 | (func (export "throw-param-f64") (param f64) (local.get 0) (throw $e-f64)) 22 | 23 | (func $throw-1-2 (i32.const 1) (i32.const 2) (throw $e-i32-i32)) 24 | (func (export "test-throw-1-2") 25 | (try 26 | (do (call $throw-1-2)) 27 | (catch $e-i32-i32 28 | (i32.const 2) 29 | (if (i32.ne) (then (unreachable))) 30 | (i32.const 1) 31 | (if (i32.ne) (then (unreachable))) 32 | ) 33 | ) 34 | ) 35 | ) 36 | 37 | (assert_return (invoke "throw-if" (i32.const 0)) (i32.const 0)) 38 | (assert_exception (invoke "throw-if" (i32.const 10))) 39 | (assert_exception (invoke "throw-if" (i32.const -1))) 40 | 41 | (assert_exception (invoke "throw-param-f32" (f32.const 5.0))) 42 | (assert_exception (invoke "throw-param-i64" (i64.const 5))) 43 | (assert_exception (invoke "throw-param-f64" (f64.const 5.0))) 44 | 45 | (assert_return (invoke "test-throw-1-2")) 46 | 47 | (assert_invalid (module (func (throw 0))) "unknown tag 0") 48 | (assert_invalid (module (tag (param i32)) (func (throw 0))) 49 | "type mismatch: instruction requires [i32] but stack has []") 50 | (assert_invalid (module (tag (param i32)) (func (i64.const 5) (throw 0))) 51 | "type mismatch: instruction requires [i32] but stack has [i64]") 52 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------