123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- ;;; WebAssembly binary parser
- ;;; Copyright (C) 2023, 2024 Igalia, S.L.
- ;;;
- ;;; Licensed under the Apache License, Version 2.0 (the "License");
- ;;; you may not use this file except in compliance with the License.
- ;;; You may obtain a copy of the License at
- ;;;
- ;;; http://www.apache.org/licenses/LICENSE-2.0
- ;;;
- ;;; Unless required by applicable law or agreed to in writing, software
- ;;; distributed under the License is distributed on an "AS IS" BASIS,
- ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ;;; See the License for the specific language governing permissions and
- ;;; limitations under the License.
- ;;; Commentary:
- ;;;
- ;;; Parser for WebAssembly binary format
- ;;;
- ;;; Code:
- (use-modules (wasm assemble)
- (wasm lower)
- (wasm wat)
- (wasm parse)
- (ice-9 binary-ports)
- (srfi srfi-64)
- (test utils))
- (define (scope-file file-name)
- (in-vicinity (getenv "HOOT_TEST_DATA_DIR") file-name))
- (test-begin "test-wasm-assembler")
- (define-syntax-rule (test-wat->wasm expected wat)
- (begin
- (test-equal expected (assemble-wasm (lower-wasm (wat->wasm 'wat))))
- (test-equal expected
- (assemble-wasm (call-with-input-bytevector expected parse-wasm)))))
- (define-syntax-rule (test-wat->wasm/emit-names expected wat)
- (begin
- (test-equal expected (assemble-wasm (lower-wasm (wat->wasm 'wat) #:emit-names? #t)))
- (test-equal expected
- (assemble-wasm (call-with-input-bytevector expected parse-wasm)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 127 3 2 1 0 10 6 1 4 0 65 42 11)
- (module
- (func (param) (result i32)
- (i32.const 42))))
- (define basic-types.wasm
- (call-with-input-file (scope-file "basic-types.wasm") get-bytevector-all))
- (define basic-types/1
- (call-with-input-bytevector basic-types.wasm parse-wasm))
- (define basic-types.wasm/2
- (assemble-wasm basic-types/1))
- (define basic-types/2
- (call-with-input-bytevector basic-types.wasm/2 parse-wasm))
- (define basic-types.wasm/3
- (assemble-wasm basic-types/2))
- ;; For wasm files like basic-types.wasm that are produced by external
- ;; tools, we don't aim for byte-for-byte parsing and re-serialization,
- ;; notably because binaryen emits deprecated GC opcodes which we rewrite
- ;; to the updated ones. But if we parse a file that we generate and
- ;; then re-serialize it, they should be the same.
- (test-equal "basic types reassembly"
- basic-types.wasm/2 basic-types.wasm/3)
- ;; Test type resolution for functions with similar signatures
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 6 1 96 1 127 1 127 3 3 2 0 0 10 11 2 4 0 32
- 0 11 4 0 32 0 11)
- (module
- (func $a (param $x i32) (result i32)
- (local.get $x))
- (func $b (param $y i32) (result i32)
- (local.get $y))))
- ;; Test vector instructions
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 123 3 2 1 0 10 8 1 6 0 65 23 253
- 15 11)
- (module (func (result v128) (i8x16.splat (i32.const 23)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 123 3 2 1 0 10 8 1 6 0 65 23 253
- 16 11)
- (module (func (result v128) (i16x8.splat (i32.const 23)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 123 3 2 1 0 10 8 1 6 0 65 23 253
- 17 11)
- (module (func (result v128) (i32x4.splat (i32.const 23)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 123 3 2 1 0 10 8 1 6 0 66 23 253
- 18 11)
- (module (func (result v128) (i64x2.splat (i64.const 23)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 123 3 2 1 0 10 11 1 9 0 67 208
- 15 73 64 253 19 11)
- (module (func (result v128) (f32x4.splat (f32.const 3.14159)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 123 3 2 1 0 10 15 1 13 0 68 110
- 134 27 240 249 33 9 64 253 20 11)
- (module (func (result v128) (f64x2.splat (f64.const 3.14159)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 4 1 94 127 0)
- (module (type $foo (array i32))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 4 1 94 127 1)
- (module (type $foo (array (mut i32)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 7 1 95 2 127 0 127 0)
- (module (type $foo (struct (field $foo i32) (field $bar i32)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 7 1 95 2 127 1 127 0)
- (module (type $foo (struct (field $a (mut i32)) (field $b i32)))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 7 1 95 2 127 0 127 1)
- (module (type $foo (struct (field $a i32) (field $b (mut i32))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 7 1 95 2 127 1 127 1)
- (module (type $foo (struct (field $a (mut i32)) (field $b (mut i32))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 7 1 78 1 95 1 127 1)
- (module
- (rec
- (type $heap-object
- (struct (field $hash (mut i32)))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 17 1 78 2 95 1 127 1 80 1 0 95 2 127 1
- 100 111 0)
- (module
- (rec
- (type $heap-object
- (struct (field $hash (mut i32))))
- (type $extern-ref
- (sub $heap-object
- (struct
- (field $hash (mut i32))
- (field $val (ref extern))))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 33 1 78 3 95 1 127 1 80 1 0 95 3 127 1
- 100 109 1 100 109 1 80 1 1 95 3 127 1 100 109 1 100 109 1)
- (module
- (rec
- (type $heap-object
- (struct (field $hash (mut i32))))
- (type $pair
- (sub $heap-object
- (struct
- (field $hash (mut i32))
- (field $car (mut (ref eq)))
- (field $cdr (mut (ref eq))))))
- (type $mutable-pair
- (sub $pair
- (struct
- (field $hash (mut i32))
- (field $car (mut (ref eq)))
- (field $cdr (mut (ref eq)))))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 4 1 96 0 0 3 2 1 0 10 9 1 7 0 65 0 14 0 0 11)
- (module (func (i32.const 0) (br_table 0))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 1 127 0 3 2 1 0 10 20 1 18 0 2 64 2
- 64 2 64 32 0 14 2 2 1 0 11 11 11 11)
- (module
- (func (param $i i32)
- (block $l1
- (block $l2
- (block $l3
- (br_table $l1 $l2 $l3 (local.get $i))))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 5 1 96 0 1 127 3 2 1 0 10 14 1 12 0 65 0 4
- 127 65 1 5 65 2 11 11)
- (module
- (func (result i32)
- (if i32
- (i32.const 0)
- (then (i32.const 1))
- (else (i32.const 2))))))
- ;; Regression test for br_on_cast parsing.
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 7 1 96 1 100 109 1 127 3 2 1 0 10 23 1 21 0 2
- 100 108 32 0 251 24 0 0 109 108 26 65 0 15 11 26 65 1 11)
- (module
- (func $immediate? (param $x (ref eq)) (result i32)
- (block $i31 (ref i31)
- (local.get $x)
- (br_on_cast $i31 (ref eq) (ref i31))
- (drop)
- (i32.const 0)
- (return))
- (drop)
- (i32.const 1))))
- ;; Test exceptions
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 4 1 96 0 0 13 3 1 0 0)
- (module (tag $foo)))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 4 1 96 0 0 2 13 1 4 116 97 103 115 3 102 111 111 4 0 0)
- (module (tag $foo (import "tags" "foo"))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 4 1 96 0 0 13 3 1 0 0 7 7 1 3 102 111 111 4 0)
- (module (tag $foo (export "foo"))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 8 2 96 0 0 96 0 1 127 3 2 1 1 13 5 2 0 0 0 0 10
- 17 1 15 0 6 127 8 0 7 1 65 42 25 65 205 0 11 11)
- (module
- (tag $foo)
- (tag $bar)
- (func (result i32)
- (try (result i32)
- (do (throw $foo))
- (catch $bar (i32.const 42))
- (catch_all (i32.const 77))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 9 2 96 1 127 0 96 0 1 127 3 2 1 1 13 3 1 0 0 10
- 26 1 24 0 6 127 6 64 65 197 0 8 0 24 0 0 7 0 65 42 106 25 65 205 0 11 11)
- (module
- (tag $foo (param i32))
- (func (result i32)
- (try $bloop (result i32)
- (do (try
- (do (i32.const 69)
- (throw $foo))
- (delegate $bloop))
- (unreachable))
- (catch $foo
- (i32.const 42)
- (i32.add))
- (catch_all (i32.const 77))))))
- (test-wat->wasm
- #vu8(0 97 115 109 1 0 0 0 1 8 2 96 0 0 96 0 1 127 3 2 1 1 13 3 1 0 0 10 24 1
- 22 0 6 127 6 127 8 0 7 0 9 0 25 0 11 7 0 65 42 25 0 11 11)
- (module
- (tag $foo)
- (func (result i32)
- (try $l1 (result i32)
- (do (try $l2 (result i32)
- (do (throw $foo))
- (catch $foo
- (rethrow $l2))
- (catch_all (unreachable))))
- (catch $foo
- (i32.const 42))
- (catch_all (unreachable))))))
- ;; Test name section
- (test-wat->wasm/emit-names
- #vu8(0 97 115 109 1 0 0 0 1 6 1 96 1 127 1 127 3 2 1 0 10 7 1 5 0 32 0 106 11
- 0 29 4 110 97 109 101 0 5 4 116 101 115 116 1 7 1 0 4 97 100 100 49 2
- 6 1 0 1 0 1 120)
- (module $test
- (func $add1 (param $x i32) (result i32)
- (i32.add (local.get $x)))))
- (test-end* "test-wasm-assembler")
|