From fc181367141ed8c6c592390cb741bd784f682ac3 Mon Sep 17 00:00:00 2001 From: Ryan Hyun Choi Date: Fri, 3 Sep 2021 09:21:24 +0900 Subject: [PATCH] LWNode_Release_210903_60ce3db Change-Id: I693792d1029267e456f09feff8cc76341ba18b5e Signed-off-by: Ryan Choi --- .../third_party/wasm/wabt/.clang-format | 1 + .../escargot/third_party/wasm/wabt/.flake8 | 5 + .../escargot/third_party/wasm/wabt/.gitignore | 9 + .../third_party/wasm/wabt/CMakeLists.txt | 730 ++++ .../third_party/wasm/wabt/Contributing.md | 8 + .../escargot/third_party/wasm/wabt/LICENSE | 202 + .../escargot/third_party/wasm/wabt/Makefile | 182 + .../escargot/third_party/wasm/wabt/README.md | 358 ++ .../third_party/wasm/wabt/cmake/README.md | 3 + .../third_party/wasm/wabt/src/apply-names.cc | 510 +++ .../third_party/wasm/wabt/src/apply-names.h | 45 + .../wasm/wabt/src/binary-reader-ir.cc | 1448 ++++++++ .../wasm/wabt/src/binary-reader-ir.h | 37 + .../wasm/wabt/src/binary-reader-logging.cc | 949 +++++ .../wasm/wabt/src/binary-reader-logging.h | 385 ++ .../wasm/wabt/src/binary-reader-nop.h | 545 +++ .../wasm/wabt/src/binary-reader-objdump.cc | 2029 ++++++++++ .../wasm/wabt/src/binary-reader-objdump.h | 87 + .../wasm/wabt/src/binary-reader-opcnt.cc | 290 ++ .../wasm/wabt/src/binary-reader-opcnt.h | 93 + .../wasm/wabt/src/binary-reader.cc | 2671 ++++++++++++++ .../third_party/wasm/wabt/src/binary-reader.h | 466 +++ .../wasm/wabt/src/binary-writer-spec.cc | 630 ++++ .../wasm/wabt/src/binary-writer-spec.h | 60 + .../wasm/wabt/src/binary-writer.cc | 1645 +++++++++ .../third_party/wasm/wabt/src/binary-writer.h | 62 + .../third_party/wasm/wabt/src/binary.cc | 62 + .../third_party/wasm/wabt/src/binary.h | 93 + .../third_party/wasm/wabt/src/binding-hash.cc | 91 + .../third_party/wasm/wabt/src/binding-hash.h | 72 + .../third_party/wasm/wabt/src/c-writer.cc | 2245 ++++++++++++ .../third_party/wasm/wabt/src/c-writer.h | 37 + .../escargot/third_party/wasm/wabt/src/cast.h | 109 + .../wasm/wabt/src/circular-array.h | 123 + .../third_party/wasm/wabt/src/color.cc | 84 + .../third_party/wasm/wabt/src/color.h | 72 + .../third_party/wasm/wabt/src/common.cc | 147 + .../third_party/wasm/wabt/src/common.h | 475 +++ .../third_party/wasm/wabt/src/config.cc | 162 + .../third_party/wasm/wabt/src/config.h.in | 311 ++ .../wasm/wabt/src/decompiler-ast.h | 378 ++ .../third_party/wasm/wabt/src/decompiler-ls.h | 265 ++ .../wasm/wabt/src/decompiler-naming.h | 211 ++ .../third_party/wasm/wabt/src/decompiler.cc | 829 +++++ .../third_party/wasm/wabt/src/decompiler.h | 36 + .../wasm/wabt/src/emscripten-exported.json | 58 + .../wasm/wabt/src/emscripten-helpers.cc | 406 ++ .../wasm/wabt/src/error-formatter.cc | 127 + .../wasm/wabt/src/error-formatter.h | 54 + .../third_party/wasm/wabt/src/error.h | 58 + .../third_party/wasm/wabt/src/expr-visitor.cc | 466 +++ .../third_party/wasm/wabt/src/expr-visitor.h | 215 ++ .../third_party/wasm/wabt/src/feature.cc | 50 + .../third_party/wasm/wabt/src/feature.def | 37 + .../third_party/wasm/wabt/src/feature.h | 58 + .../third_party/wasm/wabt/src/filenames.cc | 56 + .../third_party/wasm/wabt/src/filenames.h | 51 + .../wasm/wabt/src/generate-names.cc | 431 +++ .../wasm/wabt/src/generate-names.h | 46 + .../third_party/wasm/wabt/src/hash-util.cc | 38 + .../third_party/wasm/wabt/src/hash-util.h | 51 + .../wabt/src/interp/binary-reader-interp.cc | 1367 +++++++ .../wabt/src/interp/binary-reader-interp.h | 39 + .../wasm/wabt/src/interp/interp-inl.h | 927 +++++ .../wasm/wabt/src/interp/interp-math.h | 400 ++ .../wasm/wabt/src/interp/interp-util.cc | 114 + .../wasm/wabt/src/interp/interp-util.h | 50 + .../wasm/wabt/src/interp/interp-wasi.cc | 760 ++++ .../wasm/wabt/src/interp/interp-wasi.h | 46 + .../wasm/wabt/src/interp/interp-wasm-c-api.cc | 1329 +++++++ .../wasm/wabt/src/interp/interp.cc | 2330 ++++++++++++ .../third_party/wasm/wabt/src/interp/interp.h | 1205 ++++++ .../wasm/wabt/src/interp/istream.cc | 885 +++++ .../wasm/wabt/src/interp/istream.h | 155 + .../wasm/wabt/src/interp/wasi_api.def | 28 + .../wasm/wabt/src/intrusive-list.h | 633 ++++ .../third_party/wasm/wabt/src/ir-util.cc | 261 ++ .../third_party/wasm/wabt/src/ir-util.h | 76 + .../escargot/third_party/wasm/wabt/src/ir.cc | 691 ++++ .../escargot/third_party/wasm/wabt/src/ir.h | 1307 +++++++ .../third_party/wasm/wabt/src/leb128.cc | 354 ++ .../third_party/wasm/wabt/src/leb128.h | 69 + .../wasm/wabt/src/lexer-keywords.txt | 585 +++ .../wasm/wabt/src/lexer-source-line-finder.cc | 152 + .../wasm/wabt/src/lexer-source-line-finder.h | 61 + .../third_party/wasm/wabt/src/lexer-source.cc | 67 + .../third_party/wasm/wabt/src/lexer-source.h | 53 + .../third_party/wasm/wabt/src/literal.cc | 830 +++++ .../third_party/wasm/wabt/src/literal.h | 84 + .../third_party/wasm/wabt/src/make-unique.h | 42 + .../wasm/wabt/src/opcode-code-table.c | 41 + .../wasm/wabt/src/opcode-code-table.h | 38 + .../third_party/wasm/wabt/src/opcode.cc | 389 ++ .../third_party/wasm/wabt/src/opcode.def | 523 +++ .../third_party/wasm/wabt/src/opcode.h | 182 + .../wasm/wabt/src/option-parser.cc | 356 ++ .../third_party/wasm/wabt/src/option-parser.h | 99 + .../wasm/wabt/src/prebuilt/lexer-keywords.cc | 1745 +++++++++ .../wasm/wabt/src/prebuilt/wasm2c.include.c | 188 + .../wasm/wabt/src/prebuilt/wasm2c.include.h | 39 + .../third_party/wasm/wabt/src/range.h | 37 + .../wasm/wabt/src/resolve-names.cc | 589 +++ .../third_party/wasm/wabt/src/resolve-names.h | 33 + .../third_party/wasm/wabt/src/result.h | 63 + .../wasm/wabt/src/shared-validator.cc | 1208 ++++++ .../wasm/wabt/src/shared-validator.h | 311 ++ .../third_party/wasm/wabt/src/stream.cc | 316 ++ .../third_party/wasm/wabt/src/stream.h | 227 ++ .../third_party/wasm/wabt/src/string-view.cc | 196 + .../third_party/wasm/wabt/src/string-view.h | 347 ++ .../wasm/wabt/src/test-binary-reader.cc | 75 + .../wasm/wabt/src/test-circular-array.cc | 284 ++ .../wasm/wabt/src/test-filenames.cc | 61 + .../wasm/wabt/src/test-hexfloat.cc | 264 ++ .../third_party/wasm/wabt/src/test-interp.cc | 693 ++++ .../wasm/wabt/src/test-intrusive-list.cc | 584 +++ .../third_party/wasm/wabt/src/test-literal.cc | 838 +++++ .../wasm/wabt/src/test-option-parser.cc | 181 + .../wasm/wabt/src/test-string-view.cc | 415 +++ .../third_party/wasm/wabt/src/test-utf8.cc | 167 + .../wasm/wabt/src/test-wast-parser.cc | 87 + .../third_party/wasm/wabt/src/token.cc | 99 + .../third_party/wasm/wabt/src/token.def | 170 + .../third_party/wasm/wabt/src/token.h | 133 + .../wasm/wabt/src/tools/spectest-interp.cc | 1852 ++++++++++ .../wasm/wabt/src/tools/wasm-decompile.cc | 119 + .../wasm/wabt/src/tools/wasm-interp.cc | 337 ++ .../wasm/wabt/src/tools/wasm-objdump.cc | 145 + .../wasm/wabt/src/tools/wasm-opcodecnt.cc | 188 + .../wasm/wabt/src/tools/wasm-strip.cc | 114 + .../wasm/wabt/src/tools/wasm-validate.cc | 99 + .../third_party/wasm/wabt/src/tools/wasm2c.cc | 163 + .../wasm/wabt/src/tools/wasm2wat-fuzz.cc | 30 + .../wasm/wabt/src/tools/wasm2wat.cc | 149 + .../wasm/wabt/src/tools/wast2json.cc | 162 + .../wasm/wabt/src/tools/wat-desugar.cc | 130 + .../wasm/wabt/src/tools/wat2wasm.cc | 170 + .../third_party/wasm/wabt/src/tracing.cc | 71 + .../third_party/wasm/wabt/src/tracing.h | 73 + .../third_party/wasm/wabt/src/type-checker.cc | 915 +++++ .../third_party/wasm/wabt/src/type-checker.h | 194 + .../escargot/third_party/wasm/wabt/src/type.h | 145 + .../third_party/wasm/wabt/src/utf8.cc | 104 + .../escargot/third_party/wasm/wabt/src/utf8.h | 28 + .../third_party/wasm/wabt/src/validator.cc | 1043 ++++++ .../third_party/wasm/wabt/src/validator.h | 36 + .../third_party/wasm/wabt/src/wasm2c.c.tmpl | 184 + .../third_party/wasm/wabt/src/wasm2c.h.tmpl | 35 + .../third_party/wasm/wabt/src/wasm2c_tmpl.py | 77 + .../third_party/wasm/wabt/src/wast-lexer.cc | 557 +++ .../third_party/wasm/wabt/src/wast-lexer.h | 108 + .../third_party/wasm/wabt/src/wast-parser.cc | 3250 +++++++++++++++++ .../third_party/wasm/wabt/src/wast-parser.h | 249 ++ .../third_party/wasm/wabt/src/wat-writer.cc | 1697 +++++++++ .../third_party/wasm/wabt/src/wat-writer.h | 37 + .../third_party/wasm/wabt/ubsan.blacklist | 12 + lwnode/test/node/cctest.gypi | 78 + 157 files changed, 59883 insertions(+) create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.clang-format create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.flake8 create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.gitignore create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/CMakeLists.txt create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Contributing.md create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/LICENSE create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Makefile create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/README.md create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/cmake/README.md create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-nop.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/cast.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/circular-array.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.h.in create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ast.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ls.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-naming.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-exported.json create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-helpers.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.def create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-inl.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-math.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasm-c-api.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/wasi_api.def create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/intrusive-list.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-keywords.txt create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/make-unique.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.c create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.def create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/lexer-keywords.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.c create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/range.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/result.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-binary-reader.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-circular-array.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-filenames.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-hexfloat.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-interp.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-intrusive-list.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-literal.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-option-parser.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-string-view.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-utf8.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-wast-parser.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.def create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/spectest-interp.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-decompile.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-interp.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-objdump.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-opcodecnt.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-strip.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-validate.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2c.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat-fuzz.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wast2json.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat-desugar.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat2wasm.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.c.tmpl create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.h.tmpl create mode 100755 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c_tmpl.py create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.cc create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.h create mode 100644 lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/ubsan.blacklist create mode 100644 lwnode/test/node/cctest.gypi diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.clang-format b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.clang-format new file mode 100644 index 0000000..3f19e61 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.clang-format @@ -0,0 +1 @@ +BasedOnStyle: Chromium diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.flake8 b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.flake8 new file mode 100644 index 0000000..76b6006 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.flake8 @@ -0,0 +1,5 @@ +[flake8] +ignore = + E501, # line too long + W504 # line break after binary operator +exclude = ./third_party ./out diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.gitignore b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.gitignore new file mode 100644 index 0000000..645634f --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.gitignore @@ -0,0 +1,9 @@ +/bin +/build +/out +/fuzz-out +/emscripten +*.pyc +.idea/ +.vscode/ +/cmake-build-debug/ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/CMakeLists.txt b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/CMakeLists.txt new file mode 100644 index 0000000..43ce516 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/CMakeLists.txt @@ -0,0 +1,730 @@ +# +# Copyright 2016 WebAssembly Community Group participants +# +# 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. +# + +cmake_minimum_required(VERSION 3.0.0) +project(WABT VERSION 1.0.21) +include(GNUInstallDirs) + +if (POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif (POLICY CMP0077) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Check if wabt is being used directly or via add_subdirectory, FetchContent, etc +set(WABT_MASTER_PROJECT OFF) +if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(WABT_MASTER_PROJECT ON) +endif() + +# For git users, attempt to generate a more useful version string +if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) + find_package(Git QUIET REQUIRED) + execute_process(COMMAND + "${GIT_EXECUTABLE}" --git-dir=${CMAKE_CURRENT_SOURCE_DIR}/.git describe --tags + RESULT_VARIABLE + GIT_VERSION_RESULT + ERROR_VARIABLE + GIT_VERSION_ERROR + OUTPUT_VARIABLE + GIT_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (${GIT_VERSION_RESULT}) + # Don't issue warning if we aren't the master project; + # just assume that whoever included us knows the version they are getting + if (WABT_MASTER_PROJECT) + message(WARNING "${GIT_VERSION_ERROR} Error running git describe to determine version") + endif() + else () + set(CMAKE_PROJECT_VERSION "${CMAKE_PROJECT_VERSION} (${GIT_VERSION})") + endif () +endif () + +if (NOT "${CMAKE_PROJECT_VERSION}") + set(CMAKE_PROJECT_VERSION ${PROJECT_VERSION}) +endif() + +option(BUILD_TESTS "Build GTest-based tests" ON) +option(USE_SYSTEM_GTEST "Use system GTest, instead of building" OFF) +option(BUILD_TOOLS "Build wabt commandline tools" ON) +option(BUILD_FUZZ_TOOLS "Build tools that can repro fuzz bugs" OFF) +option(BUILD_LIBWASM "Build libwasm" ON) +option(USE_ASAN "Use address sanitizer" OFF) +option(USE_MSAN "Use memory sanitizer" OFF) +option(USE_LSAN "Use leak sanitizer" OFF) +option(USE_UBSAN "Use undefined behavior sanitizer" OFF) +option(CODE_COVERAGE "Build with code coverage enabled" OFF) +option(WITH_EXCEPTIONS "Build with exceptions enabled" OFF) +option(WERROR "Build with warnings as errors" OFF) +# WASI support is still a work in progress. +# Only a handful of syscalls are supported at this point. +option(WITH_WASI "Build WASI support via uvwasi" OFF) + +if (MSVC) + set(COMPILER_IS_CLANG 0) + set(COMPILER_IS_GNU 0) + set(COMPILER_IS_MSVC 1) +elseif (CMAKE_C_COMPILER_ID MATCHES "Clang") + set(COMPILER_IS_CLANG 1) + set(COMPILER_IS_GNU 0) + set(COMPILER_IS_MSVC 0) +elseif (CMAKE_C_COMPILER_ID STREQUAL "GNU") + set(COMPILER_IS_CLANG 0) + set(COMPILER_IS_GNU 1) + set(COMPILER_IS_MSVC 0) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + set(COMPILER_IS_CLANG 1) + set(COMPILER_IS_GNU 0) + set(COMPILER_IS_MSVC 0) +else () + set(COMPILER_IS_CLANG 0) + set(COMPILER_IS_GNU 0) + set(COMPILER_IS_MSVC 0) +endif () + +include(CheckIncludeFile) +include(CheckSymbolExists) + +check_include_file("alloca.h" HAVE_ALLOCA_H) +check_include_file("unistd.h" HAVE_UNISTD_H) +check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) +check_symbol_exists(strcasecmp "strings.h" HAVE_STRCASECMP) + +if (WIN32) + check_symbol_exists(ENABLE_VIRTUAL_TERMINAL_PROCESSING "windows.h" HAVE_WIN32_VT100) +endif () + +include(CheckTypeSize) +check_type_size(ssize_t SSIZE_T) +check_type_size(size_t SIZEOF_SIZE_T) + +configure_file( + ${WABT_SOURCE_DIR}/src/config.h.in + ${WABT_BINARY_DIR}/config.h +) + +include_directories(${WABT_SOURCE_DIR} ${WABT_BINARY_DIR}) + +if (COMPILER_IS_MSVC) + # disable warning C4018: signed/unsigned mismatch + # disable warning C4056, C4756: overflow in floating-point constant arithmetic + # seems to not like float compare w/ HUGE_VALF; bug? + # disable warnings C4267 and C4244: conversion/truncation from larger to smaller type. + # disable warning C4800: implicit conversion from larger int to bool + add_definitions(-W3 -wd4018 -wd4056 -wd4756 -wd4267 -wd4244 -wd4800 -D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) + + if (NOT WITH_EXCEPTIONS) + # disable exception use in C++ library + add_definitions(-D_HAS_EXCEPTIONS=0) + endif () + + # multi-core build. + add_definitions("/MP") + +else () + # disable -Wunused-parameter: this is really common when implementing + # interfaces, etc. + # disable -Wpointer-arith: this is a GCC extension, and doesn't work in MSVC. + add_definitions( + -Wall -Wextra -Wno-unused-parameter -Wpointer-arith -Wuninitialized + ) + + set(CMAKE_CXX_EXTENSIONS OFF) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wold-style-cast") + + if (NOT WITH_EXCEPTIONS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") + endif () + + # Need to define __STDC_*_MACROS because C99 specifies that C++ shouldn't + # define format (e.g. PRIu64) or limit (e.g. UINT32_MAX) macros without the + # definition, and some libcs (e.g. glibc2.17 and earlier) follow that. + add_definitions(-D__STDC_LIMIT_MACROS=1 -D__STDC_FORMAT_MACROS=1) + + if (MINGW OR CYGWIN) + # On MINGW, _POSIX_C_SOURCE is needed to ensure we use mingw printf + # instead of the VC runtime one. + add_definitions(-D_POSIX_C_SOURCE=200809L) + endif() + + if (COMPILER_IS_GNU) + # disable -Wclobbered: it seems to be guessing incorrectly about a local + # variable being clobbered by longjmp. + add_definitions(-Wno-clobbered) + endif () + + if (NOT EMSCRIPTEN) + # try to get the target architecture by compiling a dummy.c file and + # checking the architecture using the file command. + file(WRITE ${WABT_BINARY_DIR}/dummy.c "main(){}") + try_compile( + COMPILE_OK + ${WABT_BINARY_DIR} + ${WABT_BINARY_DIR}/dummy.c + COPY_FILE ${WABT_BINARY_DIR}/dummy + ) + if (COMPILE_OK) + execute_process( + COMMAND file ${WABT_BINARY_DIR}/dummy + RESULT_VARIABLE FILE_RESULT + OUTPUT_VARIABLE FILE_OUTPUT + ERROR_QUIET + ) + + if (FILE_RESULT EQUAL 0) + if (${FILE_OUTPUT} MATCHES "x86[-_]64") + set(TARGET_ARCH "x86-64") + elseif (${FILE_OUTPUT} MATCHES "Intel 80386") + set(TARGET_ARCH "i386") + elseif (${FILE_OUTPUT} MATCHES "ARM") + set(TARGET_ARCH "ARM") + elseif (${FILE_OUTPUT} MATCHES "IBM S/390") + set(TARGET_ARCH "s390x") + else () + message(WARNING "Unknown target architecture!") + endif () + else () + message(WARNING "Error running `file` command on dummy executable") + endif () + else () + message(WARNING "Error compiling dummy.c file") + endif () + + if (TARGET_ARCH STREQUAL "i386") + # wasm doesn't allow for x87 floating point math + add_definitions(-msse2 -mfpmath=sse) + endif () + if (TARGET_ARCH STREQUAL "s390x") + add_definitions(-DWABT_BIG_ENDIAN=1) + endif () + endif () +endif () + +set(USE_SANITIZER FALSE) + +function(sanitizer NAME FLAGS) + if (${NAME}) + if (USE_SANITIZER) + message(FATAL_ERROR "Only one sanitizer allowed") + endif () + set(USE_SANITIZER TRUE PARENT_SCOPE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS}" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS}" PARENT_SCOPE) + endif () +endfunction() +sanitizer(USE_ASAN "-fsanitize=address") +sanitizer(USE_MSAN "-fsanitize=memory") +sanitizer(USE_LSAN "-fsanitize=leak") + +if (USE_UBSAN) + # -fno-sanitize-recover was deprecated, see if we are compiling with a newer + # clang that requires -fno-sanitize-recover=all. + set(UBSAN_BLACKLIST ${WABT_SOURCE_DIR}/ubsan.blacklist) + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-fsanitize=undefined -fno-sanitize-recover -Wall -Werror" HAS_UBSAN_RECOVER_BARE) + if (HAS_UBSAN_RECOVER_BARE) + sanitizer(USE_UBSAN "-fsanitize=undefined -fno-sanitize-recover -fsanitize-blacklist=${UBSAN_BLACKLIST}") + endif () + check_cxx_compiler_flag("-fsanitize=undefined -fno-sanitize-recover=all -Wall -Werror" HAS_UBSAN_RECOVER_ALL) + if (HAS_UBSAN_RECOVER_ALL) + sanitizer(USE_UBSAN "-fsanitize=undefined -fno-sanitize-recover=all -fsanitize-blacklist=${UBSAN_BLACKLIST}") + endif () + if (NOT USE_SANITIZER) + message(FATAL_ERROR "UBSAN is not supported") + endif () +endif () + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${WABT_SOURCE_DIR}/cmake) + +add_custom_target(everything) + +set(WABT_LIBRARY_SRC + src/apply-names.h + src/apply-names.cc + src/binary.h + src/binary.cc + src/binary-reader.h + src/binary-reader.cc + src/binary-reader-ir.h + src/binary-reader-ir.cc + src/binary-reader-logging.h + src/binary-reader-logging.cc + src/binary-writer.h + src/binary-writer.cc + src/binary-writer-spec.h + src/binary-writer-spec.cc + src/binding-hash.h + src/binding-hash.cc + src/color.h + src/color.cc + src/common.h + src/common.cc + src/config.h + src/config.cc + src/decompiler.h + src/decompiler-ast.h + src/decompiler-ls.h + src/decompiler-naming.h + src/decompiler.cc + src/error-formatter.h + src/error-formatter.cc + src/expr-visitor.h + src/expr-visitor.cc + src/feature.h + src/feature.cc + src/filenames.h + src/filenames.cc + src/generate-names.h + src/generate-names.cc + src/hash-util.h + src/hash-util.cc + src/ir.h + src/ir.cc + src/ir-util.h + src/ir-util.cc + src/leb128.h + src/leb128.cc + src/lexer-source.h + src/lexer-source.cc + src/lexer-source-line-finder.h + src/lexer-source-line-finder.cc + src/literal.h + src/literal.cc + src/opcode.h + src/opcode.cc + src/opcode-code-table.h + src/opcode-code-table.c + src/option-parser.h + src/option-parser.cc + src/resolve-names.h + src/resolve-names.cc + src/shared-validator.h + src/shared-validator.cc + src/stream.h + src/stream.cc + src/string-view.h + src/string-view.cc + src/token.h + src/token.cc + src/tracing.h + src/tracing.cc + src/type.h + src/type-checker.h + src/type-checker.cc + src/utf8.h + src/utf8.cc + src/validator.h + src/validator.cc + src/wast-lexer.h + src/wast-lexer.cc + src/wast-parser.h + src/wast-parser.cc + src/wat-writer.h + src/wat-writer.cc + + # TODO(binji): Move this into its own library? + src/interp/binary-reader-interp.h + src/interp/binary-reader-interp.cc + src/interp/interp.h + src/interp/interp.cc + src/interp/interp-inl.h + src/interp/interp-math.h + src/interp/interp-util.h + src/interp/interp-util.cc + src/interp/istream.h + src/interp/istream.cc +) + +add_library(wabt STATIC ${WABT_LIBRARY_SRC}) + +IF (NOT WIN32) + add_library(wasm-rt-impl STATIC wasm2c/wasm-rt-impl.c wasm2c/wasm-rt-impl.h) + install(TARGETS wasm-rt-impl DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(FILES wasm2c/wasm-rt.h wasm2c/wasm-rt-impl.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +endif () + +if (BUILD_FUZZ_TOOLS) + set(FUZZ_FLAGS "-fsanitize=fuzzer,address") + add_library(wabt-fuzz STATIC ${WABT_LIBRARY_SRC}) + set_target_properties(wabt-fuzz + PROPERTIES + COMPILE_FLAGS "${FUZZ_FLAGS}" + ) +endif () + +# libwasm, which implenents the wasm C API +if (BUILD_LIBWASM) + add_library(wasm SHARED ${WABT_LIBRARY_SRC} src/interp/interp-wasm-c-api.cc) + target_link_libraries(wasm wabt) + target_include_directories(wasm PUBLIC third_party/wasm-c-api/include) + if (COMPILER_IS_MSVC) + if (WERROR) + target_compile_options(wasm PRIVATE -WX) + endif () + target_compile_definitions(wasm PRIVATE "WASM_API_EXTERN=__declspec(dllexport)") + else () + if (WERROR) + target_compile_options(wasm PRIVATE -Werror) + endif () + target_compile_options(wasm PRIVATE $<$:-Wno-old-style-cast>) + target_compile_definitions(wasm PRIVATE "WASM_API_EXTERN=__attribute__((visibility(\"default\")))") + endif () + set_target_properties(wasm PROPERTIES CXX_VISIBILITY_PRESET hidden) +endif () + +if (CODE_COVERAGE) + add_definitions("-fprofile-arcs -ftest-coverage") + if (COMPILER_IS_CLANG) + set(CMAKE_EXE_LINKER_FLAGS "--coverage") + else () + link_libraries(gcov) + endif () +endif () + +include(CMakeParseArguments) +function(wabt_executable) + cmake_parse_arguments(EXE "WITH_LIBM;FUZZ;INSTALL" "NAME" "SOURCES;LIBS" ${ARGN}) + + # Always link libwabt. + if (EXE_FUZZ) + set(EXE_LIBS "${EXE_LIBS};wabt-fuzz") + set(EXTRA_LINK_FLAGS "${FUZZ_FLAGS}") + else () + set(EXE_LIBS "${EXE_LIBS};wabt") + endif () + + # Optionally link libm. + if (EXE_WITH_LIBM AND (COMPILER_IS_CLANG OR COMPILER_IS_GNU)) + set(EXE_LIBS "${EXE_LIBS};m") + endif () + + add_executable(${EXE_NAME} ${EXE_SOURCES}) + add_dependencies(everything ${EXE_NAME}) + target_link_libraries(${EXE_NAME} ${EXE_LIBS}) + set_property(TARGET ${EXE_NAME} PROPERTY CXX_STANDARD 11) + set_property(TARGET ${EXE_NAME} PROPERTY CXX_STANDARD_REQUIRED ON) + + if (EMSCRIPTEN) + # build to JS for now, as node.js doesn't have code caching for wasm yet, + # and wasm startup times are slower + set(EXTRA_LINK_FLAGS + "${EXTRA_LINK_FLAGS} -s NODERAWFS -s SINGLE_FILE -s WASM=0 -Oz -s ALLOW_MEMORY_GROWTH=1" + ) + endif () + + set_target_properties(${EXE_NAME} + PROPERTIES + LINK_FLAGS "${EXTRA_LINK_FLAGS}" + ) + + if (EXE_INSTALL) + list(APPEND WABT_EXECUTABLES ${EXE_NAME}) + set(WABT_EXECUTABLES ${WABT_EXECUTABLES} PARENT_SCOPE) + + add_custom_target(${EXE_NAME}-copy-to-bin ALL + COMMAND ${CMAKE_COMMAND} -E make_directory ${WABT_SOURCE_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy $ ${WABT_SOURCE_DIR}/bin + DEPENDS ${EXE_NAME} + ) + endif () +endfunction() + +if (BUILD_TOOLS) + # wat2wasm + wabt_executable( + NAME wat2wasm + SOURCES src/tools/wat2wasm.cc + INSTALL + ) + + # wast2json + wabt_executable( + NAME wast2json + SOURCES src/tools/wast2json.cc + INSTALL + ) + + # wasm2wat + wabt_executable( + NAME wasm2wat + SOURCES src/tools/wasm2wat.cc + INSTALL + ) + + # wasm2c + wabt_executable( + NAME wasm2c + SOURCES src/tools/wasm2c.cc src/c-writer.cc + INSTALL + ) + + # wasm-opcodecnt + wabt_executable( + NAME wasm-opcodecnt + SOURCES src/tools/wasm-opcodecnt.cc src/binary-reader-opcnt.cc + INSTALL + ) + + # wasm-objdump + wabt_executable( + NAME wasm-objdump + SOURCES src/tools/wasm-objdump.cc src/binary-reader-objdump.cc + INSTALL + ) + + if(WITH_WASI) + add_subdirectory("third_party/uvwasi" EXCLUDE_FROM_ALL) + include_directories(third_party/uvwasi/include) + add_definitions(-DWITH_WASI) + set(INTERP_LIBS uvwasi_a) + set(EXTRA_INTERP_SRC src/interp/interp-wasi.cc) + endif() + + # wasm-interp + + wabt_executable( + NAME wasm-interp + SOURCES src/tools/wasm-interp.cc ${EXTRA_INTERP_SRC} + LIBS ${INTERP_LIBS} + WITH_LIBM + INSTALL + ) + + # spectest-interp + wabt_executable( + NAME spectest-interp + SOURCES src/tools/spectest-interp.cc + WITH_LIBM + INSTALL + ) + + # wat-desugar + wabt_executable( + NAME wat-desugar + SOURCES src/tools/wat-desugar.cc + INSTALL + ) + + # wasm-validate + wabt_executable( + NAME wasm-validate + SOURCES src/tools/wasm-validate.cc + INSTALL + ) + + # wasm-strip + wabt_executable( + NAME wasm-strip + SOURCES src/tools/wasm-strip.cc + INSTALL + ) + + # wasm-decompile + wabt_executable( + NAME wasm-decompile + SOURCES src/tools/wasm-decompile.cc + INSTALL + ) + + if(BUILD_FUZZ_TOOLS) + # wasm2wat-fuzz + wabt_executable( + NAME wasm2wat-fuzz + SOURCES src/tools/wasm2wat-fuzz.cc + FUZZ + INSTALL + ) + endif () +endif () + +# Python 3.5 is the version shipped in Ubuntu Xenial +find_package(PythonInterp 3.5) +if(BUILD_TESTS AND (NOT PYTHONINTERP_FOUND)) + set(BUILD_TESTS OFF) + message(WARNING "Skipping tests. Python 3 is required for wabt testing. Please install python3 to run tests.") +endif() + +find_package(Threads) +if (BUILD_TESTS) + if (NOT USE_SYSTEM_GTEST) + if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/gtest/googletest) + message(FATAL_ERROR "Can't find third_party/gtest. Run git submodule update --init, or disable with CMake -DBUILD_TESTS=OFF.") + endif () + + include_directories( + third_party/gtest/googletest + third_party/gtest/googletest/include + ) + + # gtest + add_library(gtest STATIC + third_party/gtest/googletest/src/gtest-all.cc + ) + + add_library(gtest_main STATIC + third_party/gtest/googletest/src/gtest_main.cc + ) + endif () + + # hexfloat-test + set(HEXFLOAT_TEST_SRCS + src/literal.cc + src/test-hexfloat.cc + ) + wabt_executable( + NAME hexfloat_test + SOURCES ${HEXFLOAT_TEST_SRCS} + LIBS gtest_main gtest ${CMAKE_THREAD_LIBS_INIT} + ) + + # wabt-unittests + set(UNITTESTS_SRCS + src/test-binary-reader.cc + src/test-circular-array.cc + src/test-interp.cc + src/test-intrusive-list.cc + src/test-literal.cc + src/test-option-parser.cc + src/test-string-view.cc + src/test-filenames.cc + src/test-utf8.cc + src/test-wast-parser.cc + ) + wabt_executable( + NAME wabt-unittests + SOURCES ${UNITTESTS_SRCS} + LIBS gtest_main gtest ${CMAKE_THREAD_LIBS_INIT} + ) + + if (NOT CMAKE_VERSION VERSION_LESS "3.2") + set(USES_TERMINAL USES_TERMINAL) + endif () + + # test running + set(RUN_TESTS_PY ${WABT_SOURCE_DIR}/test/run-tests.py) + + add_custom_target(run-tests + COMMAND ${PYTHON_EXECUTABLE} ${RUN_TESTS_PY} --bindir $ + DEPENDS ${WABT_EXECUTABLES} + WORKING_DIRECTORY ${WABT_SOURCE_DIR} + ${USES_TERMINAL} + ) + + add_custom_target(run-unittests + COMMAND $ + DEPENDS wabt-unittests + WORKING_DIRECTORY ${WABT_SOURCE_DIR} + ${USES_TERMINAL} + ) + + add_custom_target(run-c-api-tests + COMMAND ${PYTHON_EXECUTABLE} ${WABT_SOURCE_DIR}/test/run-c-api-examples.py --bindir $ + WORKING_DIRECTORY ${WABT_SOURCE_DIR} + ${USES_TERMINAL} + ) + + add_custom_target(check DEPENDS run-unittests run-tests run-c-api-tests) + + function(c_api_example NAME) + set(EXENAME wasm-c-api-${NAME}) + add_executable(${EXENAME} third_party/wasm-c-api/example/${NAME}.c) + if (NOT COMPILER_IS_MSVC) + set_target_properties(${EXENAME} PROPERTIES COMPILE_FLAGS "-std=gnu11 -Wno-pointer-to-int-cast") + endif () + target_link_libraries(${EXENAME} wasm Threads::Threads) + add_custom_target(${EXENAME}-copy-to-bin ALL + COMMAND ${CMAKE_COMMAND} -E make_directory ${WABT_SOURCE_DIR}/bin + COMMAND ${CMAKE_COMMAND} -E copy $ ${WABT_SOURCE_DIR}/bin/ + COMMAND ${CMAKE_COMMAND} -E copy ${WABT_SOURCE_DIR}/third_party/wasm-c-api/example/${NAME}.wasm $/ + COMMAND ${CMAKE_COMMAND} -E copy ${WABT_SOURCE_DIR}/third_party/wasm-c-api/example/${NAME}.wasm ${WABT_SOURCE_DIR}/bin/ + DEPENDS ${EXENAME} + ) + add_dependencies(run-c-api-tests ${EXENAME}) + endfunction() + + c_api_example(callback) + c_api_example(finalize) + c_api_example(global) + c_api_example(hello) + c_api_example(hostref) + c_api_example(multi) + c_api_example(memory) + c_api_example(reflect) + c_api_example(serialize) + c_api_example(start) + c_api_example(table) + c_api_example(trap) + if (NOT WIN32) + # depends on pthreads + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + c_api_example(threads) + endif () +endif () + +# install +if (BUILD_TOOLS OR BUILD_TESTS) + install(TARGETS ${WABT_EXECUTABLES} DESTINATION bin) + if (UNIX) + if (NOT CMAKE_INSTALL_MANDIR) + include(GNUInstallDirs) + endif () + file(GLOB MAN_FILES "${CMAKE_CURRENT_SOURCE_DIR}/man/*.1") + foreach(MAN_FILE ${MAN_FILES}) + install(FILES ${MAN_FILE} + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1/) + endforeach() + endif () +endif () + +if (EMSCRIPTEN) + # flags for all emscripten builds + + # exceptions are never needed + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions") + + # wabt.js + + # just dump everything into one binary so we can reference it from JavaScript + add_definitions(-Wno-warn-absolute-paths) + add_executable(libwabtjs src/emscripten-helpers.cc) + add_dependencies(everything libwabtjs) + target_link_libraries(libwabtjs wabt) + set_target_properties(libwabtjs PROPERTIES OUTPUT_NAME libwabt) + + set(WABT_POST_JS ${WABT_SOURCE_DIR}/src/wabt.post.js) + set(EMSCRIPTEN_EXPORTED_JSON ${WABT_SOURCE_DIR}/src/emscripten-exported.json) + + set(LIBWABT_LINK_FLAGS + -s SINGLE_FILE + --post-js ${WABT_POST_JS} + -s EXPORTED_FUNCTIONS=\"@${EMSCRIPTEN_EXPORTED_JSON}\" + -s RESERVED_FUNCTION_POINTERS=10 + -s NO_EXIT_RUNTIME=1 + -s ALLOW_MEMORY_GROWTH=1 + -s MODULARIZE=1 + -s EXPORT_NAME=\"'WabtModule'\" + -s WASM=0 + -Oz + ) + string(REPLACE ";" " " LIBWABT_LINK_FLAGS_STR "${LIBWABT_LINK_FLAGS}") + + set_target_properties(libwabtjs + PROPERTIES + LINK_FLAGS "${LIBWABT_LINK_FLAGS_STR}" + LINK_DEPENDS "${WABT_POST_JS};${EMSCRIPTEN_EXPORTED_JSON}" + ) +endif () diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Contributing.md b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Contributing.md new file mode 100644 index 0000000..1cc607f --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Contributing.md @@ -0,0 +1,8 @@ +# Contributing to WebAssembly + +Interested in participating? Please follow +[the same contributing guidelines as the design repository][]. + + [the same contributing guidelines as the design repository]: https://github.com/WebAssembly/design/blob/master/Contributing.md + +Also, please be sure to read [the README.md](README.md) for this repository. diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/LICENSE b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Makefile b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Makefile new file mode 100644 index 0000000..00476ae --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Makefile @@ -0,0 +1,182 @@ +# +# Copyright 2016 WebAssembly Community Group participants +# +# 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. +# + +.SUFFIXES: + +MAKEFILE_NAME := $(lastword $(MAKEFILE_LIST)) +ROOT_DIR := $(dir $(abspath $(MAKEFILE_NAME))) + +USE_NINJA ?= 0 +EMSCRIPTEN_DIR ?= $(dir $(shell which emcc)) +CMAKE_CMD ?= cmake + +DEFAULT_SUFFIX = clang-debug + +COMPILERS := GCC GCC_I686 CLANG CLANG_I686 EMCC +BUILD_TYPES := DEBUG RELEASE +SANITIZERS := ASAN MSAN LSAN UBSAN FUZZ +CONFIGS := NORMAL $(SANITIZERS) COV NO_TESTS + +# directory names +GCC_DIR := gcc/ +GCC_I686_DIR := gcc-i686/ +CLANG_DIR := clang/ +CLANG_I686_DIR := clang-i686/ +EMCC_DIR := emscripten/ +DEBUG_DIR := Debug/ +RELEASE_DIR := Release/ +NORMAL_DIR := +ASAN_DIR := asan/ +MSAN_DIR := msan/ +LSAN_DIR := lsan/ +UBSAN_DIR := ubsan/ +FUZZ_DIR := fuzz/ +COV_DIR := cov/ +NO_TESTS_DIR := no-tests/ + +# CMake flags +GCC_FLAG := -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ +GCC_I686_FLAG := -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 +CLANG_FLAG := -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ +CLANG_I686_FLAG := -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \ + -DCMAKE_C_FLAGS=-m32 -DCMAKE_CXX_FLAGS=-m32 +EMCC_FLAG := -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN_DIR}/cmake/Modules/Platform/Emscripten.cmake +DEBUG_FLAG := -DCMAKE_BUILD_TYPE=Debug +RELEASE_FLAG := -DCMAKE_BUILD_TYPE=Release +NORMAL_FLAG := +ASAN_FLAG := -DUSE_ASAN=ON +MSAN_FLAG := -DUSE_MSAN=ON +LSAN_FLAG := -DUSE_LSAN=ON +UBSAN_FLAG := -DUSE_UBSAN=ON +FUZZ_FLAG := -DBUILD_FUZZ_TOOLS=ON +COV_FLAG := -DCODE_COVERAGE=ON +NO_TESTS_FLAG := -DBUILD_TESTS=OFF + +# make target prefixes +GCC_PREFIX := gcc +GCC_I686_PREFIX := gcc-i686 +CLANG_PREFIX := clang +CLANG_I686_PREFIX := clang-i686 +EMCC_PREFIX := emscripten +DEBUG_PREFIX := -debug +RELEASE_PREFIX := -release +NORMAL_PREFIX := +ASAN_PREFIX := -asan +MSAN_PREFIX := -msan +LSAN_PREFIX := -lsan +UBSAN_PREFIX := -ubsan +FUZZ_PREFIX := -fuzz +COV_PREFIX := -cov +NO_TESTS_PREFIX := -no-tests + +ifeq ($(USE_NINJA),1) +BUILD_CMD := ninja +BUILD_FILE := build.ninja +GENERATOR := Ninja +else +BUILD_CMD := +$(MAKE) --no-print-directory +BUILD_FILE := Makefile +GENERATOR := "Unix Makefiles" +endif + +CMAKE_DIR = out/$($(1)_DIR)$($(2)_DIR)$($(3)_DIR) +BUILD_TARGET = $($(1)_PREFIX)$($(2)_PREFIX)$($(3)_PREFIX) +INSTALL_TARGET = install-$($(1)_PREFIX)$($(2)_PREFIX)$($(3)_PREFIX) +TEST_TARGET = test-$($(1)_PREFIX)$($(2)_PREFIX)$($(3)_PREFIX) + +define CMAKE +$(call CMAKE_DIR,$(1),$(2),$(3)): + mkdir -p $(call CMAKE_DIR,$(1),$(2),$(3)) + +$(call CMAKE_DIR,$(1),$(2),$(3))$$(BUILD_FILE): | $(call CMAKE_DIR,$(1),$(2),$(3)) + cd $(call CMAKE_DIR,$(1),$(2),$(3)) && \ + $$(CMAKE_CMD) -G $$(GENERATOR) $$(ROOT_DIR) $$($(1)_FLAG) $$($(2)_FLAG) $$($(3)_FLAG) +endef + +define BUILD +.PHONY: $(call BUILD_TARGET,$(1),$(2),$(3)) +$(call BUILD_TARGET,$(1),$(2),$(3)): $(call CMAKE_DIR,$(1),$(2),$(3))$$(BUILD_FILE) + $$(BUILD_CMD) -C $(call CMAKE_DIR,$(1),$(2),$(3)) all +endef + +define INSTALL +.PHONY: $(call INSTALL_TARGET,$(1),$(2),$(3)) +$(call INSTALL_TARGET,$(1),$(2),$(3)): $(call CMAKE_DIR,$(1),$(2),$(3))$$(BUILD_FILE) + $$(BUILD_CMD) -C $(call CMAKE_DIR,$(1),$(2),$(3)) install +endef + +define TEST +.PHONY: $(call TEST_TARGET,$(1),$(2),$(3)) +$(call TEST_TARGET,$(1),$(2),$(3)): $(call CMAKE_DIR,$(1),$(2),$(3))$$(BUILD_FILE) + $$(BUILD_CMD) -C $(call CMAKE_DIR,$(1),$(2),$(3)) check +test-everything: $(CALL TEST_TARGET,$(1),$(2),$(3)) +endef + +.PHONY: all install test +all: $(DEFAULT_SUFFIX) +install: install-$(DEFAULT_SUFFIX) +test: test-$(DEFAULT_SUFFIX) + +.PHONY: clean +clean: + rm -rf out + +.PHONY: test-everything +test-everything: + +.PHONY: update-gperf +update-gperf: src/prebuilt/lexer-keywords.cc + +src/prebuilt/lexer-keywords.cc: src/lexer-keywords.txt + gperf -m 50 -L C++ -N InWordSet -E -t -c --output-file=$@ $< + +.PHONY: update-wasm2c +update-wasm2c: src/prebuilt/wasm2c.include.c src/prebuilt/wasm2c.include.h + +src/prebuilt/wasm2c.include.c: src/wasm2c.c.tmpl + src/wasm2c_tmpl.py -o $@ $< + +src/prebuilt/wasm2c.include.h: src/wasm2c.h.tmpl + src/wasm2c_tmpl.py -o $@ $< + +.PHONY: demo +demo: emscripten-release + cp out/emscripten/Release/libwabt.js docs/demo + +# running CMake +$(foreach CONFIG,$(CONFIGS), \ + $(foreach COMPILER,$(COMPILERS), \ + $(foreach BUILD_TYPE,$(BUILD_TYPES), \ + $(eval $(call CMAKE,$(COMPILER),$(BUILD_TYPE),$(CONFIG)))))) + +# building +$(foreach CONFIG,$(CONFIGS), \ + $(foreach COMPILER,$(COMPILERS), \ + $(foreach BUILD_TYPE,$(BUILD_TYPES), \ + $(eval $(call BUILD,$(COMPILER),$(BUILD_TYPE),$(CONFIG)))))) + +# installing +$(foreach CONFIG,$(CONFIGS), \ + $(foreach COMPILER,$(COMPILERS), \ + $(foreach BUILD_TYPE,$(BUILD_TYPES), \ + $(eval $(call INSTALL,$(COMPILER),$(BUILD_TYPE),$(CONFIG)))))) + +# test running +$(foreach CONFIG,$(CONFIGS), \ + $(foreach COMPILER,$(COMPILERS), \ + $(foreach BUILD_TYPE,$(BUILD_TYPES), \ + $(eval $(call TEST,$(COMPILER),$(BUILD_TYPE),$(CONFIG)))))) diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/README.md b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/README.md new file mode 100644 index 0000000..7e317a8 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/README.md @@ -0,0 +1,358 @@ +[![Github CI Status](https://github.com/WebAssembly/wabt/workflows/CI/badge.svg)](https://github.com/WebAssembly/wabt) + +# WABT: The WebAssembly Binary Toolkit + +WABT (we pronounce it "wabbit") is a suite of tools for WebAssembly, including: + + - [**wat2wasm**](https://webassembly.github.io/wabt/doc/wat2wasm.1.html): translate from [WebAssembly text format](https://webassembly.github.io/spec/core/text/index.html) to the [WebAssembly binary format](https://webassembly.github.io/spec/core/binary/index.html) + - [**wasm2wat**](https://webassembly.github.io/wabt/doc/wasm2wat.1.html): the inverse of wat2wasm, translate from the binary format back to the text format (also known as a .wat) + - [**wasm-objdump**](https://webassembly.github.io/wabt/doc/wasm-objdump.1.html): print information about a wasm binary. Similiar to objdump. + - [**wasm-interp**](https://webassembly.github.io/wabt/doc/wasm-interp.1.html): decode and run a WebAssembly binary file using a stack-based interpreter + - [**wasm-decompile**](https://webassembly.github.io/wabt/doc/wasm-decompile.1.html): decompile a wasm binary into readable C-like syntax. + - [**wat-desugar**](https://webassembly.github.io/wabt/doc/wat-desugar.1.html): parse .wat text form as supported by the spec interpreter (s-expressions, flat syntax, or mixed) and print "canonical" flat format + - [**wasm2c**](https://webassembly.github.io/wabt/doc/wasm2c.1.html): convert a WebAssembly binary file to a C source and header + - [**wasm-strip**](https://webassembly.github.io/wabt/doc/wasm-strip.1.html): remove sections of a WebAssembly binary file + - [**wasm-validate**](https://webassembly.github.io/wabt/doc/wasm-validate.1.html): validate a file in the WebAssembly binary format + - [**wast2json**](https://webassembly.github.io/wabt/doc/wast2json.1.html): convert a file in the wasm spec test format to a JSON file and associated wasm binary files + - [**wasm-opcodecnt**](https://webassembly.github.io/wabt/doc/wasm-opcodecnt.1.html): count opcode usage for instructions + - [**spectest-interp**](https://webassembly.github.io/wabt/doc/spectest-interp.1.html): read a Spectest JSON file, and run its tests in the interpreter + +These tools are intended for use in (or for development of) toolchains or other +systems that want to manipulate WebAssembly files. Unlike the WebAssembly spec +interpreter (which is written to be as simple, declarative and "speccy" as +possible), they are written in C/C++ and designed for easier integration into +other systems. Unlike [Binaryen](https://github.com/WebAssembly/binaryen) these +tools do not aim to provide an optimization platform or a higher-level compiler +target; instead they aim for full fidelity and compliance with the spec (e.g. +1:1 round-trips with no changes to instructions). + +## Online Demos + +Wabt has been compiled to JavaScript via emscripten. Some of the functionality is available in the following demos: + +- [index](https://webassembly.github.io/wabt/demo/) +- [wat2wasm](https://webassembly.github.io/wabt/demo/wat2wasm/) +- [wasm2wat](https://webassembly.github.io/wabt/demo/wasm2wat/) + +## Supported Proposals + +* Proposal: Name and link to the WebAssembly proposal repo +* flag: Flag to pass to the tool to enable/disable support for the feature +* default: Whether the feature is enabled by default +* binary: Whether wabt can read/write the binary format +* text: Whether wabt can read/write the text format +* validate: Whether wabt can validate the syntax +* interpret: Whether wabt can execute these operations in `wasm-interp` or `spectest-interp` + +| Proposal | flag | default | binary | text | validate | interpret | +| - | - | - | - | - | - | - | +| [exception handling][] | `--enable-exceptions` | | ✓ | ✓ | ✓ | ✓ | +| [mutable globals][] | `--disable-mutable-globals` | ✓ | ✓ | ✓ | ✓ | ✓ | +| [nontrapping float-to-int conversions][] | `--disable-saturating-float-to-int` | ✓ | ✓ | ✓ | ✓ | ✓ | +| [sign extension][] | `--disable-sign-extension` | ✓ | ✓ | ✓ | ✓ | ✓ | +| [simd][] | `--enable-simd` | | ✓ | ✓ | ✓ | ✓ | +| [threads][] | `--enable-threads` | | ✓ | ✓ | ✓ | ✓ | +| [multi-value][] | `--disable-multi-value` | ✓ | ✓ | ✓ | ✓ | ✓ | +| [tail-call][] | `--enable-tail-call` | | ✓ | ✓ | ✓ | ✓ | +| [bulk memory][] | `--enable-bulk-memory` | | ✓ | ✓ | ✓ | ✓ | +| [reference types][] | `--enable-reference-types` | | ✓ | ✓ | ✓ | ✓ | +| [annotations][] | `--enable-annotations` | | | ✓ | | | +| [memory64][] | `--enable-memory64` | | | | | | + +[exception handling]: https://github.com/WebAssembly/exception-handling +[mutable globals]: https://github.com/WebAssembly/mutable-global +[nontrapping float-to-int conversions]: https://github.com/WebAssembly/nontrapping-float-to-int-conversions +[sign extension]: https://github.com/WebAssembly/sign-extension-ops +[simd]: https://github.com/WebAssembly/simd +[threads]: https://github.com/WebAssembly/threads +[multi-value]: https://github.com/WebAssembly/multi-value +[tail-call]: https://github.com/WebAssembly/tail-call +[bulk memory]: https://github.com/WebAssembly/bulk-memory-operations +[reference types]: https://github.com/WebAssembly/reference-types +[annotations]: https://github.com/WebAssembly/annotations +[memory64]: https://github.com/WebAssembly/memory64 + +## Cloning + +Clone as normal, but don't forget to get the submodules as well: + +```console +$ git clone --recursive https://github.com/WebAssembly/wabt +$ cd wabt +``` + +This will fetch the testsuite and gtest repos, which are needed for some tests. + +## Building using CMake directly (Linux and macOS) + +You'll need [CMake](https://cmake.org). You can then run CMake, the normal way: + +```console +$ mkdir build +$ cd build +$ cmake .. +$ cmake --build . +``` + +This will produce build files using CMake's default build generator. Read the CMake +documentation for more information. + +**NOTE**: You must create a separate directory for the build artifacts (e.g. `build` above). +Running `cmake` from the repo root directory will not work since the build produces an +executable called `wasm2c` which conflicts with the `wasm2c` directory. + +## Building using the top-level `Makefile` (Linux and macOS) + +**NOTE**: Under the hood, this uses `make` to run CMake, which then calls `make` again. +On some systems (typically macOS), this doesn't build properly. If you see these errors, +you can build using CMake directly as described above. + +You'll need [CMake](https://cmake.org). If you just run `make`, it will run CMake for you, +and put the result in `bin/clang/Debug/` by default: + +> Note: If you are on macOS, you will need to use CMake version 3.2 or higher + +```console +$ make +``` + +This will build the default version of the tools: a debug build using the Clang +compiler. + +There are many make targets available for other configurations as well. They +are generated from every combination of a compiler, build type and +configuration. + + - compilers: `gcc`, `clang`, `gcc-i686`, `emcc` + - build types: `debug`, `release` + - configurations: empty, `asan`, `msan`, `lsan`, `ubsan`, `fuzz`, `no-tests` + +They are combined with dashes, for example: + +```console +$ make clang-debug +$ make gcc-i686-release +$ make clang-debug-lsan +$ make gcc-debug-no-tests +``` + +## Building (Windows) + +You'll need [CMake](https://cmake.org). You'll also need +[Visual Studio](https://www.visualstudio.com/) (2015 or newer) or +[MinGW](http://www.mingw.org/). + +_Note: Visual Studio 2017 and later come with CMake (and the Ninja build system) +out of the box, and should be on your PATH if you open a Developer Command prompt. +See for more details._ + +You can run CMake from the command prompt, or use the CMake GUI tool. See +[Running CMake](https://cmake.org/runningcmake/) for more information. + +When running from the commandline, create a new directory for the build +artifacts, then run cmake from this directory: + +```console +> cd [build dir] +> cmake [wabt project root] -DCMAKE_BUILD_TYPE=[config] -DCMAKE_INSTALL_PREFIX=[install directory] -G [generator] +``` + +The `[config]` parameter should be a CMake build type, typically `DEBUG` or `RELEASE`. + +The `[generator]` parameter should be the type of project you want to generate, +for example `"Visual Studio 14 2015"`. You can see the list of available +generators by running `cmake --help`. + +To build the project, you can use Visual Studio, or you can tell CMake to do it: + +```console +> cmake --build [wabt project root] --config [config] --target install +``` + +This will build and install to the installation directory you provided above. + +So, for example, if you want to build the debug configuration on Visual Studio 2015: + +```console +> mkdir build +> cd build +> cmake .. -DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_INSTALL_PREFIX=..\ -G "Visual Studio 14 2015" +> cmake --build . --config DEBUG --target install +``` + +## Adding new keywords to the lexer + +If you want to add new keywords, you'll need to install +[gperf](https://www.gnu.org/software/gperf/). Before you upload your PR, please +run `make update-gperf` to update the prebuilt C++ sources in `src/prebuilt/`. + +## Running wat2wasm + +Some examples: + +```sh +# parse and typecheck test.wat +$ bin/wat2wasm test.wat + +# parse test.wat and write to binary file test.wasm +$ bin/wat2wasm test.wat -o test.wasm + +# parse spec-test.wast, and write verbose output to stdout (including the +# meaning of every byte) +$ bin/wat2wasm spec-test.wast -v +``` + +You can use `--help` to get additional help: + +```console +$ bin/wat2wasm --help +``` + +Or try the [online demo](https://webassembly.github.io/wabt/demo/wat2wasm/). + +## Running wasm2wat + +Some examples: + +```sh +# parse binary file test.wasm and write text file test.wat +$ bin/wasm2wat test.wasm -o test.wat + +# parse test.wasm and write test.wat +$ bin/wasm2wat test.wasm -o test.wat +``` + +You can use `--help` to get additional help: + +```console +$ bin/wasm2wat --help +``` + +Or try the [online demo](https://webassembly.github.io/wabt/demo/wasm2wat/). + +## Running wasm-interp + +Some examples: + +```sh +# parse binary file test.wasm, and type-check it +$ bin/wasm-interp test.wasm + +# parse test.wasm and run all its exported functions +$ bin/wasm-interp test.wasm --run-all-exports + +# parse test.wasm, run the exported functions and trace the output +$ bin/wasm-interp test.wasm --run-all-exports --trace + +# parse test.json and run the spec tests +$ bin/wasm-interp test.json --spec + +# parse test.wasm and run all its exported functions, setting the value stack +# size to 100 elements +$ bin/wasm-interp test.wasm -V 100 --run-all-exports +``` + +You can use `--help` to get additional help: + +```console +$ bin/wasm-interp --help +``` + +## Running wast2json + +See [wast2json.md](docs/wast2json.md). + +## Running wasm-decompile + +For example: + +```sh +# parse binary file test.wasm and write text file test.dcmp +$ bin/wasm-decompile test.wasm -o test.dcmp +``` + +You can use `--help` to get additional help: + +```console +$ bin/wasm-decompile --help +``` + +See [decompiler.md](docs/decompiler.md) for more information on the language +being generated. + +## Running wasm2c + +See [wasm2c.md](wasm2c/README.md) + +## Running the test suite + +See [test/README.md](test/README.md). + +## Sanitizers + +To build with the [LLVM sanitizers](https://github.com/google/sanitizers), +append the sanitizer name to the target: + +```console +$ make clang-debug-asan +$ make clang-debug-msan +$ make clang-debug-lsan +$ make clang-debug-ubsan +``` + +There are configurations for the Address Sanitizer (ASAN), Memory Sanitizer +(MSAN), Leak Sanitizer (LSAN) and Undefine Behavior Sanitizer (UBSAN). You can +read about the behaviors of the sanitizers in the link above, but essentially +the Address Sanitizer finds invalid memory accesses (use after free, access +out-of-bounds, etc.), Memory Sanitizer finds uses of uninitialized memory, +the Leak Sanitizer finds memory leaks, and the Undefined Behavior Sanitizer +finds undefined behavior (surprise!). + +Typically, you'll just want to run all the tests for a given sanitizer: + +```console +$ make test-asan +``` + +You can also run the tests for a release build: + +```console +$ make test-clang-release-asan +... +``` + +The Travis bots run all of these tests (and more). Before you land a change, +you should run them too. One easy way is to use the `test-everything` target: + +```console +$ make test-everything +``` + +To run everything the Travis bots do, you can use the following scripts: + +```console +$ CC=gcc scripts/travis-build.sh +$ CC=gcc scripts/travis-test.sh +$ CC=clang scripts/travis-build.sh +$ CC=clang scripts/travis-test.sh +``` + +## Fuzzing + +To build using the [LLVM fuzzer support](https://llvm.org/docs/LibFuzzer.html), +append `fuzz` to the target: + +```console +$ make clang-debug-fuzz +``` + +This will produce a `wasm2wat_fuzz` binary. It can be used to fuzz the binary +reader, as well as reproduce fuzzer errors found by +[oss-fuzz](https://github.com/google/oss-fuzz/tree/master/projects/wabt). + +```console +$ out/clang/Debug/fuzz/wasm2wat_fuzz ... +``` + +See the [libFuzzer documentation](https://llvm.org/docs/LibFuzzer.html) for +more information about how to use this tool. diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/cmake/README.md b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/cmake/README.md new file mode 100644 index 0000000..ee8057f --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/cmake/README.md @@ -0,0 +1,3 @@ +FindRE2C.cmake is copied from the [CMakeXFind +repository](https://github.com/julp/CMakeXFind). This makes it more convenient +to build for users who can't/won't run `git submodule update --init`. diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.cc new file mode 100644 index 0000000..0159091 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.cc @@ -0,0 +1,510 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/apply-names.h" + +#include +#include +#include + +#include "src/expr-visitor.h" +#include "src/ir.h" +#include "src/string-view.h" + +namespace wabt { + +namespace { + +class NameApplier : public ExprVisitor::DelegateNop { + public: + NameApplier(); + + Result VisitModule(Module* module); + + // Implementation of ExprVisitor::DelegateNop. + Result BeginBlockExpr(BlockExpr*) override; + Result EndBlockExpr(BlockExpr*) override; + Result OnBrExpr(BrExpr*) override; + Result OnBrIfExpr(BrIfExpr*) override; + Result OnBrTableExpr(BrTableExpr*) override; + Result OnCallExpr(CallExpr*) override; + Result OnRefFuncExpr(RefFuncExpr*) override; + Result OnCallIndirectExpr(CallIndirectExpr*) override; + Result OnReturnCallExpr(ReturnCallExpr*) override; + Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override; + Result OnGlobalGetExpr(GlobalGetExpr*) override; + Result OnGlobalSetExpr(GlobalSetExpr*) override; + Result BeginIfExpr(IfExpr*) override; + Result EndIfExpr(IfExpr*) override; + Result OnLocalGetExpr(LocalGetExpr*) override; + Result OnLocalSetExpr(LocalSetExpr*) override; + Result OnLocalTeeExpr(LocalTeeExpr*) override; + Result BeginLoopExpr(LoopExpr*) override; + Result EndLoopExpr(LoopExpr*) override; + Result OnDataDropExpr(DataDropExpr*) override; + Result OnMemoryInitExpr(MemoryInitExpr*) override; + Result OnElemDropExpr(ElemDropExpr*) override; + Result OnTableCopyExpr(TableCopyExpr*) override; + Result OnTableInitExpr(TableInitExpr*) override; + Result OnTableGetExpr(TableGetExpr*) override; + Result OnTableSetExpr(TableSetExpr*) override; + Result OnTableGrowExpr(TableGrowExpr*) override; + Result OnTableSizeExpr(TableSizeExpr*) override; + Result OnTableFillExpr(TableFillExpr*) override; + Result BeginTryExpr(TryExpr*) override; + Result EndTryExpr(TryExpr*) override; + Result OnCatchExpr(TryExpr*, Catch*) override; + Result OnDelegateExpr(TryExpr*) override; + Result OnThrowExpr(ThrowExpr*) override; + Result OnRethrowExpr(RethrowExpr*) override; + + private: + void PushLabel(const std::string& label); + void PopLabel(); + string_view FindLabelByVar(Var* var); + void UseNameForVar(string_view name, Var* var); + Result UseNameForFuncTypeVar(Var* var); + Result UseNameForFuncVar(Var* var); + Result UseNameForGlobalVar(Var* var); + Result UseNameForTableVar(Var* var); + Result UseNameForMemoryVar(Var* var); + Result UseNameForEventVar(Var* var); + Result UseNameForDataSegmentVar(Var* var); + Result UseNameForElemSegmentVar(Var* var); + Result UseNameForParamAndLocalVar(Func* func, Var* var); + Result VisitFunc(Index func_index, Func* func); + Result VisitGlobal(Global* global); + Result VisitEvent(Event* event); + Result VisitExport(Index export_index, Export* export_); + Result VisitElemSegment(Index elem_segment_index, ElemSegment* segment); + Result VisitDataSegment(Index data_segment_index, DataSegment* segment); + Result VisitStart(Var* start_var); + + Module* module_ = nullptr; + Func* current_func_ = nullptr; + ExprVisitor visitor_; + std::vector param_and_local_index_to_name_; + std::vector labels_; +}; + +NameApplier::NameApplier() : visitor_(this) {} + +void NameApplier::PushLabel(const std::string& label) { + labels_.push_back(label); +} + +void NameApplier::PopLabel() { + labels_.pop_back(); +} + +string_view NameApplier::FindLabelByVar(Var* var) { + if (var->is_name()) { + for (int i = labels_.size() - 1; i >= 0; --i) { + const std::string& label = labels_[i]; + if (label == var->name()) { + return label; + } + } + return string_view(); + } else { + if (var->index() >= labels_.size()) { + return string_view(); + } + return labels_[labels_.size() - 1 - var->index()]; + } +} + +void NameApplier::UseNameForVar(string_view name, Var* var) { + if (var->is_name()) { + assert(name == var->name()); + return; + } + + if (!name.empty()) { + var->set_name(name); + } +} + +Result NameApplier::UseNameForFuncTypeVar(Var* var) { + FuncType* func_type = module_->GetFuncType(*var); + if (!func_type) { + return Result::Error; + } + UseNameForVar(func_type->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForFuncVar(Var* var) { + Func* func = module_->GetFunc(*var); + if (!func) { + return Result::Error; + } + UseNameForVar(func->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForGlobalVar(Var* var) { + Global* global = module_->GetGlobal(*var); + if (!global) { + return Result::Error; + } + UseNameForVar(global->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForTableVar(Var* var) { + Table* table = module_->GetTable(*var); + if (!table) { + return Result::Error; + } + UseNameForVar(table->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForMemoryVar(Var* var) { + Memory* memory = module_->GetMemory(*var); + if (!memory) { + return Result::Error; + } + UseNameForVar(memory->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForEventVar(Var* var) { + Event* event = module_->GetEvent(*var); + if (!event) { + return Result::Error; + } + UseNameForVar(event->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForDataSegmentVar(Var* var) { + DataSegment* data_segment = module_->GetDataSegment(*var); + if (!data_segment) { + return Result::Error; + } + UseNameForVar(data_segment->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForElemSegmentVar(Var* var) { + ElemSegment* elem_segment = module_->GetElemSegment(*var); + if (!elem_segment) { + return Result::Error; + } + UseNameForVar(elem_segment->name, var); + return Result::Ok; +} + +Result NameApplier::UseNameForParamAndLocalVar(Func* func, Var* var) { + Index local_index = func->GetLocalIndex(*var); + if (local_index >= func->GetNumParamsAndLocals()) { + return Result::Error; + } + + std::string name = param_and_local_index_to_name_[local_index]; + if (var->is_name()) { + assert(name == var->name()); + return Result::Ok; + } + + if (!name.empty()) { + var->set_name(name); + } + return Result::Ok; +} + +Result NameApplier::BeginBlockExpr(BlockExpr* expr) { + PushLabel(expr->block.label); + return Result::Ok; +} + +Result NameApplier::EndBlockExpr(BlockExpr* expr) { + PopLabel(); + return Result::Ok; +} + +Result NameApplier::BeginLoopExpr(LoopExpr* expr) { + PushLabel(expr->block.label); + return Result::Ok; +} + +Result NameApplier::EndLoopExpr(LoopExpr* expr) { + PopLabel(); + return Result::Ok; +} + +Result NameApplier::OnDataDropExpr(DataDropExpr* expr) { + CHECK_RESULT(UseNameForDataSegmentVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnMemoryInitExpr(MemoryInitExpr* expr) { + CHECK_RESULT(UseNameForDataSegmentVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnElemDropExpr(ElemDropExpr* expr) { + CHECK_RESULT(UseNameForElemSegmentVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnTableCopyExpr(TableCopyExpr* expr) { + CHECK_RESULT(UseNameForTableVar(&expr->dst_table)); + CHECK_RESULT(UseNameForTableVar(&expr->src_table)); + return Result::Ok; +} + +Result NameApplier::OnTableInitExpr(TableInitExpr* expr) { + CHECK_RESULT(UseNameForElemSegmentVar(&expr->segment_index)); + CHECK_RESULT(UseNameForTableVar(&expr->table_index)); + return Result::Ok; +} + +Result NameApplier::OnTableGetExpr(TableGetExpr* expr) { + CHECK_RESULT(UseNameForTableVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnTableSetExpr(TableSetExpr* expr) { + CHECK_RESULT(UseNameForTableVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnTableGrowExpr(TableGrowExpr* expr) { + CHECK_RESULT(UseNameForTableVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnTableSizeExpr(TableSizeExpr* expr) { + CHECK_RESULT(UseNameForTableVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnTableFillExpr(TableFillExpr* expr) { + CHECK_RESULT(UseNameForTableVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnBrExpr(BrExpr* expr) { + string_view label = FindLabelByVar(&expr->var); + UseNameForVar(label, &expr->var); + return Result::Ok; +} + +Result NameApplier::OnBrIfExpr(BrIfExpr* expr) { + string_view label = FindLabelByVar(&expr->var); + UseNameForVar(label, &expr->var); + return Result::Ok; +} + +Result NameApplier::OnBrTableExpr(BrTableExpr* expr) { + for (Var& target : expr->targets) { + string_view label = FindLabelByVar(&target); + UseNameForVar(label, &target); + } + + string_view label = FindLabelByVar(&expr->default_target); + UseNameForVar(label, &expr->default_target); + return Result::Ok; +} + +Result NameApplier::BeginTryExpr(TryExpr* expr) { + PushLabel(expr->block.label); + return Result::Ok; +} + +Result NameApplier::EndTryExpr(TryExpr*) { + PopLabel(); + return Result::Ok; +} + +Result NameApplier::OnCatchExpr(TryExpr*, Catch* expr) { + if (!expr->IsCatchAll()) { + CHECK_RESULT(UseNameForEventVar(&expr->var)); + } + return Result::Ok; +} + +Result NameApplier::OnDelegateExpr(TryExpr* expr) { + string_view label = FindLabelByVar(&expr->delegate_target); + UseNameForVar(label, &expr->delegate_target); + return Result::Ok; +} + +Result NameApplier::OnThrowExpr(ThrowExpr* expr) { + CHECK_RESULT(UseNameForEventVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnRethrowExpr(RethrowExpr* expr) { + string_view label = FindLabelByVar(&expr->var); + UseNameForVar(label, &expr->var); + return Result::Ok; +} + +Result NameApplier::OnCallExpr(CallExpr* expr) { + CHECK_RESULT(UseNameForFuncVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnRefFuncExpr(RefFuncExpr* expr) { + CHECK_RESULT(UseNameForFuncVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnCallIndirectExpr(CallIndirectExpr* expr) { + if (expr->decl.has_func_type) { + CHECK_RESULT(UseNameForFuncTypeVar(&expr->decl.type_var)); + } + CHECK_RESULT(UseNameForTableVar(&expr->table)); + return Result::Ok; +} + +Result NameApplier::OnReturnCallExpr(ReturnCallExpr* expr) { + CHECK_RESULT(UseNameForFuncVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) { + if (expr->decl.has_func_type) { + CHECK_RESULT(UseNameForFuncTypeVar(&expr->decl.type_var)); + } + CHECK_RESULT(UseNameForTableVar(&expr->table)); + return Result::Ok; +} + +Result NameApplier::OnGlobalGetExpr(GlobalGetExpr* expr) { + CHECK_RESULT(UseNameForGlobalVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnLocalGetExpr(LocalGetExpr* expr) { + CHECK_RESULT(UseNameForParamAndLocalVar(current_func_, &expr->var)); + return Result::Ok; +} + +Result NameApplier::BeginIfExpr(IfExpr* expr) { + PushLabel(expr->true_.label); + return Result::Ok; +} + +Result NameApplier::EndIfExpr(IfExpr* expr) { + PopLabel(); + return Result::Ok; +} + +Result NameApplier::OnGlobalSetExpr(GlobalSetExpr* expr) { + CHECK_RESULT(UseNameForGlobalVar(&expr->var)); + return Result::Ok; +} + +Result NameApplier::OnLocalSetExpr(LocalSetExpr* expr) { + CHECK_RESULT(UseNameForParamAndLocalVar(current_func_, &expr->var)); + return Result::Ok; +} + +Result NameApplier::OnLocalTeeExpr(LocalTeeExpr* expr) { + CHECK_RESULT(UseNameForParamAndLocalVar(current_func_, &expr->var)); + return Result::Ok; +} + +Result NameApplier::VisitFunc(Index func_index, Func* func) { + current_func_ = func; + if (func->decl.has_func_type) { + CHECK_RESULT(UseNameForFuncTypeVar(&func->decl.type_var)); + } + + MakeTypeBindingReverseMapping(func->GetNumParamsAndLocals(), func->bindings, + ¶m_and_local_index_to_name_); + + CHECK_RESULT(visitor_.VisitFunc(func)); + current_func_ = nullptr; + return Result::Ok; +} + +Result NameApplier::VisitGlobal(Global* global) { + CHECK_RESULT(visitor_.VisitExprList(global->init_expr)); + return Result::Ok; +} + +Result NameApplier::VisitEvent(Event* event) { + if (event->decl.has_func_type) { + CHECK_RESULT(UseNameForFuncTypeVar(&event->decl.type_var)); + } + return Result::Ok; +} + +Result NameApplier::VisitExport(Index export_index, Export* export_) { + if (export_->kind == ExternalKind::Func) { + UseNameForFuncVar(&export_->var); + } + return Result::Ok; +} + +Result NameApplier::VisitElemSegment(Index elem_segment_index, + ElemSegment* segment) { + CHECK_RESULT(UseNameForTableVar(&segment->table_var)); + CHECK_RESULT(visitor_.VisitExprList(segment->offset)); + for (ElemExpr& elem_expr : segment->elem_exprs) { + if (elem_expr.kind == ElemExprKind::RefFunc) { + CHECK_RESULT(UseNameForFuncVar(&elem_expr.var)); + } + } + return Result::Ok; +} + +Result NameApplier::VisitDataSegment(Index data_segment_index, + DataSegment* segment) { + CHECK_RESULT(UseNameForMemoryVar(&segment->memory_var)); + CHECK_RESULT(visitor_.VisitExprList(segment->offset)); + return Result::Ok; +} + +Result NameApplier::VisitStart(Var* start_var) { + CHECK_RESULT(UseNameForFuncVar(start_var)); + return Result::Ok; +} + +Result NameApplier::VisitModule(Module* module) { + module_ = module; + for (size_t i = 0; i < module->funcs.size(); ++i) + CHECK_RESULT(VisitFunc(i, module->funcs[i])); + for (size_t i = 0; i < module->globals.size(); ++i) + CHECK_RESULT(VisitGlobal(module->globals[i])); + for (size_t i = 0; i < module->events.size(); ++i) + CHECK_RESULT(VisitEvent(module->events[i])); + for (size_t i = 0; i < module->exports.size(); ++i) + CHECK_RESULT(VisitExport(i, module->exports[i])); + for (size_t i = 0; i < module->elem_segments.size(); ++i) + CHECK_RESULT(VisitElemSegment(i, module->elem_segments[i])); + for (size_t i = 0; i < module->data_segments.size(); ++i) + CHECK_RESULT(VisitDataSegment(i, module->data_segments[i])); + for (size_t i = 0; i < module->starts.size(); ++i) + CHECK_RESULT(VisitStart(module->starts[i])); + module_ = nullptr; + return Result::Ok; +} + +} // end anonymous namespace + +Result ApplyNames(Module* module) { + NameApplier applier; + return applier.VisitModule(module); +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.h new file mode 100644 index 0000000..1837c37 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.h @@ -0,0 +1,45 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_APPLY_NAMES_H_ +#define WABT_APPLY_NAMES_H_ + +#include "src/common.h" + +namespace wabt { + +struct Module; + +/* Use function, import, function type, parameter and local names in Vars + * that reference them. + * + * e.g. transform this: + * + * (func $foo ...) + * ... + * (call 0 ...) + * + * to this: + * + * (func $foo ...) + * ... + * (call $foo ...) + */ +Result ApplyNames(struct Module*); + +} // namespace wabt + +#endif /* WABT_APPLY_NAMES_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.cc new file mode 100644 index 0000000..cdda331 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.cc @@ -0,0 +1,1448 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary-reader-ir.h" + +#include +#include +#include +#include +#include +#include + +#include "src/binary-reader-nop.h" +#include "src/cast.h" +#include "src/common.h" +#include "src/ir.h" + +namespace wabt { + +namespace { + +struct LabelNode { + LabelNode(LabelType, ExprList* exprs, Expr* context = nullptr); + + LabelType label_type; + ExprList* exprs; + Expr* context; +}; + +LabelNode::LabelNode(LabelType label_type, ExprList* exprs, Expr* context) + : label_type(label_type), exprs(exprs), context(context) {} + +class BinaryReaderIR : public BinaryReaderNop { + public: + BinaryReaderIR(Module* out_module, + const char* filename, + Errors* errors); + + bool OnError(const Error&) override; + + Result OnTypeCount(Index count) override; + Result OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) override; + Result OnStructType(Index index, Index field_count, TypeMut* fields) override; + Result OnArrayType(Index index, TypeMut field) override; + + Result OnImportCount(Index count) override; + Result OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) override; + Result OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) override; + Result OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) override; + Result OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) override; + Result OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) override; + + Result OnFunctionCount(Index count) override; + Result OnFunction(Index index, Index sig_index) override; + + Result OnTableCount(Index count) override; + Result OnTable(Index index, + Type elem_type, + const Limits* elem_limits) override; + + Result OnMemoryCount(Index count) override; + Result OnMemory(Index index, const Limits* limits) override; + + Result OnGlobalCount(Index count) override; + Result BeginGlobal(Index index, Type type, bool mutable_) override; + Result BeginGlobalInitExpr(Index index) override; + Result EndGlobalInitExpr(Index index) override; + + Result OnExportCount(Index count) override; + Result OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) override; + + Result OnStartFunction(Index func_index) override; + + Result OnFunctionBodyCount(Index count) override; + Result BeginFunctionBody(Index index, Offset size) override; + Result OnLocalDecl(Index decl_index, Index count, Type type) override; + + Result OnAtomicLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicRmwExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicRmwCmpxchgExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicWaitExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicFenceExpr(uint32_t consistency_model) override; + Result OnAtomicNotifyExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnBinaryExpr(Opcode opcode) override; + Result OnBlockExpr(Type sig_type) override; + Result OnBrExpr(Index depth) override; + Result OnBrIfExpr(Index depth) override; + Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) override; + Result OnCallExpr(Index func_index) override; + Result OnCatchExpr(Index event_index) override; + Result OnCatchAllExpr() override; + Result OnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnReturnCallExpr(Index func_index) override; + Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnCompareExpr(Opcode opcode) override; + Result OnConvertExpr(Opcode opcode) override; + Result OnDelegateExpr(Index depth) override; + Result OnDropExpr() override; + Result OnElseExpr() override; + Result OnEndExpr() override; + Result OnF32ConstExpr(uint32_t value_bits) override; + Result OnF64ConstExpr(uint64_t value_bits) override; + Result OnV128ConstExpr(v128 value_bits) override; + Result OnGlobalGetExpr(Index global_index) override; + Result OnGlobalSetExpr(Index global_index) override; + Result OnI32ConstExpr(uint32_t value) override; + Result OnI64ConstExpr(uint64_t value) override; + Result OnIfExpr(Type sig_type) override; + Result OnLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnLocalGetExpr(Index local_index) override; + Result OnLocalSetExpr(Index local_index) override; + Result OnLocalTeeExpr(Index local_index) override; + Result OnLoopExpr(Type sig_type) override; + Result OnMemoryCopyExpr() override; + Result OnDataDropExpr(Index segment_index) override; + Result OnMemoryFillExpr() override; + Result OnMemoryGrowExpr() override; + Result OnMemoryInitExpr(Index segment_index) override; + Result OnMemorySizeExpr() override; + Result OnTableCopyExpr(Index dst_index, Index src_index) override; + Result OnElemDropExpr(Index segment_index) override; + Result OnTableInitExpr(Index segment_index, Index table_index) override; + Result OnTableGetExpr(Index table_index) override; + Result OnTableSetExpr(Index table_index) override; + Result OnTableGrowExpr(Index table_index) override; + Result OnTableSizeExpr(Index table_index) override; + Result OnTableFillExpr(Index table_index) override; + Result OnRefFuncExpr(Index func_index) override; + Result OnRefNullExpr(Type type) override; + Result OnRefIsNullExpr() override; + Result OnNopExpr() override; + Result OnRethrowExpr(Index depth) override; + Result OnReturnExpr() override; + Result OnSelectExpr(Index result_count, Type* result_types) override; + Result OnStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnThrowExpr(Index event_index) override; + Result OnTryExpr(Type sig_type) override; + Result OnUnaryExpr(Opcode opcode) override; + Result OnTernaryExpr(Opcode opcode) override; + Result OnUnreachableExpr() override; + Result OnUnwindExpr() override; + Result EndFunctionBody(Index index) override; + Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override; + Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override; + Result OnLoadSplatExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + + Result OnElemSegmentCount(Index count) override; + Result BeginElemSegment(Index index, + Index table_index, + uint8_t flags) override; + Result BeginElemSegmentInitExpr(Index index) override; + Result EndElemSegmentInitExpr(Index index) override; + Result OnElemSegmentElemType(Index index, Type elem_type) override; + Result OnElemSegmentElemExprCount(Index index, Index count) override; + Result OnElemSegmentElemExpr_RefNull(Index segment_index, Type type) override; + Result OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) override; + + Result OnDataSegmentCount(Index count) override; + Result BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) override; + Result BeginDataSegmentInitExpr(Index index) override; + Result EndDataSegmentInitExpr(Index index) override; + Result OnDataSegmentData(Index index, + const void* data, + Address size) override; + + Result OnModuleName(string_view module_name) override; + Result OnFunctionNamesCount(Index num_functions) override; + Result OnFunctionName(Index function_index, + string_view function_name) override; + Result OnLocalNameLocalCount(Index function_index, Index num_locals) override; + Result OnLocalName(Index function_index, + Index local_index, + string_view local_name) override; + + Result BeginEventSection(Offset size) override { return Result::Ok; } + Result OnEventCount(Index count) override { return Result::Ok; } + Result OnEventType(Index index, Index sig_index) override; + Result EndEventSection() override { return Result::Ok; } + + Result OnInitExprF32ConstExpr(Index index, uint32_t value) override; + Result OnInitExprF64ConstExpr(Index index, uint64_t value) override; + Result OnInitExprV128ConstExpr(Index index, v128 value) override; + Result OnInitExprGlobalGetExpr(Index index, Index global_index) override; + Result OnInitExprI32ConstExpr(Index index, uint32_t value) override; + Result OnInitExprI64ConstExpr(Index index, uint64_t value) override; + Result OnInitExprRefNull(Index index, Type type) override; + Result OnInitExprRefFunc(Index index, Index func_index) override; + + Result OnDataSymbol(Index index, uint32_t flags, string_view name, + Index segment, uint32_t offset, uint32_t size) override; + Result OnFunctionSymbol(Index index, uint32_t flags, string_view name, + Index func_index) override; + Result OnGlobalSymbol(Index index, uint32_t flags, string_view name, + Index global_index) override; + Result OnSectionSymbol(Index index, uint32_t flags, + Index section_index) override; + Result OnEventSymbol(Index index, uint32_t flags, string_view name, + Index event_index) override; + Result OnTableSymbol(Index index, uint32_t flags, string_view name, + Index table_index) override; + + private: + Location GetLocation() const; + void PrintError(const char* format, ...); + void PushLabel(LabelType label_type, + ExprList* first, + Expr* context = nullptr); + Result PopLabel(); + Result GetLabelAt(LabelNode** label, Index depth); + Result TopLabel(LabelNode** label); + Result TopLabelExpr(LabelNode** label, Expr** expr); + Result AppendExpr(std::unique_ptr expr); + Result AppendCatch(Catch&& catch_); + void SetFuncDeclaration(FuncDeclaration* decl, Var var); + void SetBlockDeclaration(BlockDeclaration* decl, Type sig_type); + + std::string GetUniqueName(BindingHash* bindings, + const std::string& original_name); + + Errors* errors_ = nullptr; + Module* module_ = nullptr; + + Func* current_func_ = nullptr; + std::vector label_stack_; + ExprList* current_init_expr_ = nullptr; + const char* filename_; +}; + +BinaryReaderIR::BinaryReaderIR(Module* out_module, + const char* filename, + Errors* errors) + : errors_(errors), module_(out_module), filename_(filename) {} + +Location BinaryReaderIR::GetLocation() const { + Location loc; + loc.filename = filename_; + loc.offset = state->offset; + return loc; +} + +void WABT_PRINTF_FORMAT(2, 3) BinaryReaderIR::PrintError(const char* format, + ...) { + WABT_SNPRINTF_ALLOCA(buffer, length, format); + errors_->emplace_back(ErrorLevel::Error, Location(kInvalidOffset), buffer); +} + +void BinaryReaderIR::PushLabel(LabelType label_type, + ExprList* first, + Expr* context) { + label_stack_.emplace_back(label_type, first, context); +} + +Result BinaryReaderIR::PopLabel() { + if (label_stack_.size() == 0) { + PrintError("popping empty label stack"); + return Result::Error; + } + + label_stack_.pop_back(); + return Result::Ok; +} + +Result BinaryReaderIR::GetLabelAt(LabelNode** label, Index depth) { + if (depth >= label_stack_.size()) { + PrintError("accessing stack depth: %" PRIindex " >= max: %" PRIzd, depth, + label_stack_.size()); + return Result::Error; + } + + *label = &label_stack_[label_stack_.size() - depth - 1]; + return Result::Ok; +} + +Result BinaryReaderIR::TopLabel(LabelNode** label) { + return GetLabelAt(label, 0); +} + +Result BinaryReaderIR::TopLabelExpr(LabelNode** label, Expr** expr) { + CHECK_RESULT(TopLabel(label)); + LabelNode* parent_label; + CHECK_RESULT(GetLabelAt(&parent_label, 1)); + *expr = &parent_label->exprs->back(); + return Result::Ok; +} + +Result BinaryReaderIR::AppendExpr(std::unique_ptr expr) { + expr->loc = GetLocation(); + LabelNode* label; + CHECK_RESULT(TopLabel(&label)); + label->exprs->push_back(std::move(expr)); + return Result::Ok; +} + +void BinaryReaderIR::SetFuncDeclaration(FuncDeclaration* decl, Var var) { + decl->has_func_type = true; + decl->type_var = var; + if (auto* func_type = module_->GetFuncType(var)) { + decl->sig = func_type->sig; + } +} + +void BinaryReaderIR::SetBlockDeclaration(BlockDeclaration* decl, + Type sig_type) { + if (sig_type.IsIndex()) { + Index type_index = sig_type.GetIndex(); + SetFuncDeclaration(decl, Var(type_index)); + } else { + decl->has_func_type = false; + decl->sig.param_types.clear(); + decl->sig.result_types = sig_type.GetInlineVector(); + } +} + +std::string BinaryReaderIR::GetUniqueName(BindingHash* bindings, + const std::string& orig_name) { + int counter = 1; + std::string unique_name = orig_name; + while (bindings->count(unique_name) != 0) { + unique_name = orig_name + "." + std::to_string(counter++); + } + return unique_name; +} + +bool BinaryReaderIR::OnError(const Error& error) { + errors_->push_back(error); + return true; +} + +Result BinaryReaderIR::OnTypeCount(Index count) { + WABT_TRY + module_->types.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) { + auto field = MakeUnique(GetLocation()); + auto func_type = MakeUnique(); + func_type->sig.param_types.assign(param_types, param_types + param_count); + func_type->sig.result_types.assign(result_types, result_types + result_count); + field->type = std::move(func_type); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnStructType(Index index, + Index field_count, + TypeMut* fields) { + auto field = MakeUnique(GetLocation()); + auto struct_type = MakeUnique(); + struct_type->fields.resize(field_count); + for (Index i = 0; i < field_count; ++i) { + struct_type->fields[i].type = fields[i].type; + struct_type->fields[i].mutable_ = fields[i].mutable_; + } + field->type = std::move(struct_type); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnArrayType(Index index, TypeMut type_mut) { + auto field = MakeUnique(GetLocation()); + auto array_type = MakeUnique(); + array_type->field.type = type_mut.type; + array_type->field.mutable_ = type_mut.mutable_; + field->type = std::move(array_type); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportCount(Index count) { + WABT_TRY + module_->imports.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) { + auto import = MakeUnique(); + import->module_name = module_name.to_string(); + import->field_name = field_name.to_string(); + SetFuncDeclaration(&import->func.decl, Var(sig_index, GetLocation())); + module_->AppendField( + MakeUnique(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) { + auto import = MakeUnique(); + import->module_name = module_name.to_string(); + import->field_name = field_name.to_string(); + import->table.elem_limits = *elem_limits; + import->table.elem_type = elem_type; + module_->AppendField( + MakeUnique(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) { + auto import = MakeUnique(); + import->module_name = module_name.to_string(); + import->field_name = field_name.to_string(); + import->memory.page_limits = *page_limits; + module_->AppendField( + MakeUnique(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) { + auto import = MakeUnique(); + import->module_name = module_name.to_string(); + import->field_name = field_name.to_string(); + import->global.type = type; + import->global.mutable_ = mutable_; + module_->AppendField( + MakeUnique(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) { + auto import = MakeUnique(); + import->module_name = module_name.to_string(); + import->field_name = field_name.to_string(); + SetFuncDeclaration(&import->event.decl, Var(sig_index, GetLocation())); + module_->AppendField( + MakeUnique(std::move(import), GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionCount(Index count) { + WABT_TRY + module_->funcs.reserve(module_->num_func_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnFunction(Index index, Index sig_index) { + auto field = MakeUnique(GetLocation()); + Func& func = field->func; + SetFuncDeclaration(&func.decl, Var(sig_index, GetLocation())); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnTableCount(Index count) { + WABT_TRY + module_->tables.reserve(module_->num_table_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnTable(Index index, + Type elem_type, + const Limits* elem_limits) { + auto field = MakeUnique(GetLocation()); + Table& table = field->table; + table.elem_limits = *elem_limits; + table.elem_type = elem_type; + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnMemoryCount(Index count) { + WABT_TRY + module_->memories.reserve(module_->num_memory_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnMemory(Index index, const Limits* page_limits) { + auto field = MakeUnique(GetLocation()); + Memory& memory = field->memory; + memory.page_limits = *page_limits; + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnGlobalCount(Index count) { + WABT_TRY + module_->globals.reserve(module_->num_global_imports + count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::BeginGlobal(Index index, Type type, bool mutable_) { + auto field = MakeUnique(GetLocation()); + Global& global = field->global; + global.type = type; + global.mutable_ = mutable_; + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::BeginGlobalInitExpr(Index index) { + assert(index == module_->globals.size() - 1); + Global* global = module_->globals[index]; + current_init_expr_ = &global->init_expr; + return Result::Ok; +} + +Result BinaryReaderIR::EndGlobalInitExpr(Index index) { + current_init_expr_ = nullptr; + return Result::Ok; +} + +Result BinaryReaderIR::OnExportCount(Index count) { + WABT_TRY + module_->exports.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) { + auto field = MakeUnique(GetLocation()); + Export& export_ = field->export_; + export_.name = name.to_string(); + export_.var = Var(item_index, GetLocation()); + export_.kind = kind; + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnStartFunction(Index func_index) { + Var start(func_index, GetLocation()); + module_->AppendField(MakeUnique(start, GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionBodyCount(Index count) { + assert(module_->num_func_imports + count == module_->funcs.size()); + return Result::Ok; +} + +Result BinaryReaderIR::BeginFunctionBody(Index index, Offset size) { + current_func_ = module_->funcs[index]; + PushLabel(LabelType::Func, ¤t_func_->exprs); + return Result::Ok; +} + +Result BinaryReaderIR::OnLocalDecl(Index decl_index, Index count, Type type) { + current_func_->local_types.AppendDecl(type, count); + return Result::Ok; +} + +Result BinaryReaderIR::OnAtomicLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr( + MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr( + MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicRmwExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr( + MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicRmwCmpxchgExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr( + MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicWaitExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr( + MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnAtomicFenceExpr(uint32_t consistency_model) { + return AppendExpr(MakeUnique(consistency_model)); +} + +Result BinaryReaderIR::OnAtomicNotifyExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr( + MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnBinaryExpr(Opcode opcode) { + return AppendExpr(MakeUnique(opcode)); +} + +Result BinaryReaderIR::OnBlockExpr(Type sig_type) { + auto expr = MakeUnique(); + SetBlockDeclaration(&expr->block.decl, sig_type); + ExprList* expr_list = &expr->block.exprs; + CHECK_RESULT(AppendExpr(std::move(expr))); + PushLabel(LabelType::Block, expr_list); + return Result::Ok; +} + +Result BinaryReaderIR::OnBrExpr(Index depth) { + return AppendExpr(MakeUnique(Var(depth))); +} + +Result BinaryReaderIR::OnBrIfExpr(Index depth) { + return AppendExpr(MakeUnique(Var(depth))); +} + +Result BinaryReaderIR::OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) { + auto expr = MakeUnique(); + expr->default_target = Var(default_target_depth); + expr->targets.resize(num_targets); + for (Index i = 0; i < num_targets; ++i) { + expr->targets[i] = Var(target_depths[i]); + } + return AppendExpr(std::move(expr)); +} + +Result BinaryReaderIR::OnCallExpr(Index func_index) { + return AppendExpr(MakeUnique(Var(func_index))); +} + +Result BinaryReaderIR::OnCallIndirectExpr(Index sig_index, Index table_index) { + auto expr = MakeUnique(); + SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation())); + expr->table = Var(table_index); + return AppendExpr(std::move(expr)); +} + +Result BinaryReaderIR::OnReturnCallExpr(Index func_index) { + return AppendExpr(MakeUnique(Var(func_index))); +} + +Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index, Index table_index) { + auto expr = MakeUnique(); + SetFuncDeclaration(&expr->decl, Var(sig_index, GetLocation())); + expr->table = Var(table_index); + return AppendExpr(std::move(expr)); +} + +Result BinaryReaderIR::OnCompareExpr(Opcode opcode) { + return AppendExpr(MakeUnique(opcode)); +} + +Result BinaryReaderIR::OnConvertExpr(Opcode opcode) { + return AppendExpr(MakeUnique(opcode)); +} + +Result BinaryReaderIR::OnDropExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnElseExpr() { + LabelNode* label; + Expr* expr; + CHECK_RESULT(TopLabelExpr(&label, &expr)); + + if (label->label_type == LabelType::If) { + auto* if_expr = cast(expr); + if_expr->true_.end_loc = GetLocation(); + label->exprs = &if_expr->false_; + label->label_type = LabelType::Else; + } else { + PrintError("else expression without matching if"); + return Result::Error; + } + + return Result::Ok; +} + +Result BinaryReaderIR::OnEndExpr() { + LabelNode* label; + Expr* expr; + CHECK_RESULT(TopLabelExpr(&label, &expr)); + switch (label->label_type) { + case LabelType::Block: + cast(expr)->block.end_loc = GetLocation(); + break; + case LabelType::Loop: + cast(expr)->block.end_loc = GetLocation(); + break; + case LabelType::If: + cast(expr)->true_.end_loc = GetLocation(); + break; + case LabelType::Else: + cast(expr)->false_end_loc = GetLocation(); + break; + case LabelType::Try: + cast(expr)->block.end_loc = GetLocation(); + break; + + case LabelType::Func: + case LabelType::Catch: + case LabelType::Unwind: + break; + } + + return PopLabel(); +} + +Result BinaryReaderIR::OnF32ConstExpr(uint32_t value_bits) { + return AppendExpr( + MakeUnique(Const::F32(value_bits, GetLocation()))); +} + +Result BinaryReaderIR::OnF64ConstExpr(uint64_t value_bits) { + return AppendExpr( + MakeUnique(Const::F64(value_bits, GetLocation()))); +} + +Result BinaryReaderIR::OnV128ConstExpr(v128 value_bits) { + return AppendExpr( + MakeUnique(Const::V128(value_bits, GetLocation()))); +} + +Result BinaryReaderIR::OnGlobalGetExpr(Index global_index) { + return AppendExpr( + MakeUnique(Var(global_index, GetLocation()))); +} + +Result BinaryReaderIR::OnLocalGetExpr(Index local_index) { + return AppendExpr(MakeUnique(Var(local_index, GetLocation()))); +} + +Result BinaryReaderIR::OnI32ConstExpr(uint32_t value) { + return AppendExpr(MakeUnique(Const::I32(value, GetLocation()))); +} + +Result BinaryReaderIR::OnI64ConstExpr(uint64_t value) { + return AppendExpr(MakeUnique(Const::I64(value, GetLocation()))); +} + +Result BinaryReaderIR::OnIfExpr(Type sig_type) { + auto expr = MakeUnique(); + SetBlockDeclaration(&expr->true_.decl, sig_type); + ExprList* expr_list = &expr->true_.exprs; + CHECK_RESULT(AppendExpr(std::move(expr))); + PushLabel(LabelType::If, expr_list); + return Result::Ok; +} + +Result BinaryReaderIR::OnLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr(MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnLoopExpr(Type sig_type) { + auto expr = MakeUnique(); + SetBlockDeclaration(&expr->block.decl, sig_type); + ExprList* expr_list = &expr->block.exprs; + CHECK_RESULT(AppendExpr(std::move(expr))); + PushLabel(LabelType::Loop, expr_list); + return Result::Ok; +} + +Result BinaryReaderIR::OnMemoryCopyExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnDataDropExpr(Index segment) { + return AppendExpr(MakeUnique(Var(segment))); +} + +Result BinaryReaderIR::OnMemoryFillExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnMemoryGrowExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnMemoryInitExpr(Index segment) { + return AppendExpr(MakeUnique(Var(segment))); +} + +Result BinaryReaderIR::OnMemorySizeExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnTableCopyExpr(Index dst_index, Index src_index) { + return AppendExpr(MakeUnique(Var(dst_index), Var(src_index))); +} + +Result BinaryReaderIR::OnElemDropExpr(Index segment) { + return AppendExpr(MakeUnique(Var(segment))); +} + +Result BinaryReaderIR::OnTableInitExpr(Index segment, Index table_index) { + return AppendExpr(MakeUnique(Var(segment), Var(table_index))); +} + +Result BinaryReaderIR::OnTableGetExpr(Index table_index) { + return AppendExpr(MakeUnique(Var(table_index))); +} + +Result BinaryReaderIR::OnTableSetExpr(Index table_index) { + return AppendExpr(MakeUnique(Var(table_index))); +} + +Result BinaryReaderIR::OnTableGrowExpr(Index table_index) { + return AppendExpr(MakeUnique(Var(table_index))); +} + +Result BinaryReaderIR::OnTableSizeExpr(Index table_index) { + return AppendExpr(MakeUnique(Var(table_index))); +} + +Result BinaryReaderIR::OnTableFillExpr(Index table_index) { + return AppendExpr(MakeUnique(Var(table_index))); +} + +Result BinaryReaderIR::OnRefFuncExpr(Index func_index) { + return AppendExpr(MakeUnique(Var(func_index))); +} + +Result BinaryReaderIR::OnRefNullExpr(Type type) { + return AppendExpr(MakeUnique(type)); +} + +Result BinaryReaderIR::OnRefIsNullExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnNopExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnRethrowExpr(Index depth) { + return AppendExpr(MakeUnique(Var(depth, GetLocation()))); +} + +Result BinaryReaderIR::OnReturnExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::OnSelectExpr(Index result_count, Type* result_types) { + TypeVector results; + results.assign(result_types, result_types + result_count); + return AppendExpr(MakeUnique(results)); +} + +Result BinaryReaderIR::OnGlobalSetExpr(Index global_index) { + return AppendExpr( + MakeUnique(Var(global_index, GetLocation()))); +} + +Result BinaryReaderIR::OnLocalSetExpr(Index local_index) { + return AppendExpr(MakeUnique(Var(local_index, GetLocation()))); +} + +Result BinaryReaderIR::OnStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr(MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnThrowExpr(Index event_index) { + return AppendExpr(MakeUnique(Var(event_index, GetLocation()))); +} + +Result BinaryReaderIR::OnLocalTeeExpr(Index local_index) { + return AppendExpr(MakeUnique(Var(local_index, GetLocation()))); +} + +Result BinaryReaderIR::OnTryExpr(Type sig_type) { + auto expr_ptr = MakeUnique(); + // Save expr so it can be used below, after expr_ptr has been moved. + TryExpr* expr = expr_ptr.get(); + ExprList* expr_list = &expr->block.exprs; + SetBlockDeclaration(&expr->block.decl, sig_type); + CHECK_RESULT(AppendExpr(std::move(expr_ptr))); + PushLabel(LabelType::Try, expr_list, expr); + return Result::Ok; +} + +Result BinaryReaderIR::AppendCatch(Catch&& catch_) { + LabelNode* label = nullptr; + CHECK_RESULT(TopLabel(&label)); + + if (label->label_type != LabelType::Try) { + PrintError("catch not inside try block"); + return Result::Error; + } + + auto* try_ = cast(label->context); + + if (catch_.IsCatchAll() && !try_->catches.empty() && try_->catches.back().IsCatchAll()) { + PrintError("only one catch_all allowed in try block"); + return Result::Error; + } + + if (try_->kind == TryKind::Invalid) { + try_->kind = TryKind::Catch; + } else if (try_->kind != TryKind::Catch) { + PrintError("catch not allowed in try-unwind or try-delegate"); + return Result::Error; + } + + try_->catches.push_back(std::move(catch_)); + label->exprs = &try_->catches.back().exprs; + return Result::Ok; +} + +Result BinaryReaderIR::OnCatchExpr(Index except_index) { + return AppendCatch(Catch(Var(except_index, GetLocation()))); +} + +Result BinaryReaderIR::OnCatchAllExpr() { + return AppendCatch(Catch(GetLocation())); +} + +Result BinaryReaderIR::OnUnwindExpr() { + LabelNode* label = nullptr; + CHECK_RESULT(TopLabel(&label)); + + if (label->label_type != LabelType::Try) { + PrintError("unwind not inside try block"); + return Result::Error; + } + + auto* try_ = cast(label->context); + + if (try_->kind == TryKind::Invalid) { + try_->kind = TryKind::Unwind; + } else if (try_->kind != TryKind::Unwind) { + PrintError("unwind not allowed in try-catch or try-delegate"); + return Result::Error; + } + + label->exprs = &try_->unwind; + return Result::Ok; +} + +Result BinaryReaderIR::OnDelegateExpr(Index depth) { + LabelNode* label = nullptr; + CHECK_RESULT(TopLabel(&label)); + + if (label->label_type != LabelType::Try) { + PrintError("delegate not inside try block"); + return Result::Error; + } + + auto* try_ = cast(label->context); + + if (try_->kind == TryKind::Invalid) { + try_->kind = TryKind::Delegate; + } else if (try_->kind != TryKind::Delegate) { + PrintError("delegate not allowed in try-catch or try-unwind"); + return Result::Error; + } + + try_->delegate_target = Var(depth, GetLocation()); + + PopLabel(); + return Result::Ok; +} + +Result BinaryReaderIR::OnUnaryExpr(Opcode opcode) { + return AppendExpr(MakeUnique(opcode)); +} + +Result BinaryReaderIR::OnTernaryExpr(Opcode opcode) { + return AppendExpr(MakeUnique(opcode)); +} + +Result BinaryReaderIR::OnUnreachableExpr() { + return AppendExpr(MakeUnique()); +} + +Result BinaryReaderIR::EndFunctionBody(Index index) { + CHECK_RESULT(PopLabel()); + current_func_ = nullptr; + return Result::Ok; +} + +Result BinaryReaderIR::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) { + return AppendExpr(MakeUnique(opcode, value)); +} + +Result BinaryReaderIR::OnSimdShuffleOpExpr(Opcode opcode, v128 value) { + return AppendExpr(MakeUnique(opcode, value)); +} + +Result BinaryReaderIR::OnLoadSplatExpr(Opcode opcode, + Address alignment_log2, + Address offset) { + return AppendExpr( + MakeUnique(opcode, 1 << alignment_log2, offset)); +} + +Result BinaryReaderIR::OnElemSegmentCount(Index count) { + WABT_TRY + module_->elem_segments.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::BeginElemSegment(Index index, + Index table_index, + uint8_t flags) { + auto field = MakeUnique(GetLocation()); + ElemSegment& elem_segment = field->elem_segment; + elem_segment.table_var = Var(table_index, GetLocation()); + if ((flags & SegDeclared) == SegDeclared) { + elem_segment.kind = SegmentKind::Declared; + } else if ((flags & SegPassive) == SegPassive) { + elem_segment.kind = SegmentKind::Passive; + } else { + elem_segment.kind = SegmentKind::Active; + } + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::BeginElemSegmentInitExpr(Index index) { + assert(index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[index]; + current_init_expr_ = &segment->offset; + return Result::Ok; +} + +Result BinaryReaderIR::EndElemSegmentInitExpr(Index index) { + current_init_expr_ = nullptr; + return Result::Ok; +} + +Result BinaryReaderIR::OnElemSegmentElemType(Index index, Type elem_type) { + assert(index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[index]; + segment->elem_type = elem_type; + return Result::Ok; +} + +Result BinaryReaderIR::OnElemSegmentElemExprCount(Index index, Index count) { + assert(index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[index]; + WABT_TRY + segment->elem_exprs.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::OnElemSegmentElemExpr_RefNull(Index segment_index, + Type type) { + assert(segment_index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[segment_index]; + segment->elem_exprs.emplace_back(type); + return Result::Ok; +} + +Result BinaryReaderIR::OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) { + assert(segment_index == module_->elem_segments.size() - 1); + ElemSegment* segment = module_->elem_segments[segment_index]; + segment->elem_exprs.emplace_back(Var(func_index, GetLocation())); + return Result::Ok; +} + +Result BinaryReaderIR::OnDataSegmentCount(Index count) { + WABT_TRY + module_->data_segments.reserve(count); + WABT_CATCH_BAD_ALLOC + return Result::Ok; +} + +Result BinaryReaderIR::BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) { + auto field = MakeUnique(GetLocation()); + DataSegment& data_segment = field->data_segment; + data_segment.memory_var = Var(memory_index, GetLocation()); + if ((flags & SegPassive) == SegPassive) { + data_segment.kind = SegmentKind::Passive; + } else { + data_segment.kind = SegmentKind::Active; + } + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::BeginDataSegmentInitExpr(Index index) { + assert(index == module_->data_segments.size() - 1); + DataSegment* segment = module_->data_segments[index]; + current_init_expr_ = &segment->offset; + return Result::Ok; +} + +Result BinaryReaderIR::EndDataSegmentInitExpr(Index index) { + current_init_expr_ = nullptr; + return Result::Ok; +} + +Result BinaryReaderIR::OnDataSegmentData(Index index, + const void* data, + Address size) { + assert(index == module_->data_segments.size() - 1); + DataSegment* segment = module_->data_segments[index]; + segment->data.resize(size); + if (size > 0) { + memcpy(segment->data.data(), data, size); + } + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionNamesCount(Index count) { + if (count > module_->funcs.size()) { + PrintError("expected function name count (%" PRIindex + ") <= function count (%" PRIzd ")", + count, module_->funcs.size()); + return Result::Error; + } + return Result::Ok; +} + +static std::string MakeDollarName(string_view name) { + return std::string("$") + name.to_string(); +} + +Result BinaryReaderIR::OnModuleName(string_view name) { + if (name.empty()) { + return Result::Ok; + } + + module_->name = MakeDollarName(name); + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionName(Index index, string_view name) { + if (name.empty()) { + return Result::Ok; + } + + Func* func = module_->funcs[index]; + std::string dollar_name = + GetUniqueName(&module_->func_bindings, MakeDollarName(name)); + func->name = dollar_name; + module_->func_bindings.emplace(dollar_name, Binding(index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnLocalNameLocalCount(Index index, Index count) { + assert(index < module_->funcs.size()); + Func* func = module_->funcs[index]; + Index num_params_and_locals = func->GetNumParamsAndLocals(); + if (count > num_params_and_locals) { + PrintError("expected local name count (%" PRIindex + ") <= local count (%" PRIindex ")", + count, num_params_and_locals); + return Result::Error; + } + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprF32ConstExpr(Index index, uint32_t value) { + Location loc = GetLocation(); + current_init_expr_->push_back( + MakeUnique(Const::F32(value, loc), loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprF64ConstExpr(Index index, uint64_t value) { + Location loc = GetLocation(); + current_init_expr_->push_back( + MakeUnique(Const::F64(value, loc), loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprV128ConstExpr(Index index, v128 value) { + Location loc = GetLocation(); + current_init_expr_->push_back( + MakeUnique(Const::V128(value, loc), loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprGlobalGetExpr(Index index, + Index global_index) { + Location loc = GetLocation(); + current_init_expr_->push_back( + MakeUnique(Var(global_index, loc), loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprI32ConstExpr(Index index, uint32_t value) { + Location loc = GetLocation(); + current_init_expr_->push_back( + MakeUnique(Const::I32(value, loc), loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprI64ConstExpr(Index index, uint64_t value) { + Location loc = GetLocation(); + current_init_expr_->push_back( + MakeUnique(Const::I64(value, loc), loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprRefNull(Index index, Type type) { + Location loc = GetLocation(); + current_init_expr_->push_back(MakeUnique(type, loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnInitExprRefFunc(Index index, Index func_index) { + Location loc = GetLocation(); + current_init_expr_->push_back( + MakeUnique(Var(func_index, loc), loc)); + return Result::Ok; +} + +Result BinaryReaderIR::OnLocalName(Index func_index, + Index local_index, + string_view name) { + if (name.empty()) { + return Result::Ok; + } + + Func* func = module_->funcs[func_index]; + func->bindings.emplace(GetUniqueName(&func->bindings, MakeDollarName(name)), + Binding(local_index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnEventType(Index index, Index sig_index) { + auto field = MakeUnique(GetLocation()); + Event& event = field->event; + SetFuncDeclaration(&event.decl, Var(sig_index, GetLocation())); + module_->AppendField(std::move(field)); + return Result::Ok; +} + +Result BinaryReaderIR::OnDataSymbol(Index index, uint32_t flags, + string_view name, Index segment, + uint32_t offset, uint32_t size) { + if (name.empty()) { + return Result::Ok; + } + if (flags & WABT_SYMBOL_FLAG_UNDEFINED) { + // Refers to data in another file, `segment` not valid. + return Result::Ok; + } + if (offset) { + // If it is pointing into the data segment, then it's not really naming + // the whole segment. + return Result::Ok; + } + if (segment >= module_->data_segments.size()) { + PrintError("invalid data segment index: %" PRIindex, segment); + return Result::Error; + } + DataSegment* seg = module_->data_segments[segment]; + std::string dollar_name = + GetUniqueName(&module_->data_segment_bindings, MakeDollarName(name)); + seg->name = dollar_name; + module_->data_segment_bindings.emplace(dollar_name, Binding(segment)); + return Result::Ok; +} + +Result BinaryReaderIR::OnFunctionSymbol(Index index, uint32_t flags, + string_view name, Index func_index) { + if (name.empty()) { + return Result::Ok; + } + if (func_index >= module_->funcs.size()) { + PrintError("invalid function index: %" PRIindex, func_index); + return Result::Error; + } + Func* func = module_->funcs[func_index]; + if (!func->name.empty()) { + // The name section has already named this function. + return Result::Ok; + } + std::string dollar_name = + GetUniqueName(&module_->func_bindings, MakeDollarName(name)); + func->name = dollar_name; + module_->func_bindings.emplace(dollar_name, Binding(func_index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnGlobalSymbol(Index index, uint32_t flags, + string_view name, Index global_index) { + if (name.empty()) { + return Result::Ok; + } + if (global_index >= module_->globals.size()) { + PrintError("invalid global index: %" PRIindex, global_index); + return Result::Error; + } + Global* glob = module_->globals[global_index]; + std::string dollar_name = + GetUniqueName(&module_->global_bindings, MakeDollarName(name)); + glob->name = dollar_name; + module_->global_bindings.emplace(dollar_name, Binding(global_index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnSectionSymbol(Index index, uint32_t flags, + Index section_index) { + return Result::Ok; +} + +Result BinaryReaderIR::OnEventSymbol(Index index, uint32_t flags, + string_view name, Index event_index) { + if (name.empty()) { + return Result::Ok; + } + if (event_index >= module_->events.size()) { + PrintError("invalid event index: %" PRIindex, event_index); + return Result::Error; + } + Event* event = module_->events[event_index]; + std::string dollar_name = + GetUniqueName(&module_->event_bindings, MakeDollarName(name)); + event->name = dollar_name; + module_->event_bindings.emplace(dollar_name, Binding(event_index)); + return Result::Ok; +} + +Result BinaryReaderIR::OnTableSymbol(Index index, uint32_t flags, + string_view name, Index table_index) { + if (name.empty()) { + return Result::Ok; + } + if (table_index >= module_->tables.size()) { + PrintError("invalid table index: %" PRIindex, table_index); + return Result::Error; + } + Table* table = module_->tables[table_index]; + std::string dollar_name = + GetUniqueName(&module_->table_bindings, MakeDollarName(name)); + table->name = dollar_name; + module_->table_bindings.emplace(dollar_name, Binding(table_index)); + return Result::Ok; +} + +} // end anonymous namespace + +Result ReadBinaryIr(const char* filename, + const void* data, + size_t size, + const ReadBinaryOptions& options, + Errors* errors, + Module* out_module) { + BinaryReaderIR reader(out_module, filename, errors); + return ReadBinary(data, size, &reader, options); +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.h new file mode 100644 index 0000000..18c1558 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.h @@ -0,0 +1,37 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_READER_IR_H_ +#define WABT_BINARY_READER_IR_H_ + +#include "src/common.h" +#include "src/error.h" + +namespace wabt { + +struct Module; +struct ReadBinaryOptions; + +Result ReadBinaryIr(const char* filename, + const void* data, + size_t size, + const ReadBinaryOptions& options, + Errors*, + Module* out_module); + +} // namespace wabt + +#endif /* WABT_BINARY_READER_IR_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.cc new file mode 100644 index 0000000..5cebbe9 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.cc @@ -0,0 +1,949 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary-reader-logging.h" + +#include + +#include "src/stream.h" + +namespace wabt { + +#define INDENT_SIZE 2 + +#define LOGF_NOINDENT(...) stream_->Writef(__VA_ARGS__) + +#define LOGF(...) \ + do { \ + WriteIndent(); \ + LOGF_NOINDENT(__VA_ARGS__); \ + } while (0) + +namespace { + +void SPrintLimits(char* dst, size_t size, const Limits* limits) { + int result; + if (limits->has_max) { + result = wabt_snprintf(dst, size, "initial: %" PRIu64 ", max: %" PRIu64, + limits->initial, limits->max); + } else { + result = wabt_snprintf(dst, size, "initial: %" PRIu64, limits->initial); + } + WABT_USE(result); + assert(static_cast(result) < size); +} + +} // end anonymous namespace + +BinaryReaderLogging::BinaryReaderLogging(Stream* stream, + BinaryReaderDelegate* forward) + : stream_(stream), reader_(forward), indent_(0) {} + +void BinaryReaderLogging::Indent() { + indent_ += INDENT_SIZE; +} + +void BinaryReaderLogging::Dedent() { + indent_ -= INDENT_SIZE; + assert(indent_ >= 0); +} + +void BinaryReaderLogging::WriteIndent() { + static char s_indent[] = + " " + " "; + static const size_t s_indent_len = sizeof(s_indent) - 1; + size_t i = indent_; + while (i > s_indent_len) { + stream_->WriteData(s_indent, s_indent_len); + i -= s_indent_len; + } + if (i > 0) { + stream_->WriteData(s_indent, indent_); + } +} + +void BinaryReaderLogging::LogType(Type type) { + if (type.IsIndex()) { + LOGF_NOINDENT("typeidx[%d]", type.GetIndex()); + } else { + LOGF_NOINDENT("%s", type.GetName()); + } +} + +void BinaryReaderLogging::LogTypes(Index type_count, Type* types) { + LOGF_NOINDENT("["); + for (Index i = 0; i < type_count; ++i) { + LogType(types[i]); + if (i != type_count - 1) { + LOGF_NOINDENT(", "); + } + } + LOGF_NOINDENT("]"); +} + +void BinaryReaderLogging::LogTypes(TypeVector& types) { + LogTypes(types.size(), types.data()); +} + +void BinaryReaderLogging::LogField(TypeMut field) { + if (field.mutable_) { + LOGF_NOINDENT("(mut "); + } + LogType(field.type); + if (field.mutable_) { + LOGF_NOINDENT(")"); + } +} + +bool BinaryReaderLogging::OnError(const Error& error) { + return reader_->OnError(error); +} + +void BinaryReaderLogging::OnSetState(const State* s) { + BinaryReaderDelegate::OnSetState(s); + reader_->OnSetState(s); +} + +Result BinaryReaderLogging::BeginModule(uint32_t version) { + LOGF("BeginModule(version: %u)\n", version); + Indent(); + return reader_->BeginModule(version); +} + +Result BinaryReaderLogging::BeginSection(Index section_index, + BinarySection section_type, + Offset size) { + return reader_->BeginSection(section_index, section_type, size); +} + +Result BinaryReaderLogging::BeginCustomSection(Index section_index, + Offset size, + string_view section_name) { + LOGF("BeginCustomSection('" PRIstringview "', size: %" PRIzd ")\n", + WABT_PRINTF_STRING_VIEW_ARG(section_name), size); + Indent(); + return reader_->BeginCustomSection(section_index, size, section_name); +} + +Result BinaryReaderLogging::OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) { + LOGF("OnFuncType(index: %" PRIindex ", params: ", index); + LogTypes(param_count, param_types); + LOGF_NOINDENT(", results: "); + LogTypes(result_count, result_types); + LOGF_NOINDENT(")\n"); + return reader_->OnFuncType(index, param_count, param_types, result_count, + result_types); +} + +Result BinaryReaderLogging::OnStructType(Index index, + Index field_count, + TypeMut* fields) { + LOGF("OnStructType(index: %" PRIindex ", fields: ", index); + LOGF_NOINDENT("["); + for (Index i = 0; i < field_count; ++i) { + LogField(fields[i]); + if (i != field_count - 1) { + LOGF_NOINDENT(", "); + } + } + LOGF_NOINDENT("])\n"); + return reader_->OnStructType(index, field_count, fields); +} + +Result BinaryReaderLogging::OnArrayType(Index index, TypeMut field) { + LOGF("OnArrayType(index: %" PRIindex ", field: ", index); + LogField(field); + LOGF_NOINDENT(")\n"); + return reader_->OnArrayType(index, field); +} + +Result BinaryReaderLogging::OnImport(Index index, + ExternalKind kind, + string_view module_name, + string_view field_name) { + LOGF("OnImport(index: %" PRIindex ", kind: %s, module: \"" PRIstringview + "\", field: \"" PRIstringview "\")\n", + index, GetKindName(kind), WABT_PRINTF_STRING_VIEW_ARG(module_name), + WABT_PRINTF_STRING_VIEW_ARG(field_name)); + return reader_->OnImport(index, kind, module_name, field_name); +} + +Result BinaryReaderLogging::OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) { + LOGF("OnImportFunc(import_index: %" PRIindex ", func_index: %" PRIindex + ", sig_index: %" PRIindex ")\n", + import_index, func_index, sig_index); + return reader_->OnImportFunc(import_index, module_name, field_name, + func_index, sig_index); +} + +Result BinaryReaderLogging::OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) { + char buf[100]; + SPrintLimits(buf, sizeof(buf), elem_limits); + LOGF("OnImportTable(import_index: %" PRIindex ", table_index: %" PRIindex + ", elem_type: %s, %s)\n", + import_index, table_index, elem_type.GetName(), buf); + return reader_->OnImportTable(import_index, module_name, field_name, + table_index, elem_type, elem_limits); +} + +Result BinaryReaderLogging::OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) { + char buf[100]; + SPrintLimits(buf, sizeof(buf), page_limits); + LOGF("OnImportMemory(import_index: %" PRIindex ", memory_index: %" PRIindex + ", %s)\n", + import_index, memory_index, buf); + return reader_->OnImportMemory(import_index, module_name, field_name, + memory_index, page_limits); +} + +Result BinaryReaderLogging::OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) { + LOGF("OnImportGlobal(import_index: %" PRIindex ", global_index: %" PRIindex + ", type: %s, mutable: " + "%s)\n", + import_index, global_index, type.GetName(), mutable_ ? "true" : "false"); + return reader_->OnImportGlobal(import_index, module_name, field_name, + global_index, type, mutable_); +} + +Result BinaryReaderLogging::OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) { + LOGF("OnImportEvent(import_index: %" PRIindex ", event_index: %" PRIindex + ", sig_index: %" PRIindex ")\n", + import_index, event_index, sig_index); + return reader_->OnImportEvent(import_index, module_name, field_name, + event_index, sig_index); +} + +Result BinaryReaderLogging::OnTable(Index index, + Type elem_type, + const Limits* elem_limits) { + char buf[100]; + SPrintLimits(buf, sizeof(buf), elem_limits); + LOGF("OnTable(index: %" PRIindex ", elem_type: %s, %s)\n", index, + elem_type.GetName(), buf); + return reader_->OnTable(index, elem_type, elem_limits); +} + +Result BinaryReaderLogging::OnMemory(Index index, const Limits* page_limits) { + char buf[100]; + SPrintLimits(buf, sizeof(buf), page_limits); + LOGF("OnMemory(index: %" PRIindex ", %s)\n", index, buf); + return reader_->OnMemory(index, page_limits); +} + +Result BinaryReaderLogging::BeginGlobal(Index index, Type type, bool mutable_) { + LOGF("BeginGlobal(index: %" PRIindex ", type: %s, mutable: %s)\n", index, + type.GetName(), mutable_ ? "true" : "false"); + return reader_->BeginGlobal(index, type, mutable_); +} + +Result BinaryReaderLogging::OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) { + LOGF("OnExport(index: %" PRIindex ", kind: %s, item_index: %" PRIindex + ", name: \"" PRIstringview "\")\n", + index, GetKindName(kind), item_index, WABT_PRINTF_STRING_VIEW_ARG(name)); + return reader_->OnExport(index, kind, item_index, name); +} + +Result BinaryReaderLogging::BeginFunctionBody(Index value, Offset size) { + LOGF("BeginFunctionBody(%" PRIindex ", size:%" PRIzd ")\n", value, size); + return reader_->BeginFunctionBody(value, size); +} + +Result BinaryReaderLogging::OnLocalDecl(Index decl_index, + Index count, + Type type) { + LOGF("OnLocalDecl(index: %" PRIindex ", count: %" PRIindex ", type: %s)\n", + decl_index, count, type.GetName()); + return reader_->OnLocalDecl(decl_index, count, type); +} + +Result BinaryReaderLogging::OnBlockExpr(Type sig_type) { + LOGF("OnBlockExpr(sig: "); + LogType(sig_type); + LOGF_NOINDENT(")\n"); + return reader_->OnBlockExpr(sig_type); +} + +Result BinaryReaderLogging::OnBrExpr(Index depth) { + LOGF("OnBrExpr(depth: %" PRIindex ")\n", depth); + return reader_->OnBrExpr(depth); +} + +Result BinaryReaderLogging::OnBrIfExpr(Index depth) { + LOGF("OnBrIfExpr(depth: %" PRIindex ")\n", depth); + return reader_->OnBrIfExpr(depth); +} + +Result BinaryReaderLogging::OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) { + LOGF("OnBrTableExpr(num_targets: %" PRIindex ", depths: [", num_targets); + for (Index i = 0; i < num_targets; ++i) { + LOGF_NOINDENT("%" PRIindex, target_depths[i]); + if (i != num_targets - 1) { + LOGF_NOINDENT(", "); + } + } + LOGF_NOINDENT("], default: %" PRIindex ")\n", default_target_depth); + return reader_->OnBrTableExpr(num_targets, target_depths, + default_target_depth); +} + +Result BinaryReaderLogging::OnF32ConstExpr(uint32_t value_bits) { + float value; + memcpy(&value, &value_bits, sizeof(value)); + LOGF("OnF32ConstExpr(%g (0x%08x))\n", value, value_bits); + return reader_->OnF32ConstExpr(value_bits); +} + +Result BinaryReaderLogging::OnF64ConstExpr(uint64_t value_bits) { + double value; + memcpy(&value, &value_bits, sizeof(value)); + LOGF("OnF64ConstExpr(%g (0x%016" PRIx64 "))\n", value, value_bits); + return reader_->OnF64ConstExpr(value_bits); +} + +Result BinaryReaderLogging::OnV128ConstExpr(v128 value_bits) { + LOGF("OnV128ConstExpr(0x%08x 0x%08x 0x%08x 0x%08x)\n", value_bits.u32(0), + value_bits.u32(1), value_bits.u32(2), value_bits.u32(3)); + return reader_->OnV128ConstExpr(value_bits); +} + +Result BinaryReaderLogging::OnI32ConstExpr(uint32_t value) { + LOGF("OnI32ConstExpr(%u (0x%x))\n", value, value); + return reader_->OnI32ConstExpr(value); +} + +Result BinaryReaderLogging::OnI64ConstExpr(uint64_t value) { + LOGF("OnI64ConstExpr(%" PRIu64 " (0x%" PRIx64 "))\n", value, value); + return reader_->OnI64ConstExpr(value); +} + +Result BinaryReaderLogging::OnIfExpr(Type sig_type) { + LOGF("OnIfExpr(sig: "); + LogType(sig_type); + LOGF_NOINDENT(")\n"); + return reader_->OnIfExpr(sig_type); +} + +Result BinaryReaderLogging::OnLoopExpr(Type sig_type) { + LOGF("OnLoopExpr(sig: "); + LogType(sig_type); + LOGF_NOINDENT(")\n"); + return reader_->OnLoopExpr(sig_type); +} + +Result BinaryReaderLogging::OnSelectExpr(Index result_count, + Type* result_types) { + LOGF("OnSelectExpr(return_type: "); + LogTypes(result_count, result_types); + LOGF_NOINDENT(")\n"); + return reader_->OnSelectExpr(result_count, result_types); +} + +Result BinaryReaderLogging::OnTryExpr(Type sig_type) { + LOGF("OnTryExpr(sig: "); + LogType(sig_type); + LOGF_NOINDENT(")\n"); + return reader_->OnTryExpr(sig_type); +} + +Result BinaryReaderLogging::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) { + LOGF("OnSimdLaneOpExpr (lane: %" PRIu64 ")\n", value); + return reader_->OnSimdLaneOpExpr(opcode, value); +} + +Result BinaryReaderLogging::OnSimdShuffleOpExpr(Opcode opcode, v128 value) { + LOGF("OnSimdShuffleOpExpr (lane: 0x%08x %08x %08x %08x)\n", value.u32(0), + value.u32(1), value.u32(2), value.u32(3)); + return reader_->OnSimdShuffleOpExpr(opcode, value); +} + +Result BinaryReaderLogging::BeginElemSegment(Index index, + Index table_index, + uint8_t flags) { + LOGF("BeginElemSegment(index: %" PRIindex ", table_index: %" PRIindex + ", flags: %d)\n", + index, table_index, flags); + return reader_->BeginElemSegment(index, table_index, flags); +} + +Result BinaryReaderLogging::OnElemSegmentElemType(Index index, Type elem_type) { + LOGF("OnElemSegmentElemType(index: %" PRIindex ", type: %s)\n", index, + elem_type.GetName()); + return reader_->OnElemSegmentElemType(index, elem_type); +} + +Result BinaryReaderLogging::OnDataSegmentData(Index index, + const void* data, + Address size) { + LOGF("OnDataSegmentData(index:%" PRIindex ", size:%" PRIaddress ")\n", index, + size); + return reader_->OnDataSegmentData(index, data, size); +} + +Result BinaryReaderLogging::OnModuleNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) { + LOGF("OnModuleNameSubsection(index:%" PRIindex ", nametype:%u, size:%" PRIzd + ")\n", + index, name_type, subsection_size); + return reader_->OnModuleNameSubsection(index, name_type, subsection_size); +} + +Result BinaryReaderLogging::OnModuleName(string_view name) { + LOGF("OnModuleName(name: \"" PRIstringview "\")\n", + WABT_PRINTF_STRING_VIEW_ARG(name)); + return reader_->OnModuleName(name); +} + +Result BinaryReaderLogging::OnFunctionNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) { + LOGF("OnFunctionNameSubsection(index:%" PRIindex ", nametype:%u, size:%" PRIzd + ")\n", + index, name_type, subsection_size); + return reader_->OnFunctionNameSubsection(index, name_type, subsection_size); +} + +Result BinaryReaderLogging::OnFunctionName(Index index, string_view name) { + LOGF("OnFunctionName(index: %" PRIindex ", name: \"" PRIstringview "\")\n", + index, WABT_PRINTF_STRING_VIEW_ARG(name)); + return reader_->OnFunctionName(index, name); +} + +Result BinaryReaderLogging::OnLocalNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) { + LOGF("OnLocalNameSubsection(index:%" PRIindex ", nametype:%u, size:%" PRIzd + ")\n", + index, name_type, subsection_size); + return reader_->OnLocalNameSubsection(index, name_type, subsection_size); +} + +Result BinaryReaderLogging::OnLocalName(Index func_index, + Index local_index, + string_view name) { + LOGF("OnLocalName(func_index: %" PRIindex ", local_index: %" PRIindex + ", name: \"" PRIstringview "\")\n", + func_index, local_index, WABT_PRINTF_STRING_VIEW_ARG(name)); + return reader_->OnLocalName(func_index, local_index, name); +} + +Result BinaryReaderLogging::OnNameSubsection( + Index index, + NameSectionSubsection subsection_type, + Offset subsection_size) { + LOGF("OnNameSubsection(index: %" PRIindex ", type: %s, size:%" PRIzd ")\n", + index, GetNameSectionSubsectionName(subsection_type), subsection_size); + return reader_->OnNameSubsection(index, subsection_type, subsection_size); +} + +Result BinaryReaderLogging::OnNameEntry(NameSectionSubsection type, + Index index, + string_view name) { + LOGF("OnNameEntry(type: %s, index: %" PRIindex ", name: \"" PRIstringview + "\")\n", + GetNameSectionSubsectionName(type), index, + WABT_PRINTF_STRING_VIEW_ARG(name)); + return reader_->OnNameEntry(type, index, name); +} + +Result BinaryReaderLogging::OnInitExprF32ConstExpr(Index index, + uint32_t value_bits) { + float value; + memcpy(&value, &value_bits, sizeof(value)); + LOGF("OnInitExprF32ConstExpr(index: %" PRIindex ", value: %g (0x04%x))\n", + index, value, value_bits); + return reader_->OnInitExprF32ConstExpr(index, value_bits); +} + +Result BinaryReaderLogging::OnInitExprF64ConstExpr(Index index, + uint64_t value_bits) { + double value; + memcpy(&value, &value_bits, sizeof(value)); + LOGF("OnInitExprF64ConstExpr(index: %" PRIindex " value: %g (0x08%" PRIx64 + "))\n", + index, value, value_bits); + return reader_->OnInitExprF64ConstExpr(index, value_bits); +} + +Result BinaryReaderLogging::OnInitExprV128ConstExpr(Index index, + v128 value_bits) { + LOGF("OnInitExprV128ConstExpr(index: %" PRIindex + " value: ( 0x%08x 0x%08x 0x%08x 0x%08x))\n", + index, value_bits.u32(0), value_bits.u32(1), value_bits.u32(2), + value_bits.u32(3)); + return reader_->OnInitExprV128ConstExpr(index, value_bits); +} + +Result BinaryReaderLogging::OnInitExprI32ConstExpr(Index index, + uint32_t value) { + LOGF("OnInitExprI32ConstExpr(index: %" PRIindex ", value: %u)\n", index, + value); + return reader_->OnInitExprI32ConstExpr(index, value); +} + +Result BinaryReaderLogging::OnInitExprI64ConstExpr(Index index, + uint64_t value) { + LOGF("OnInitExprI64ConstExpr(index: %" PRIindex ", value: %" PRIu64 ")\n", + index, value); + return reader_->OnInitExprI64ConstExpr(index, value); +} + +Result BinaryReaderLogging::OnDylinkInfo(uint32_t mem_size, + uint32_t mem_align, + uint32_t table_size, + uint32_t table_align) { + LOGF( + "OnDylinkInfo(mem_size: %u, mem_align: %u, table_size: %u, table_align: " + "%u)\n", + mem_size, mem_align, table_size, table_align); + return reader_->OnDylinkInfo(mem_size, mem_align, table_size, table_align); +} + +Result BinaryReaderLogging::OnDylinkNeeded(string_view so_name) { + LOGF("OnDylinkNeeded(name: " PRIstringview ")\n", + WABT_PRINTF_STRING_VIEW_ARG(so_name)); + return reader_->OnDylinkNeeded(so_name); +} + +Result BinaryReaderLogging::OnRelocCount(Index count, + Index section_index) { + LOGF("OnRelocCount(count: %" PRIindex ", section: %" PRIindex ")\n", count, + section_index); + return reader_->OnRelocCount(count, section_index); +} + +Result BinaryReaderLogging::OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) { + int32_t signed_addend = static_cast(addend); + LOGF("OnReloc(type: %s, offset: %" PRIzd ", index: %" PRIindex + ", addend: %d)\n", + GetRelocTypeName(type), offset, index, signed_addend); + return reader_->OnReloc(type, offset, index, addend); +} + +Result BinaryReaderLogging::OnSymbol(Index symbol_index, + SymbolType type, + uint32_t flags) { + LOGF("OnSymbol(type: %s flags: 0x%x)\n", GetSymbolTypeName(type), flags); + return reader_->OnSymbol(symbol_index, type, flags); +} + +Result BinaryReaderLogging::OnDataSymbol(Index index, + uint32_t flags, + string_view name, + Index segment, + uint32_t offset, + uint32_t size) { + LOGF("OnDataSymbol(name: " PRIstringview " flags: 0x%x)\n", + WABT_PRINTF_STRING_VIEW_ARG(name), flags); + return reader_->OnDataSymbol(index, flags, name, segment, offset, size); +} + +Result BinaryReaderLogging::OnFunctionSymbol(Index index, + uint32_t flags, + string_view name, + Index func_index) { + LOGF("OnFunctionSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex + ")\n", + WABT_PRINTF_STRING_VIEW_ARG(name), flags, func_index); + return reader_->OnFunctionSymbol(index, flags, name, func_index); +} + +Result BinaryReaderLogging::OnGlobalSymbol(Index index, + uint32_t flags, + string_view name, + Index global_index) { + LOGF("OnGlobalSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex + ")\n", + WABT_PRINTF_STRING_VIEW_ARG(name), flags, global_index); + return reader_->OnGlobalSymbol(index, flags, name, global_index); +} + +Result BinaryReaderLogging::OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) { + LOGF("OnSectionSymbol(flags: 0x%x index: %" PRIindex ")\n", flags, + section_index); + return reader_->OnSectionSymbol(index, flags, section_index); +} + +Result BinaryReaderLogging::OnEventSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) { + LOGF("OnEventSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex + ")\n", + WABT_PRINTF_STRING_VIEW_ARG(name), flags, event_index); + return reader_->OnEventSymbol(index, flags, name, event_index); +} + +Result BinaryReaderLogging::OnTableSymbol(Index index, + uint32_t flags, + string_view name, + Index table_index) { + LOGF("OnTableSymbol(name: " PRIstringview " flags: 0x%x index: %" PRIindex + ")\n", + WABT_PRINTF_STRING_VIEW_ARG(name), flags, table_index); + return reader_->OnTableSymbol(index, flags, name, table_index); +} + +Result BinaryReaderLogging::OnSegmentInfo(Index index, + string_view name, + Address alignment, + uint32_t flags) { + LOGF("OnSegmentInfo(%d name: " PRIstringview ", alignment: %" PRIaddress + ", flags: 0x%x)\n", + index, WABT_PRINTF_STRING_VIEW_ARG(name), alignment, flags); + return reader_->OnSegmentInfo(index, name, alignment, flags); +} + +Result BinaryReaderLogging::OnInitFunction(uint32_t priority, + Index func_index) { + LOGF("OnInitFunction(%d priority: %d)\n", func_index, priority); + return reader_->OnInitFunction(priority, func_index); +} + +Result BinaryReaderLogging::OnComdatBegin(string_view name, + uint32_t flags, + Index count) { + LOGF("OnComdatBegin(" PRIstringview ", flags: %d, count: %" PRIindex ")\n", + WABT_PRINTF_STRING_VIEW_ARG(name), flags, count); + return reader_->OnComdatBegin(name, flags, count); +} + +Result BinaryReaderLogging::OnComdatEntry(ComdatType kind, Index index) { + LOGF("OnComdatEntry(kind: %d, index: %" PRIindex ")\n", + static_cast(kind), index); + return reader_->OnComdatEntry(kind, index); +} + +#define DEFINE_BEGIN(name) \ + Result BinaryReaderLogging::name(Offset size) { \ + LOGF(#name "(%" PRIzd ")\n", size); \ + Indent(); \ + return reader_->name(size); \ + } + +#define DEFINE_END(name) \ + Result BinaryReaderLogging::name() { \ + Dedent(); \ + LOGF(#name "\n"); \ + return reader_->name(); \ + } + +#define DEFINE_INDEX(name) \ + Result BinaryReaderLogging::name(Index value) { \ + LOGF(#name "(%" PRIindex ")\n", value); \ + return reader_->name(value); \ + } + +#define DEFINE_TYPE(name) \ + Result BinaryReaderLogging::name(Type type) { \ + LOGF(#name "(%s)\n", type.GetName()); \ + return reader_->name(type); \ + } + +#define DEFINE_INDEX_DESC(name, desc) \ + Result BinaryReaderLogging::name(Index value) { \ + LOGF(#name "(" desc ": %" PRIindex ")\n", value); \ + return reader_->name(value); \ + } + +#define DEFINE_INDEX_TYPE(name) \ + Result BinaryReaderLogging::name(Index value, Type type) { \ + LOGF(#name "(index: %" PRIindex ", type: %s)\n", value, type.GetName()); \ + return reader_->name(value, type); \ + } + +#define DEFINE_INDEX_INDEX(name, desc0, desc1) \ + Result BinaryReaderLogging::name(Index value0, Index value1) { \ + LOGF(#name "(" desc0 ": %" PRIindex ", " desc1 ": %" PRIindex ")\n", \ + value0, value1); \ + return reader_->name(value0, value1); \ + } + +#define DEFINE_INDEX_INDEX_U8(name, desc0, desc1, desc2) \ + Result BinaryReaderLogging::name(Index value0, Index value1, \ + uint8_t value2) { \ + LOGF(#name "(" desc0 ": %" PRIindex ", " desc1 ": %" PRIindex ", " desc2 \ + ": %d)\n", \ + value0, value1, value2); \ + return reader_->name(value0, value1, value2); \ + } + +#define DEFINE_OPCODE(name) \ + Result BinaryReaderLogging::name(Opcode opcode) { \ + LOGF(#name "(\"%s\" (%u))\n", opcode.GetName(), opcode.GetCode()); \ + return reader_->name(opcode); \ + } + +#define DEFINE_LOAD_STORE_OPCODE(name) \ + Result BinaryReaderLogging::name(Opcode opcode, Address alignment_log2, \ + Address offset) { \ + LOGF(#name "(opcode: \"%s\" (%u), align log2: %" PRIaddress \ + ", offset: %" PRIaddress ")\n", \ + opcode.GetName(), opcode.GetCode(), alignment_log2, offset); \ + return reader_->name(opcode, alignment_log2, offset); \ + } + +#define DEFINE0(name) \ + Result BinaryReaderLogging::name() { \ + LOGF(#name "\n"); \ + return reader_->name(); \ + } + +DEFINE_END(EndModule) + +DEFINE_END(EndCustomSection) + +DEFINE_BEGIN(BeginTypeSection) +DEFINE_INDEX(OnTypeCount) +DEFINE_END(EndTypeSection) + +DEFINE_BEGIN(BeginImportSection) +DEFINE_INDEX(OnImportCount) +DEFINE_END(EndImportSection) + +DEFINE_BEGIN(BeginFunctionSection) +DEFINE_INDEX(OnFunctionCount) +DEFINE_INDEX_INDEX(OnFunction, "index", "sig_index") +DEFINE_END(EndFunctionSection) + +DEFINE_BEGIN(BeginTableSection) +DEFINE_INDEX(OnTableCount) +DEFINE_END(EndTableSection) + +DEFINE_BEGIN(BeginMemorySection) +DEFINE_INDEX(OnMemoryCount) +DEFINE_END(EndMemorySection) + +DEFINE_BEGIN(BeginGlobalSection) +DEFINE_INDEX(OnGlobalCount) +DEFINE_INDEX(BeginGlobalInitExpr) +DEFINE_INDEX(EndGlobalInitExpr) +DEFINE_INDEX(EndGlobal) +DEFINE_END(EndGlobalSection) + +DEFINE_BEGIN(BeginExportSection) +DEFINE_INDEX(OnExportCount) +DEFINE_END(EndExportSection) + +DEFINE_BEGIN(BeginStartSection) +DEFINE_INDEX(OnStartFunction) +DEFINE_END(EndStartSection) + +DEFINE_BEGIN(BeginCodeSection) +DEFINE_INDEX(OnFunctionBodyCount) +DEFINE_INDEX(EndFunctionBody) +DEFINE_INDEX(OnLocalDeclCount) +DEFINE_LOAD_STORE_OPCODE(OnAtomicLoadExpr); +DEFINE_LOAD_STORE_OPCODE(OnAtomicRmwExpr); +DEFINE_LOAD_STORE_OPCODE(OnAtomicRmwCmpxchgExpr); +DEFINE_LOAD_STORE_OPCODE(OnAtomicStoreExpr); +DEFINE_LOAD_STORE_OPCODE(OnAtomicWaitExpr); +DEFINE_INDEX_DESC(OnAtomicFenceExpr, "consistency_model"); +DEFINE_LOAD_STORE_OPCODE(OnAtomicNotifyExpr); +DEFINE_OPCODE(OnBinaryExpr) +DEFINE_INDEX_DESC(OnCallExpr, "func_index") +DEFINE_INDEX_INDEX(OnCallIndirectExpr, "sig_index", "table_index") +DEFINE_INDEX_DESC(OnCatchExpr, "event_index"); +DEFINE0(OnCatchAllExpr); +DEFINE_OPCODE(OnCompareExpr) +DEFINE_OPCODE(OnConvertExpr) +DEFINE_INDEX_DESC(OnDelegateExpr, "depth"); +DEFINE0(OnDropExpr) +DEFINE0(OnElseExpr) +DEFINE0(OnEndExpr) +DEFINE_INDEX_DESC(OnGlobalGetExpr, "index") +DEFINE_INDEX_DESC(OnGlobalSetExpr, "index") +DEFINE_LOAD_STORE_OPCODE(OnLoadExpr); +DEFINE_INDEX_DESC(OnLocalGetExpr, "index") +DEFINE_INDEX_DESC(OnLocalSetExpr, "index") +DEFINE_INDEX_DESC(OnLocalTeeExpr, "index") +DEFINE0(OnMemoryCopyExpr) +DEFINE_INDEX(OnDataDropExpr) +DEFINE0(OnMemoryFillExpr) +DEFINE0(OnMemoryGrowExpr) +DEFINE_INDEX(OnMemoryInitExpr) +DEFINE0(OnMemorySizeExpr) +DEFINE_INDEX_INDEX(OnTableCopyExpr, "dst_index", "src_index") +DEFINE_INDEX(OnElemDropExpr) +DEFINE_INDEX_INDEX(OnTableInitExpr, "segment_index", "table_index") +DEFINE_INDEX(OnTableSetExpr) +DEFINE_INDEX(OnTableGetExpr) +DEFINE_INDEX(OnTableGrowExpr) +DEFINE_INDEX(OnTableSizeExpr) +DEFINE_INDEX_DESC(OnTableFillExpr, "table index") +DEFINE_INDEX(OnRefFuncExpr) +DEFINE_TYPE(OnRefNullExpr) +DEFINE0(OnRefIsNullExpr) +DEFINE0(OnNopExpr) +DEFINE_INDEX_DESC(OnRethrowExpr, "depth"); +DEFINE_INDEX_DESC(OnReturnCallExpr, "func_index") + +DEFINE_INDEX_INDEX(OnReturnCallIndirectExpr, "sig_index", "table_index") +DEFINE0(OnReturnExpr) +DEFINE_LOAD_STORE_OPCODE(OnLoadSplatExpr); +DEFINE_LOAD_STORE_OPCODE(OnStoreExpr); +DEFINE_INDEX_DESC(OnThrowExpr, "event_index") +DEFINE0(OnUnreachableExpr) +DEFINE0(OnUnwindExpr) +DEFINE_OPCODE(OnUnaryExpr) +DEFINE_OPCODE(OnTernaryExpr) +DEFINE_END(EndCodeSection) + +DEFINE_BEGIN(BeginElemSection) +DEFINE_INDEX(OnElemSegmentCount) +DEFINE_INDEX(BeginElemSegmentInitExpr) +DEFINE_INDEX(EndElemSegmentInitExpr) +DEFINE_INDEX_INDEX(OnElemSegmentElemExprCount, "index", "count") +DEFINE_INDEX_TYPE(OnElemSegmentElemExpr_RefNull) +DEFINE_INDEX_INDEX(OnElemSegmentElemExpr_RefFunc, "index", "func_index") +DEFINE_INDEX(EndElemSegment) +DEFINE_END(EndElemSection) + +DEFINE_BEGIN(BeginDataSection) +DEFINE_INDEX(OnDataSegmentCount) +DEFINE_INDEX_INDEX_U8(BeginDataSegment, "index", "memory_index", "flags") +DEFINE_INDEX(BeginDataSegmentInitExpr) +DEFINE_INDEX(EndDataSegmentInitExpr) +DEFINE_INDEX(EndDataSegment) +DEFINE_END(EndDataSection) + +DEFINE_BEGIN(BeginDataCountSection) +DEFINE_INDEX(OnDataCount) +DEFINE_END(EndDataCountSection) + +DEFINE_BEGIN(BeginNamesSection) +DEFINE_INDEX(OnFunctionNamesCount) +DEFINE_INDEX(OnLocalNameFunctionCount) +DEFINE_INDEX_INDEX(OnLocalNameLocalCount, "index", "count") +DEFINE_INDEX(OnNameCount); +DEFINE_END(EndNamesSection) + +DEFINE_BEGIN(BeginRelocSection) +DEFINE_END(EndRelocSection) + +DEFINE_INDEX_INDEX(OnInitExprGlobalGetExpr, "index", "global_index") +DEFINE_INDEX_TYPE(OnInitExprRefNull) +DEFINE_INDEX_INDEX(OnInitExprRefFunc, "index", "func_index") + +DEFINE_BEGIN(BeginDylinkSection) +DEFINE_INDEX(OnDylinkNeededCount) +DEFINE_END(EndDylinkSection) + +DEFINE_BEGIN(BeginLinkingSection) +DEFINE_INDEX(OnSymbolCount) +DEFINE_INDEX(OnSegmentInfoCount) +DEFINE_INDEX(OnInitFunctionCount) +DEFINE_INDEX(OnComdatCount) +DEFINE_END(EndLinkingSection) + +DEFINE_BEGIN(BeginEventSection); +DEFINE_INDEX(OnEventCount); +DEFINE_INDEX_INDEX(OnEventType, "index", "sig_index") +DEFINE_END(EndEventSection); + +// We don't need to log these (the individual opcodes are logged instead), but +// we still need to forward the calls. +Result BinaryReaderLogging::OnOpcode(Opcode opcode) { + return reader_->OnOpcode(opcode); +} + +Result BinaryReaderLogging::OnOpcodeBare() { + return reader_->OnOpcodeBare(); +} + +Result BinaryReaderLogging::OnOpcodeIndex(Index value) { + return reader_->OnOpcodeIndex(value); +} + +Result BinaryReaderLogging::OnOpcodeIndexIndex(Index value, Index value2) { + return reader_->OnOpcodeIndexIndex(value, value2); +} + +Result BinaryReaderLogging::OnOpcodeUint32(uint32_t value) { + return reader_->OnOpcodeUint32(value); +} + +Result BinaryReaderLogging::OnOpcodeUint32Uint32(uint32_t value, + uint32_t value2) { + return reader_->OnOpcodeUint32Uint32(value, value2); +} + +Result BinaryReaderLogging::OnOpcodeUint64(uint64_t value) { + return reader_->OnOpcodeUint64(value); +} + +Result BinaryReaderLogging::OnOpcodeF32(uint32_t value) { + return reader_->OnOpcodeF32(value); +} + +Result BinaryReaderLogging::OnOpcodeF64(uint64_t value) { + return reader_->OnOpcodeF64(value); +} + +Result BinaryReaderLogging::OnOpcodeV128(v128 value) { + return reader_->OnOpcodeV128(value); +} + +Result BinaryReaderLogging::OnOpcodeBlockSig(Type sig_type) { + return reader_->OnOpcodeBlockSig(sig_type); +} + +Result BinaryReaderLogging::OnOpcodeType(Type type) { + return reader_->OnOpcodeType(type); +} + +Result BinaryReaderLogging::OnEndFunc() { + return reader_->OnEndFunc(); +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.h new file mode 100644 index 0000000..70dcbae --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.h @@ -0,0 +1,385 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_READER_LOGGING_H_ +#define WABT_BINARY_READER_LOGGING_H_ + +#include "src/binary-reader.h" + +namespace wabt { + +class Stream; + +class BinaryReaderLogging : public BinaryReaderDelegate { + public: + BinaryReaderLogging(Stream*, BinaryReaderDelegate* forward); + + bool OnError(const Error&) override; + void OnSetState(const State* s) override; + + Result BeginModule(uint32_t version) override; + Result EndModule() override; + + Result BeginSection(Index section_index, + BinarySection section_type, + Offset size) override; + + Result BeginCustomSection(Index section_index, + Offset size, + string_view section_name) override; + Result EndCustomSection() override; + + Result BeginTypeSection(Offset size) override; + Result OnTypeCount(Index count) override; + Result OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) override; + Result OnStructType(Index index, Index field_count, TypeMut* fields) override; + Result OnArrayType(Index index, TypeMut field) override; + Result EndTypeSection() override; + + Result BeginImportSection(Offset size) override; + Result OnImportCount(Index count) override; + Result OnImport(Index index, + ExternalKind kind, + string_view module_name, + string_view field_name) override; + Result OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) override; + Result OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) override; + Result OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) override; + Result OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) override; + Result OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) override; + Result EndImportSection() override; + + Result BeginFunctionSection(Offset size) override; + Result OnFunctionCount(Index count) override; + Result OnFunction(Index index, Index sig_index) override; + Result EndFunctionSection() override; + + Result BeginTableSection(Offset size) override; + Result OnTableCount(Index count) override; + Result OnTable(Index index, + Type elem_type, + const Limits* elem_limits) override; + Result EndTableSection() override; + + Result BeginMemorySection(Offset size) override; + Result OnMemoryCount(Index count) override; + Result OnMemory(Index index, const Limits* limits) override; + Result EndMemorySection() override; + + Result BeginGlobalSection(Offset size) override; + Result OnGlobalCount(Index count) override; + Result BeginGlobal(Index index, Type type, bool mutable_) override; + Result BeginGlobalInitExpr(Index index) override; + Result EndGlobalInitExpr(Index index) override; + Result EndGlobal(Index index) override; + Result EndGlobalSection() override; + + Result BeginExportSection(Offset size) override; + Result OnExportCount(Index count) override; + Result OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) override; + Result EndExportSection() override; + + Result BeginStartSection(Offset size) override; + Result OnStartFunction(Index func_index) override; + Result EndStartSection() override; + + Result BeginCodeSection(Offset size) override; + Result OnFunctionBodyCount(Index count) override; + Result BeginFunctionBody(Index index, Offset size) override; + Result OnLocalDeclCount(Index count) override; + Result OnLocalDecl(Index decl_index, Index count, Type type) override; + + Result OnOpcode(Opcode opcode) override; + Result OnOpcodeBare() override; + Result OnOpcodeIndex(Index value) override; + Result OnOpcodeIndexIndex(Index value, Index value2) override; + Result OnOpcodeUint32(uint32_t value) override; + Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override; + Result OnOpcodeUint64(uint64_t value) override; + Result OnOpcodeF32(uint32_t value) override; + Result OnOpcodeF64(uint64_t value) override; + Result OnOpcodeV128(v128 value) override; + Result OnOpcodeBlockSig(Type sig_type) override; + Result OnOpcodeType(Type type) override; + Result OnAtomicLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicRmwExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicRmwCmpxchgExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnBinaryExpr(Opcode opcode) override; + Result OnBlockExpr(Type sig_type) override; + Result OnBrExpr(Index depth) override; + Result OnBrIfExpr(Index depth) override; + Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) override; + Result OnCallExpr(Index func_index) override; + Result OnCatchExpr(Index event_index) override; + Result OnCatchAllExpr() override; + Result OnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnCompareExpr(Opcode opcode) override; + Result OnConvertExpr(Opcode opcode) override; + Result OnDelegateExpr(Index depth) override; + Result OnDropExpr() override; + Result OnElseExpr() override; + Result OnEndExpr() override; + Result OnEndFunc() override; + Result OnF32ConstExpr(uint32_t value_bits) override; + Result OnF64ConstExpr(uint64_t value_bits) override; + Result OnV128ConstExpr(v128 value_bits) override; + Result OnGlobalGetExpr(Index global_index) override; + Result OnGlobalSetExpr(Index global_index) override; + Result OnI32ConstExpr(uint32_t value) override; + Result OnI64ConstExpr(uint64_t value) override; + Result OnIfExpr(Type sig_type) override; + Result OnLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnLocalGetExpr(Index local_index) override; + Result OnLocalSetExpr(Index local_index) override; + Result OnLocalTeeExpr(Index local_index) override; + Result OnLoopExpr(Type sig_type) override; + Result OnMemoryCopyExpr() override; + Result OnDataDropExpr(Index segment_index) override; + Result OnMemoryFillExpr() override; + Result OnMemoryGrowExpr() override; + Result OnMemoryInitExpr(Index segment_index) override; + Result OnMemorySizeExpr() override; + Result OnTableCopyExpr(Index dst_index, Index src_index) override; + Result OnElemDropExpr(Index segment_index) override; + Result OnTableInitExpr(Index segment_index, Index table_index) override; + Result OnTableGetExpr(Index table) override; + Result OnTableSetExpr(Index table) override; + Result OnTableGrowExpr(Index table) override; + Result OnTableSizeExpr(Index table) override; + Result OnTableFillExpr(Index table) override; + Result OnRefFuncExpr(Index index) override; + Result OnRefNullExpr(Type type) override; + Result OnRefIsNullExpr() override; + Result OnNopExpr() override; + Result OnRethrowExpr(Index depth) override; + Result OnReturnCallExpr(Index func_index) override; + Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override; + Result OnReturnExpr() override; + Result OnSelectExpr(Index result_count, Type* result_types) override; + Result OnStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnThrowExpr(Index event_index) override; + Result OnTryExpr(Type sig_type) override; + Result OnUnaryExpr(Opcode opcode) override; + Result OnTernaryExpr(Opcode opcode) override; + Result OnUnreachableExpr() override; + Result OnUnwindExpr() override; + Result OnAtomicWaitExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result OnAtomicFenceExpr(uint32_t consistency_model) override; + Result OnAtomicNotifyExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + Result EndFunctionBody(Index index) override; + Result EndCodeSection() override; + Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override; + Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override; + Result OnLoadSplatExpr(Opcode opcode, + Address alignment_log2, + Address offset) override; + + Result BeginElemSection(Offset size) override; + Result OnElemSegmentCount(Index count) override; + Result BeginElemSegment(Index index, + Index table_index, + uint8_t flags) override; + Result BeginElemSegmentInitExpr(Index index) override; + Result EndElemSegmentInitExpr(Index index) override; + Result OnElemSegmentElemType(Index index, Type elem_type) override; + Result OnElemSegmentElemExprCount(Index index, Index count) override; + Result OnElemSegmentElemExpr_RefNull(Index segment_index, Type type) override; + Result OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) override; + Result EndElemSegment(Index index) override; + Result EndElemSection() override; + + Result BeginDataSection(Offset size) override; + Result OnDataSegmentCount(Index count) override; + Result BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) override; + Result BeginDataSegmentInitExpr(Index index) override; + Result EndDataSegmentInitExpr(Index index) override; + Result OnDataSegmentData(Index index, + const void* data, + Address size) override; + Result EndDataSegment(Index index) override; + Result EndDataSection() override; + + Result BeginDataCountSection(Offset size) override; + Result OnDataCount(Index count) override; + Result EndDataCountSection() override; + + Result BeginNamesSection(Offset size) override; + Result OnModuleNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) override; + Result OnModuleName(string_view name) override; + Result OnFunctionNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) override; + Result OnFunctionNamesCount(Index num_functions) override; + Result OnFunctionName(Index function_index, + string_view function_name) override; + Result OnLocalNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) override; + Result OnLocalNameFunctionCount(Index num_functions) override; + Result OnLocalNameLocalCount(Index function_index, Index num_locals) override; + Result OnLocalName(Index function_index, + Index local_index, + string_view local_name) override; + Result OnNameSubsection(Index index, + NameSectionSubsection subsection_type, + Offset subsection_size) override; + Result OnNameEntry(NameSectionSubsection type, + Index index, + string_view name) override; + Result OnNameCount(Index num_names) override; + Result EndNamesSection() override; + + Result BeginRelocSection(Offset size) override; + Result OnRelocCount(Index count, Index section_index) override; + Result OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) override; + Result EndRelocSection() override; + + Result BeginDylinkSection(Offset size) override; + Result OnDylinkInfo(uint32_t mem_size, + uint32_t mem_align, + uint32_t table_size, + uint32_t table_align) override; + Result OnDylinkNeededCount(Index count) override; + Result OnDylinkNeeded(string_view needed) override; + Result EndDylinkSection() override; + + Result BeginLinkingSection(Offset size) override; + Result OnSymbolCount(Index count) override; + Result OnSymbol(Index sybmol_index, SymbolType type, uint32_t flags) override; + Result OnDataSymbol(Index index, + uint32_t flags, + string_view name, + Index segment, + uint32_t offset, + uint32_t size) override; + Result OnFunctionSymbol(Index index, + uint32_t flags, + string_view name, + Index func_index) override; + Result OnGlobalSymbol(Index index, + uint32_t flags, + string_view name, + Index global_index) override; + Result OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) override; + Result OnEventSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) override; + Result OnTableSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) override; + Result OnSegmentInfoCount(Index count) override; + Result OnSegmentInfo(Index index, + string_view name, + Address alignment, + uint32_t flags) override; + Result OnInitFunctionCount(Index count) override; + Result OnInitFunction(uint32_t priority, Index function_index) override; + Result OnComdatCount(Index count) override; + Result OnComdatBegin(string_view name, uint32_t flags, Index count) override; + Result OnComdatEntry(ComdatType kind, Index index) override; + Result EndLinkingSection() override; + + Result BeginEventSection(Offset size) override; + Result OnEventCount(Index count) override; + Result OnEventType(Index index, Index sig_index) override; + Result EndEventSection() override; + + Result OnInitExprF32ConstExpr(Index index, uint32_t value) override; + Result OnInitExprF64ConstExpr(Index index, uint64_t value) override; + Result OnInitExprV128ConstExpr(Index index, v128 value) override; + Result OnInitExprGlobalGetExpr(Index index, Index global_index) override; + Result OnInitExprI32ConstExpr(Index index, uint32_t value) override; + Result OnInitExprI64ConstExpr(Index index, uint64_t value) override; + Result OnInitExprRefNull(Index index, Type type) override; + Result OnInitExprRefFunc(Index index, Index func_index) override; + + private: + void Indent(); + void Dedent(); + void WriteIndent(); + void LogType(Type type); + void LogTypes(Index type_count, Type* types); + void LogTypes(TypeVector& types); + void LogField(TypeMut field); + + Stream* stream_; + BinaryReaderDelegate* reader_; + int indent_; +}; + +} // namespace wabt + +#endif // WABT_BINARY_READER_LOGGING_H_ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-nop.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-nop.h new file mode 100644 index 0000000..f72dbf1 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-nop.h @@ -0,0 +1,545 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_READER_NOP_H_ +#define WABT_BINARY_READER_NOP_H_ + +#include "src/binary-reader.h" + +namespace wabt { + +class BinaryReaderNop : public BinaryReaderDelegate { + public: + bool OnError(const Error&) override { return false; } + + /* Module */ + Result BeginModule(uint32_t version) override { return Result::Ok; } + Result EndModule() override { return Result::Ok; } + + Result BeginSection(Index section_index, + BinarySection section_type, + Offset size) override { + return Result::Ok; + } + + /* Custom section */ + Result BeginCustomSection(Index section_index, + Offset size, + string_view section_name) override { + return Result::Ok; + } + Result EndCustomSection() override { return Result::Ok; } + + /* Type section */ + Result BeginTypeSection(Offset size) override { return Result::Ok; } + Result OnTypeCount(Index count) override { return Result::Ok; } + Result OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) override { + return Result::Ok; + } + Result OnStructType(Index index, + Index field_count, + TypeMut* fields) override { + return Result::Ok; + } + Result OnArrayType(Index index, TypeMut field) override { + return Result::Ok; + } + Result EndTypeSection() override { return Result::Ok; } + + /* Import section */ + Result BeginImportSection(Offset size) override { return Result::Ok; } + Result OnImportCount(Index count) override { return Result::Ok; } + Result OnImport(Index index, + ExternalKind kind, + string_view module_name, + string_view field_name) override { + return Result::Ok; + } + Result OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) override { + return Result::Ok; + } + Result OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) override { + return Result::Ok; + } + Result OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) override { + return Result::Ok; + } + Result OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) override { + return Result::Ok; + } + Result OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) override { + return Result::Ok; + } + Result EndImportSection() override { return Result::Ok; } + + /* Function section */ + Result BeginFunctionSection(Offset size) override { return Result::Ok; } + Result OnFunctionCount(Index count) override { return Result::Ok; } + Result OnFunction(Index index, Index sig_index) override { + return Result::Ok; + } + Result EndFunctionSection() override { return Result::Ok; } + + /* Table section */ + Result BeginTableSection(Offset size) override { return Result::Ok; } + Result OnTableCount(Index count) override { return Result::Ok; } + Result OnTable(Index index, + Type elem_type, + const Limits* elem_limits) override { + return Result::Ok; + } + Result EndTableSection() override { return Result::Ok; } + + /* Memory section */ + Result BeginMemorySection(Offset size) override { return Result::Ok; } + Result OnMemoryCount(Index count) override { return Result::Ok; } + Result OnMemory(Index index, const Limits* limits) override { + return Result::Ok; + } + Result EndMemorySection() override { return Result::Ok; } + + /* Global section */ + Result BeginGlobalSection(Offset size) override { return Result::Ok; } + Result OnGlobalCount(Index count) override { return Result::Ok; } + Result BeginGlobal(Index index, Type type, bool mutable_) override { + return Result::Ok; + } + Result BeginGlobalInitExpr(Index index) override { return Result::Ok; } + Result EndGlobalInitExpr(Index index) override { return Result::Ok; } + Result EndGlobal(Index index) override { return Result::Ok; } + Result EndGlobalSection() override { return Result::Ok; } + + /* Exports section */ + Result BeginExportSection(Offset size) override { return Result::Ok; } + Result OnExportCount(Index count) override { return Result::Ok; } + Result OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) override { + return Result::Ok; + } + Result EndExportSection() override { return Result::Ok; } + + /* Start section */ + Result BeginStartSection(Offset size) override { return Result::Ok; } + Result OnStartFunction(Index func_index) override { return Result::Ok; } + Result EndStartSection() override { return Result::Ok; } + + /* Code section */ + Result BeginCodeSection(Offset size) override { return Result::Ok; } + Result OnFunctionBodyCount(Index count) override { return Result::Ok; } + Result BeginFunctionBody(Index index, Offset size) override { + return Result::Ok; + } + Result OnLocalDeclCount(Index count) override { return Result::Ok; } + Result OnLocalDecl(Index decl_index, Index count, Type type) override { + return Result::Ok; + } + + /* Function expressions; called between BeginFunctionBody and + EndFunctionBody */ + Result OnOpcode(Opcode Opcode) override { return Result::Ok; } + Result OnOpcodeBare() override { return Result::Ok; } + Result OnOpcodeIndex(Index value) override { return Result::Ok; } + Result OnOpcodeIndexIndex(Index value, Index value2) override { + return Result::Ok; + } + Result OnOpcodeUint32(uint32_t value) override { return Result::Ok; } + Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override { + return Result::Ok; + } + Result OnOpcodeUint64(uint64_t value) override { return Result::Ok; } + Result OnOpcodeF32(uint32_t value) override { return Result::Ok; } + Result OnOpcodeF64(uint64_t value) override { return Result::Ok; } + Result OnOpcodeV128(v128 value) override { return Result::Ok; } + Result OnOpcodeBlockSig(Type sig_type) override { return Result::Ok; } + Result OnOpcodeType(Type type) override { return Result::Ok; } + Result OnAtomicLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) override { + return Result::Ok; + } + Result OnAtomicStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) override { + return Result::Ok; + } + Result OnAtomicRmwExpr(Opcode opcode, + Address alignment_log2, + Address offset) override { + return Result::Ok; + } + Result OnAtomicRmwCmpxchgExpr(Opcode opcode, + Address alignment_log2, + Address offset) override { + return Result::Ok; + } + Result OnAtomicWaitExpr(Opcode, Address, Address) override { + return Result::Ok; + } + Result OnAtomicFenceExpr(uint32_t) override { + return Result::Ok; + } + Result OnAtomicNotifyExpr(Opcode, Address, Address) override { + return Result::Ok; + } + Result OnBinaryExpr(Opcode opcode) override { return Result::Ok; } + Result OnBlockExpr(Type sig_type) override { return Result::Ok; } + Result OnBrExpr(Index depth) override { return Result::Ok; } + Result OnBrIfExpr(Index depth) override { return Result::Ok; } + Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) override { + return Result::Ok; + } + Result OnCallExpr(Index func_index) override { return Result::Ok; } + Result OnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; } + Result OnCatchExpr(Index event_index) override { return Result::Ok; } + Result OnCatchAllExpr() override { return Result::Ok; } + Result OnCompareExpr(Opcode opcode) override { return Result::Ok; } + Result OnConvertExpr(Opcode opcode) override { return Result::Ok; } + Result OnDelegateExpr(Index depth) override { return Result::Ok; } + Result OnDropExpr() override { return Result::Ok; } + Result OnElseExpr() override { return Result::Ok; } + Result OnEndExpr() override { return Result::Ok; } + Result OnEndFunc() override { return Result::Ok; } + Result OnF32ConstExpr(uint32_t value_bits) override { return Result::Ok; } + Result OnF64ConstExpr(uint64_t value_bits) override { return Result::Ok; } + Result OnV128ConstExpr(v128 value_bits) override { return Result::Ok; } + Result OnGlobalGetExpr(Index global_index) override { return Result::Ok; } + Result OnGlobalSetExpr(Index global_index) override { return Result::Ok; } + Result OnI32ConstExpr(uint32_t value) override { return Result::Ok; } + Result OnI64ConstExpr(uint64_t value) override { return Result::Ok; } + Result OnIfExpr(Type sig_type) override { return Result::Ok; } + Result OnLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) override { + return Result::Ok; + } + Result OnLocalGetExpr(Index local_index) override { return Result::Ok; } + Result OnLocalSetExpr(Index local_index) override { return Result::Ok; } + Result OnLocalTeeExpr(Index local_index) override { return Result::Ok; } + Result OnLoopExpr(Type sig_type) override { return Result::Ok; } + Result OnMemoryCopyExpr() override { return Result::Ok; } + Result OnDataDropExpr(Index segment_index) override { return Result::Ok; } + Result OnMemoryFillExpr() override { return Result::Ok; } + Result OnMemoryGrowExpr() override { return Result::Ok; } + Result OnMemoryInitExpr(Index segment_index) override { return Result::Ok; } + Result OnMemorySizeExpr() override { return Result::Ok; } + Result OnTableCopyExpr(Index dst_index, Index src_index) override { + return Result::Ok; + } + Result OnElemDropExpr(Index segment_index) override { return Result::Ok; } + Result OnTableInitExpr(Index segment_index, Index table_index) override { + return Result::Ok; + } + Result OnTableGetExpr(Index table_index) override { return Result::Ok; } + Result OnTableSetExpr(Index table_index) override { return Result::Ok; } + Result OnTableGrowExpr(Index table_index) override { return Result::Ok; } + Result OnTableSizeExpr(Index table_index) override { return Result::Ok; } + Result OnTableFillExpr(Index table_index) override { return Result::Ok; } + Result OnRefFuncExpr(Index func_index) override { return Result::Ok; } + Result OnRefNullExpr(Type type) override { return Result::Ok; } + Result OnRefIsNullExpr() override { return Result::Ok; } + Result OnNopExpr() override { return Result::Ok; } + Result OnRethrowExpr(Index depth) override { return Result::Ok; } + Result OnReturnCallExpr(Index sig_index) override { return Result::Ok; } + Result OnReturnCallIndirectExpr(Index sig_index, Index table_index) override { return Result::Ok; } + Result OnReturnExpr() override { return Result::Ok; } + Result OnSelectExpr(Index result_count, Type* result_types) override { + return Result::Ok; + } + Result OnStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) override { + return Result::Ok; + } + Result OnThrowExpr(Index depth) override { return Result::Ok; } + Result OnTryExpr(Type sig_type) override { return Result::Ok; } + Result OnUnaryExpr(Opcode opcode) override { return Result::Ok; } + Result OnTernaryExpr(Opcode opcode) override { return Result::Ok; } + Result OnUnreachableExpr() override { return Result::Ok; } + Result OnUnwindExpr() override { return Result::Ok; } + Result EndFunctionBody(Index index) override { return Result::Ok; } + Result EndCodeSection() override { return Result::Ok; } + Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) override { + return Result::Ok; + } + Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) override { + return Result::Ok; + } + Result OnLoadSplatExpr(Opcode opcode, + Address alignment_log2, + Address offset) override { + return Result::Ok; + } + + /* Elem section */ + Result BeginElemSection(Offset size) override { return Result::Ok; } + Result OnElemSegmentCount(Index count) override { return Result::Ok; } + Result BeginElemSegment(Index index, + Index table_index, + uint8_t flags) override { + return Result::Ok; + } + Result BeginElemSegmentInitExpr(Index index) override { return Result::Ok; } + Result EndElemSegmentInitExpr(Index index) override { return Result::Ok; } + Result OnElemSegmentElemType(Index index, Type elem_type) override { + return Result::Ok; + } + Result OnElemSegmentElemExprCount(Index index, Index count) override { + return Result::Ok; + } + Result OnElemSegmentElemExpr_RefNull(Index segment_index, + Type type) override { + return Result::Ok; + } + Result OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) override { + return Result::Ok; + } + Result EndElemSegment(Index index) override { return Result::Ok; } + Result EndElemSection() override { return Result::Ok; } + + /* Data section */ + Result BeginDataSection(Offset size) override { return Result::Ok; } + Result OnDataSegmentCount(Index count) override { return Result::Ok; } + Result BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) override { + return Result::Ok; + } + Result BeginDataSegmentInitExpr(Index index) override { return Result::Ok; } + Result EndDataSegmentInitExpr(Index index) override { return Result::Ok; } + Result OnDataSegmentData(Index index, + const void* data, + Address size) override { + return Result::Ok; + } + Result EndDataSegment(Index index) override { return Result::Ok; } + Result EndDataSection() override { return Result::Ok; } + + /* DataCount section */ + Result BeginDataCountSection(Offset size) override { return Result::Ok; } + Result OnDataCount(Index count) override { return Result::Ok; } + Result EndDataCountSection() override { return Result::Ok; } + + /* Names section */ + Result BeginNamesSection(Offset size) override { return Result::Ok; } + Result OnModuleNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) override { + return Result::Ok; + } + Result OnModuleName(string_view name) override { return Result::Ok; } + Result OnFunctionNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) override { + return Result::Ok; + } + Result OnFunctionNamesCount(Index num_functions) override { + return Result::Ok; + } + Result OnFunctionName(Index function_index, + string_view function_name) override { + return Result::Ok; + } + Result OnLocalNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) override { + return Result::Ok; + } + Result OnLocalNameFunctionCount(Index num_functions) override { + return Result::Ok; + } + Result OnLocalNameLocalCount(Index function_index, + Index num_locals) override { + return Result::Ok; + } + Result OnLocalName(Index function_index, + Index local_index, + string_view local_name) override { + return Result::Ok; + } + Result EndNamesSection() override { return Result::Ok; } + + Result OnNameSubsection(Index index, + NameSectionSubsection subsection_type, + Offset subsection_size) override { + return Result::Ok; + } + Result OnNameCount(Index num_names) override { return Result::Ok; } + Result OnNameEntry(NameSectionSubsection type, + Index index, + string_view name) override { + return Result::Ok; + } + + /* Reloc section */ + Result BeginRelocSection(Offset size) override { return Result::Ok; } + Result OnRelocCount(Index count, Index section_code) override { + return Result::Ok; + } + Result OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) override { + return Result::Ok; + } + Result EndRelocSection() override { return Result::Ok; } + + /* Event section */ + Result BeginEventSection(Offset size) override { return Result::Ok; } + Result OnEventCount(Index count) override { return Result::Ok; } + Result OnEventType(Index index, Index sig_index) override { + return Result::Ok; + } + Result EndEventSection() override { return Result::Ok; } + + /* Dylink section */ + Result BeginDylinkSection(Offset size) override { return Result::Ok; } + Result OnDylinkInfo(uint32_t mem_size, + uint32_t mem_align, + uint32_t table_size, + uint32_t table_align) override { + return Result::Ok; + } + Result OnDylinkNeededCount(Index count) override { return Result::Ok; } + Result OnDylinkNeeded(string_view so_name) override { return Result::Ok; } + Result EndDylinkSection() override { return Result::Ok; } + + /* Linking section */ + Result BeginLinkingSection(Offset size) override { return Result::Ok; } + Result OnSymbolCount(Index count) override { return Result::Ok; } + Result OnSymbol(Index sybmol_index, + SymbolType type, + uint32_t flags) override { + return Result::Ok; + } + Result OnDataSymbol(Index index, + uint32_t flags, + string_view name, + Index segment, + uint32_t offset, + uint32_t size) override { + return Result::Ok; + } + Result OnFunctionSymbol(Index index, + uint32_t flags, + string_view name, + Index func_index) override { + return Result::Ok; + } + Result OnGlobalSymbol(Index index, + uint32_t flags, + string_view name, + Index global_index) override { + return Result::Ok; + } + Result OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) override { + return Result::Ok; + } + Result OnEventSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) override { + return Result::Ok; + } + Result OnTableSymbol(Index index, + uint32_t flags, + string_view name, + Index table_index) override { + return Result::Ok; + } + Result OnSegmentInfoCount(Index count) override { return Result::Ok; } + Result OnSegmentInfo(Index index, + string_view name, + Address alignment, + uint32_t flags) override { + return Result::Ok; + } + Result OnInitFunctionCount(Index count) override { return Result::Ok; } + Result OnInitFunction(uint32_t priority, Index function_index) override { + return Result::Ok; + } + Result OnComdatCount(Index count) override { return Result::Ok; } + Result OnComdatBegin(string_view name, uint32_t flags, Index count) override { + return Result::Ok; + } + Result OnComdatEntry(ComdatType kind, Index index) override { + return Result::Ok; + } + Result EndLinkingSection() override { return Result::Ok; } + + /* InitExpr - used by elem, data and global sections; these functions are + * only called between calls to Begin*InitExpr and End*InitExpr */ + Result OnInitExprF32ConstExpr(Index index, uint32_t value) override { + return Result::Ok; + } + Result OnInitExprF64ConstExpr(Index index, uint64_t value) override { + return Result::Ok; + } + Result OnInitExprV128ConstExpr(Index index, v128 value) override { + return Result::Ok; + } + Result OnInitExprGlobalGetExpr(Index index, Index global_index) override { + return Result::Ok; + } + Result OnInitExprI32ConstExpr(Index index, uint32_t value) override { + return Result::Ok; + } + Result OnInitExprI64ConstExpr(Index index, uint64_t value) override { + return Result::Ok; + } + Result OnInitExprRefNull(Index index, Type type) override { + return Result::Ok; + } + Result OnInitExprRefFunc(Index index, Index func_index) override { + return Result::Ok; + } +}; + +} // namespace wabt + +#endif /* WABT_BINARY_READER_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.cc new file mode 100644 index 0000000..64e7b42 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.cc @@ -0,0 +1,2029 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary-reader-objdump.h" + +#include +#include +#include +#include +#include +#include + +#if HAVE_STRCASECMP +#include +#endif + +#include "src/binary-reader-nop.h" +#include "src/filenames.h" +#include "src/literal.h" + +namespace wabt { + +namespace { + +class BinaryReaderObjdumpBase : public BinaryReaderNop { + public: + BinaryReaderObjdumpBase(const uint8_t* data, + size_t size, + ObjdumpOptions* options, + ObjdumpState* state); + + bool OnError(const Error&) override; + + Result BeginModule(uint32_t version) override; + Result BeginSection(Index section_index, + BinarySection section_type, + Offset size) override; + + Result OnRelocCount(Index count, Index section_index) override; + + protected: + string_view GetFunctionName(Index index) const; + string_view GetGlobalName(Index index) const; + string_view GetSectionName(Index index) const; + string_view GetEventName(Index index) const; + string_view GetSymbolName(Index index) const; + string_view GetSegmentName(Index index) const; + string_view GetTableName(Index index) const; + void PrintRelocation(const Reloc& reloc, Offset offset) const; + Offset GetSectionStart(BinarySection section_code) const { + return section_starts_[static_cast(section_code)]; + } + + ObjdumpOptions* options_; + ObjdumpState* objdump_state_; + const uint8_t* data_; + size_t size_; + bool print_details_ = false; + BinarySection reloc_section_ = BinarySection::Invalid; + Offset section_starts_[kBinarySectionCount]; + // Map of section index to section type + std::vector section_types_; + bool section_found_ = false; + std::string module_name_; + + std::unique_ptr err_stream_; +}; + +BinaryReaderObjdumpBase::BinaryReaderObjdumpBase(const uint8_t* data, + size_t size, + ObjdumpOptions* options, + ObjdumpState* objdump_state) + : options_(options), + objdump_state_(objdump_state), + data_(data), + size_(size), + err_stream_(FileStream::CreateStderr()) { + ZeroMemory(section_starts_); +} + +Result BinaryReaderObjdumpBase::BeginSection(Index section_index, + BinarySection section_code, + Offset size) { + section_starts_[static_cast(section_code)] = state->offset; + section_types_.push_back(section_code); + return Result::Ok; +} + +bool BinaryReaderObjdumpBase::OnError(const Error&) { + // Tell the BinaryReader that this error is "handled" for all passes other + // than the prepass. When the error is handled the default message will be + // suppressed. + return options_->mode != ObjdumpMode::Prepass; +} + +Result BinaryReaderObjdumpBase::BeginModule(uint32_t version) { + switch (options_->mode) { + case ObjdumpMode::Headers: + printf("\n"); + printf("Sections:\n\n"); + break; + case ObjdumpMode::Details: + printf("\n"); + printf("Section Details:\n\n"); + break; + case ObjdumpMode::Disassemble: + printf("\n"); + printf("Code Disassembly:\n\n"); + break; + case ObjdumpMode::Prepass: { + string_view basename = GetBasename(options_->filename); + if (basename == "-") { + basename = ""; + } + printf("%s:\tfile format wasm %#x\n", basename.to_string().c_str(), + version); + break; + } + case ObjdumpMode::RawData: + break; + } + + return Result::Ok; +} + +string_view BinaryReaderObjdumpBase::GetFunctionName(Index index) const { + return objdump_state_->function_names.Get(index); +} + +string_view BinaryReaderObjdumpBase::GetGlobalName(Index index) const { + return objdump_state_->global_names.Get(index); +} + +string_view BinaryReaderObjdumpBase::GetSectionName(Index index) const { + return objdump_state_->section_names.Get(index); +} + +string_view BinaryReaderObjdumpBase::GetEventName(Index index) const { + return objdump_state_->event_names.Get(index); +} + +string_view BinaryReaderObjdumpBase::GetSegmentName(Index index) const { + return objdump_state_->segment_names.Get(index); +} + +string_view BinaryReaderObjdumpBase::GetTableName(Index index) const { + return objdump_state_->table_names.Get(index); +} + +string_view BinaryReaderObjdumpBase::GetSymbolName(Index symbol_index) const { + if (symbol_index >= objdump_state_->symtab.size()) + return ""; + ObjdumpSymbol& sym = objdump_state_->symtab[symbol_index]; + switch (sym.kind) { + case SymbolType::Function: + return GetFunctionName(sym.index); + case SymbolType::Data: + return sym.name; + case SymbolType::Global: + return GetGlobalName(sym.index); + case SymbolType::Section: + return GetSectionName(sym.index); + case SymbolType::Event: + return GetEventName(sym.index); + case SymbolType::Table: + return GetTableName(sym.index); + } + WABT_UNREACHABLE; +} + +void BinaryReaderObjdumpBase::PrintRelocation(const Reloc& reloc, + Offset offset) const { + printf(" %06" PRIzx ": %-18s %" PRIindex, offset, + GetRelocTypeName(reloc.type), reloc.index); + if (reloc.addend) { + printf(" + %d", reloc.addend); + } + if (reloc.type != RelocType::TypeIndexLEB) { + printf(" <" PRIstringview ">", + WABT_PRINTF_STRING_VIEW_ARG(GetSymbolName(reloc.index))); + } + printf("\n"); +} + +Result BinaryReaderObjdumpBase::OnRelocCount(Index count, Index section_index) { + if (section_index >= section_types_.size()) { + err_stream_->Writef("invalid relocation section index: %" PRIindex "\n", + section_index); + reloc_section_ = BinarySection::Invalid; + return Result::Error; + } + reloc_section_ = section_types_[section_index]; + return Result::Ok; +} + +class BinaryReaderObjdumpPrepass : public BinaryReaderObjdumpBase { + public: + using BinaryReaderObjdumpBase::BinaryReaderObjdumpBase; + + Result BeginSection(Index section_index, + BinarySection section_code, + Offset size) override { + BinaryReaderObjdumpBase::BeginSection(section_index, section_code, size); + if (section_code != BinarySection::Custom) { + objdump_state_->section_names.Set(section_index, + wabt::GetSectionName(section_code)); + } + return Result::Ok; + } + + Result BeginCustomSection(Index section_index, + Offset size, + string_view section_name) override { + objdump_state_->section_names.Set(section_index, section_name); + return Result::Ok; + } + + Result OnFunctionName(Index index, string_view name) override { + SetFunctionName(index, name); + return Result::Ok; + } + + Result OnNameEntry(NameSectionSubsection type, + Index index, + string_view name) override { + switch (type) { + // TODO(sbc): remove OnFunctionName in favor of just using + // OnNameEntry so that this works + /* + case NameSectionSubsection::Function: + SetFunctionName(index, name); + break; + */ + case NameSectionSubsection::Global: + SetGlobalName(index, name); + break; + case NameSectionSubsection::Table: + SetTableName(index, name); + break; + case NameSectionSubsection::DataSegment: + SetSegmentName(index, name); + break; + default: + break; + } + return Result::Ok; + } + + Result OnSymbolCount(Index count) override { + objdump_state_->symtab.resize(count); + return Result::Ok; + } + + Result OnDataSymbol(Index index, + uint32_t flags, + string_view name, + Index segment, + uint32_t offset, + uint32_t size) override { + objdump_state_->symtab[index] = {SymbolType::Data, name.to_string(), 0}; + return Result::Ok; + } + + Result OnFunctionSymbol(Index index, + uint32_t flags, + string_view name, + Index func_index) override { + if (!name.empty()) { + SetFunctionName(func_index, name); + } + objdump_state_->symtab[index] = {SymbolType::Function, name.to_string(), + func_index}; + return Result::Ok; + } + + Result OnGlobalSymbol(Index index, + uint32_t flags, + string_view name, + Index global_index) override { + if (!name.empty()) { + SetGlobalName(global_index, name); + } + objdump_state_->symtab[index] = {SymbolType::Global, name.to_string(), + global_index}; + return Result::Ok; + } + + Result OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) override { + objdump_state_->symtab[index] = {SymbolType::Section, + std::string(GetSectionName(section_index)), + section_index}; + return Result::Ok; + } + + Result OnEventSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) override { + if (!name.empty()) { + SetEventName(event_index, name); + } + objdump_state_->symtab[index] = {SymbolType::Event, name.to_string(), + event_index}; + return Result::Ok; + } + + Result OnTableSymbol(Index index, + uint32_t flags, + string_view name, + Index table_index) override { + if (!name.empty()) { + SetTableName(table_index, name); + } + objdump_state_->symtab[index] = {SymbolType::Table, name.to_string(), + table_index}; + return Result::Ok; + } + + Result OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) override { + SetFunctionName(func_index, + module_name.to_string() + "." + field_name.to_string()); + return Result::Ok; + } + + Result OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) override { + SetEventName(event_index, + module_name.to_string() + "." + field_name.to_string()); + return Result::Ok; + } + + Result OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) override { + SetGlobalName(global_index, + module_name.to_string() + "." + field_name.to_string()); + return Result::Ok; + } + + Result OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) override { + SetTableName(table_index, + module_name.to_string() + "." + field_name.to_string()); + return Result::Ok; + } + + Result OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) override { + if (kind == ExternalKind::Func) { + SetFunctionName(item_index, name); + } else if (kind == ExternalKind::Global) { + SetGlobalName(item_index, name); + } + return Result::Ok; + } + + Result OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) override; + + Result OnModuleName(string_view name) override { + if (options_->mode == ObjdumpMode::Prepass) { + printf("module name: <" PRIstringview ">\n", + WABT_PRINTF_STRING_VIEW_ARG(name)); + } + return Result::Ok; + } + + Result OnSegmentInfo(Index index, + string_view name, + Address alignment_log2, + uint32_t flags) override { + SetSegmentName(index, name); + return Result::Ok; + } + + protected: + void SetFunctionName(Index index, string_view name); + void SetGlobalName(Index index, string_view name); + void SetEventName(Index index, string_view name); + void SetTableName(Index index, string_view name); + void SetSegmentName(Index index, string_view name); +}; + +void BinaryReaderObjdumpPrepass::SetFunctionName(Index index, + string_view name) { + objdump_state_->function_names.Set(index, name); +} + +void BinaryReaderObjdumpPrepass::SetGlobalName(Index index, string_view name) { + objdump_state_->global_names.Set(index, name); +} + +void BinaryReaderObjdumpPrepass::SetEventName(Index index, string_view name) { + objdump_state_->event_names.Set(index, name); +} + +void BinaryReaderObjdumpPrepass::SetTableName(Index index, string_view name) { + objdump_state_->table_names.Set(index, name); +} + +void BinaryReaderObjdumpPrepass::SetSegmentName(Index index, string_view name) { + objdump_state_->segment_names.Set(index, name); +} + +Result BinaryReaderObjdumpPrepass::OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) { + BinaryReaderObjdumpBase::OnReloc(type, offset, index, addend); + if (reloc_section_ == BinarySection::Code) { + objdump_state_->code_relocations.emplace_back(type, offset, index, addend); + } else if (reloc_section_ == BinarySection::Data) { + objdump_state_->data_relocations.emplace_back(type, offset, index, addend); + } + return Result::Ok; +} + +class BinaryReaderObjdumpDisassemble : public BinaryReaderObjdumpBase { + public: + using BinaryReaderObjdumpBase::BinaryReaderObjdumpBase; + + std::string BlockSigToString(Type type) const; + + Result BeginFunctionBody(Index index, Offset size) override; + + Result OnLocalDeclCount(Index count) override; + Result OnLocalDecl(Index decl_index, Index count, Type type) override; + + Result OnOpcode(Opcode Opcode) override; + Result OnOpcodeBare() override; + Result OnOpcodeIndex(Index value) override; + Result OnOpcodeIndexIndex(Index value, Index value2) override; + Result OnOpcodeUint32(uint32_t value) override; + Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override; + Result OnOpcodeUint64(uint64_t value) override; + Result OnOpcodeF32(uint32_t value) override; + Result OnOpcodeF64(uint64_t value) override; + Result OnOpcodeV128(v128 value) override; + Result OnOpcodeBlockSig(Type sig_type) override; + Result OnOpcodeType(Type type) override; + + Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) override; + Result OnDelegateExpr(Index) override; + Result OnEndExpr() override; + Result OnEndFunc() override; + + private: + void LogOpcode(size_t data_size, const char* fmt, ...); + + Opcode current_opcode = Opcode::Unreachable; + Offset current_opcode_offset = 0; + Offset last_opcode_end = 0; + int indent_level = 0; + Index next_reloc = 0; + Index local_index_ = 0; +}; + +std::string BinaryReaderObjdumpDisassemble::BlockSigToString(Type type) const { + if (type.IsIndex()) { + return StringPrintf("type[%d]", type.GetIndex()); + } else if (type == Type::Void) { + return ""; + } else { + return type.GetName(); + } +} + +Result BinaryReaderObjdumpDisassemble::OnOpcode(Opcode opcode) { + if (options_->debug) { + const char* opcode_name = opcode.GetName(); + err_stream_->Writef("on_opcode: %#" PRIzx ": %s\n", state->offset, + opcode_name); + } + + if (last_opcode_end) { + if (state->offset != last_opcode_end + opcode.GetLength()) { + Opcode missing_opcode = Opcode::FromCode(data_[last_opcode_end]); + const char* opcode_name = missing_opcode.GetName(); + fprintf(stderr, + "warning: %#" PRIzx " missing opcode callback at %#" PRIzx + " (%#02x=%s)\n", + state->offset, last_opcode_end + 1, data_[last_opcode_end], + opcode_name); + return Result::Error; + } + } + + current_opcode_offset = state->offset; + current_opcode = opcode; + return Result::Ok; +} + +#define IMMEDIATE_OCTET_COUNT 9 + +Result BinaryReaderObjdumpDisassemble::OnLocalDeclCount(Index count) { + local_index_ = 0; + current_opcode_offset = state->offset; + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnLocalDecl(Index decl_index, + Index count, + Type type) { + Offset offset = current_opcode_offset; + size_t data_size = state->offset - offset; + + printf(" %06" PRIzx ":", offset); + for (size_t i = 0; i < data_size && i < IMMEDIATE_OCTET_COUNT; + i++, offset++) { + printf(" %02x", data_[offset]); + } + for (size_t i = data_size; i < IMMEDIATE_OCTET_COUNT; i++) { + printf(" "); + } + printf(" | local[%" PRIindex, local_index_); + + if (count != 1) { + printf("..%" PRIindex "", local_index_ + count - 1); + } + local_index_ += count; + + printf("] type=%s\n", type.GetName()); + + last_opcode_end = current_opcode_offset + data_size; + current_opcode_offset = last_opcode_end; + + return Result::Ok; +} + +void BinaryReaderObjdumpDisassemble::LogOpcode(size_t data_size, + const char* fmt, + ...) { + const Offset opcode_size = current_opcode.GetLength(); + const Offset total_size = opcode_size + data_size; + // current_opcode_offset has already read past this opcode; rewind it by the + // size of this opcode, which may be more than one byte. + Offset offset = current_opcode_offset - opcode_size; + const Offset offset_end = offset + total_size; + + bool first_line = true; + while (offset < offset_end) { + // Print bytes, but only display a maximum of IMMEDIATE_OCTET_COUNT on each + // line. + printf(" %06" PRIzx ":", offset); + size_t i; + for (i = 0; offset < offset_end && i < IMMEDIATE_OCTET_COUNT; + ++i, ++offset) { + printf(" %02x", data_[offset]); + } + // Fill the rest of the remaining space with spaces. + for (; i < IMMEDIATE_OCTET_COUNT; ++i) { + printf(" "); + } + printf(" | "); + + if (first_line) { + first_line = false; + + // Print disassembly. + int indent_level = this->indent_level; + switch (current_opcode) { + case Opcode::Else: + case Opcode::Catch: + case Opcode::CatchAll: + case Opcode::Unwind: + indent_level--; + default: + break; + } + for (int j = 0; j < indent_level; j++) { + printf(" "); + } + + const char* opcode_name = current_opcode.GetName(); + printf("%s", opcode_name); + if (fmt) { + printf(" "); + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + } + } + + printf("\n"); + } + + last_opcode_end = offset_end; + + // Print relocation after then full (potentially multi-line) instruction. + if (options_->relocs && + next_reloc < objdump_state_->code_relocations.size()) { + const Reloc& reloc = objdump_state_->code_relocations[next_reloc]; + Offset code_start = GetSectionStart(BinarySection::Code); + Offset abs_offset = code_start + reloc.offset; + if (last_opcode_end > abs_offset) { + PrintRelocation(reloc, abs_offset); + next_reloc++; + } + } +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeBare() { + LogOpcode(0, nullptr); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeIndex(Index value) { + Offset immediate_len = state->offset - current_opcode_offset; + string_view name; + if (current_opcode == Opcode::Call && + !(name = GetFunctionName(value)).empty()) { + LogOpcode(immediate_len, "%d <" PRIstringview ">", value, + WABT_PRINTF_STRING_VIEW_ARG(name)); + } else if ((current_opcode == Opcode::GlobalGet || + current_opcode == Opcode::GlobalSet) && + !(name = GetGlobalName(value)).empty()) { + LogOpcode(immediate_len, "%d <" PRIstringview ">", value, + WABT_PRINTF_STRING_VIEW_ARG(name)); + } else { + LogOpcode(immediate_len, "%d", value); + } + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeIndexIndex(Index value, + Index value2) { + Offset immediate_len = state->offset - current_opcode_offset; + LogOpcode(immediate_len, "%" PRIindex " %" PRIindex, value, value2); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32(uint32_t value) { + Offset immediate_len = state->offset - current_opcode_offset; + string_view name; + if (current_opcode == Opcode::DataDrop && + !(name = GetSegmentName(value)).empty()) { + LogOpcode(immediate_len, "%d <" PRIstringview ">", value, + WABT_PRINTF_STRING_VIEW_ARG(name)); + } else { + LogOpcode(immediate_len, "%u", value); + } + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeUint32Uint32(uint32_t value, + uint32_t value2) { + Offset immediate_len = state->offset - current_opcode_offset; + string_view name; + if (current_opcode == Opcode::MemoryInit && + !(name = GetSegmentName(value)).empty()) { + LogOpcode(immediate_len, "%u %u <" PRIstringview ">", value, value2, + WABT_PRINTF_STRING_VIEW_ARG(name)); + } else { + LogOpcode(immediate_len, "%u %u", value, value2); + } + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeUint64(uint64_t value) { + Offset immediate_len = state->offset - current_opcode_offset; + LogOpcode(immediate_len, "%" PRId64, value); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeF32(uint32_t value) { + Offset immediate_len = state->offset - current_opcode_offset; + char buffer[WABT_MAX_FLOAT_HEX]; + WriteFloatHex(buffer, sizeof(buffer), value); + LogOpcode(immediate_len, buffer); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeF64(uint64_t value) { + Offset immediate_len = state->offset - current_opcode_offset; + char buffer[WABT_MAX_DOUBLE_HEX]; + WriteDoubleHex(buffer, sizeof(buffer), value); + LogOpcode(immediate_len, buffer); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeV128(v128 value) { + Offset immediate_len = state->offset - current_opcode_offset; + // v128 is always dumped as i32x4: + LogOpcode(immediate_len, "0x%08x 0x%08x 0x%08x 0x%08x", value.u32(0), + value.u32(1), value.u32(2), value.u32(3)); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeType(Type type) { + Offset immediate_len = state->offset - current_opcode_offset; + LogOpcode(immediate_len, type.GetRefKindName()); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnBrTableExpr( + Index num_targets, + Index* target_depths, + Index default_target_depth) { + Offset immediate_len = state->offset - current_opcode_offset; + + std::string buffer = std::string(); + for (Index i = 0; i < num_targets; i++) { + buffer.append(std::to_string(target_depths[i])).append(" "); + } + buffer.append(std::to_string(default_target_depth)); + + LogOpcode(immediate_len, "%s", buffer.c_str()); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnDelegateExpr(Index depth) { + // Because `delegate` ends the block we need to dedent here, and + // we don't need to dedent it in LogOpcode. + if (indent_level > 0) { + indent_level--; + } + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnEndFunc() { + LogOpcode(0, nullptr); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnEndExpr() { + if (indent_level > 0) { + indent_level--; + } + LogOpcode(0, nullptr); + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::BeginFunctionBody(Index index, + Offset size) { + printf("%06" PRIzx " func[%" PRIindex "]", state->offset, index); + auto name = GetFunctionName(index); + if (!name.empty()) { + printf(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + printf(":\n"); + + last_opcode_end = 0; + return Result::Ok; +} + +Result BinaryReaderObjdumpDisassemble::OnOpcodeBlockSig(Type sig_type) { + Offset immediate_len = state->offset - current_opcode_offset; + if (sig_type != Type::Void) { + LogOpcode(immediate_len, "%s", BlockSigToString(sig_type).c_str()); + } else { + LogOpcode(immediate_len, nullptr); + } + indent_level++; + return Result::Ok; +} + +enum class InitExprType { + I32, + F32, + I64, + F64, + V128, + Global, + FuncRef, + // TODO: There isn't a nullref anymore, this just represents ref.null of some + // type T. + NullRef, +}; + +struct InitExpr { + InitExprType type; + union { + Index index; + uint32_t i32; + uint32_t f32; + uint64_t i64; + uint64_t f64; + v128 v128_v; + Type type; + } value; +}; + +class BinaryReaderObjdump : public BinaryReaderObjdumpBase { + public: + BinaryReaderObjdump(const uint8_t* data, + size_t size, + ObjdumpOptions* options, + ObjdumpState* state); + + Result EndModule() override; + Result BeginSection(Index section_index, + BinarySection section_type, + Offset size) override; + Result BeginCustomSection(Index section_index, + Offset size, + string_view section_name) override; + + Result OnTypeCount(Index count) override; + Result OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) override; + Result OnStructType(Index index, Index field_count, TypeMut* fields) override; + Result OnArrayType(Index index, TypeMut field) override; + + Result OnImportCount(Index count) override; + Result OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) override; + Result OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) override; + Result OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) override; + Result OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) override; + Result OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) override; + + Result OnFunctionCount(Index count) override; + Result OnFunction(Index index, Index sig_index) override; + + Result OnTableCount(Index count) override; + Result OnTable(Index index, + Type elem_type, + const Limits* elem_limits) override; + + Result OnMemoryCount(Index count) override; + Result OnMemory(Index index, const Limits* limits) override; + + Result OnGlobalCount(Index count) override; + Result BeginGlobal(Index index, Type type, bool mutable_) override; + + Result OnExportCount(Index count) override; + Result OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) override; + + Result OnStartFunction(Index func_index) override; + Result OnDataCount(Index count) override; + + Result OnFunctionBodyCount(Index count) override; + Result BeginFunctionBody(Index index, Offset size) override; + + Result BeginElemSection(Offset size) override { + in_elem_section_ = true; + return Result::Ok; + } + Result EndElemSection() override { + in_elem_section_ = false; + return Result::Ok; + } + + Result OnElemSegmentCount(Index count) override; + Result BeginElemSegment(Index index, + Index table_index, + uint8_t flags) override; + Result OnElemSegmentElemType(Index index, Type elem_type) override; + Result OnElemSegmentElemExprCount(Index index, Index count) override; + Result OnElemSegmentElemExpr_RefNull(Index segment_index, Type type) override; + Result OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) override; + + Result BeginDataSection(Offset size) override { + in_data_section_ = true; + return Result::Ok; + } + Result EndDataSection() override { + in_data_section_ = false; + return Result::Ok; + } + + Result OnDataSegmentCount(Index count) override; + Result BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) override; + Result OnDataSegmentData(Index index, + const void* data, + Address size) override; + + Result OnModuleName(string_view name) override; + Result OnFunctionName(Index function_index, + string_view function_name) override; + Result OnLocalName(Index function_index, + Index local_index, + string_view local_name) override; + Result OnNameEntry(NameSectionSubsection type, + Index index, + string_view name) override; + + Result OnInitExprF32ConstExpr(Index index, uint32_t value) override; + Result OnInitExprF64ConstExpr(Index index, uint64_t value) override; + Result OnInitExprV128ConstExpr(Index index, v128 value) override; + Result OnInitExprGlobalGetExpr(Index index, Index global_index) override; + Result OnInitExprI32ConstExpr(Index index, uint32_t value) override; + Result OnInitExprI64ConstExpr(Index index, uint64_t value) override; + Result OnInitExprRefNull(Index index, Type type) override; + Result OnInitExprRefFunc(Index index, Index func_index) override; + + Result OnDylinkInfo(uint32_t mem_size, + uint32_t mem_align_log2, + uint32_t table_size, + uint32_t table_align_log2) override; + Result OnDylinkNeededCount(Index count) override; + Result OnDylinkNeeded(string_view so_name) override; + + Result OnRelocCount(Index count, Index section_index) override; + Result OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) override; + + Result OnSymbolCount(Index count) override; + Result OnDataSymbol(Index index, + uint32_t flags, + string_view name, + Index segment, + uint32_t offset, + uint32_t size) override; + Result OnFunctionSymbol(Index index, + uint32_t flags, + string_view name, + Index func_index) override; + Result OnGlobalSymbol(Index index, + uint32_t flags, + string_view name, + Index global_index) override; + Result OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) override; + Result OnEventSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) override; + Result OnTableSymbol(Index index, + uint32_t flags, + string_view name, + Index table_index) override; + Result OnSegmentInfoCount(Index count) override; + Result OnSegmentInfo(Index index, + string_view name, + Address alignment_log2, + uint32_t flags) override; + Result OnInitFunctionCount(Index count) override; + Result OnInitFunction(uint32_t priority, Index function_index) override; + Result OnComdatCount(Index count) override; + Result OnComdatBegin(string_view name, uint32_t flags, Index count) override; + Result OnComdatEntry(ComdatType kind, Index index) override; + Result EndLinkingSection() override { return Result::Ok; } + + Result OnEventCount(Index count) override; + Result OnEventType(Index index, Index sig_index) override; + + private: + Result InitExprToConstOffset(const InitExpr& expr, uint32_t* out_offset); + Result HandleInitExpr(const InitExpr& expr); + bool ShouldPrintDetails(); + void PrintDetails(const char* fmt, ...); + Result PrintSymbolFlags(uint32_t flags); + void PrintInitExpr(const InitExpr& expr); + Result OnCount(Index count); + + std::unique_ptr out_stream_; + Index elem_index_ = 0; + Index table_index_ = 0; + Index next_data_reloc_ = 0; + bool in_data_section_ = false; + bool in_elem_section_ = false; + InitExpr data_init_expr_; + InitExpr elem_init_expr_; + uint8_t data_flags_ = 0; + uint8_t elem_flags_ = 0; + Index data_mem_index_ = 0; + uint32_t data_offset_ = 0; + uint32_t elem_offset_ = 0; +}; + +BinaryReaderObjdump::BinaryReaderObjdump(const uint8_t* data, + size_t size, + ObjdumpOptions* options, + ObjdumpState* objdump_state) + : BinaryReaderObjdumpBase(data, size, options, objdump_state), + out_stream_(FileStream::CreateStdout()) {} + +Result BinaryReaderObjdump::BeginCustomSection(Index section_index, + Offset size, + string_view section_name) { + PrintDetails(" - name: \"" PRIstringview "\"\n", + WABT_PRINTF_STRING_VIEW_ARG(section_name)); + if (options_->mode == ObjdumpMode::Headers) { + printf("\"" PRIstringview "\"\n", + WABT_PRINTF_STRING_VIEW_ARG(section_name)); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::BeginSection(Index section_index, + BinarySection section_code, + Offset size) { + BinaryReaderObjdumpBase::BeginSection(section_index, section_code, size); + + // |section_name| and |match_name| are identical for known sections. For + // custom sections, |section_name| is "Custom", but |match_name| is the name + // of the custom section. + const char* section_name = wabt::GetSectionName(section_code); + std::string match_name = GetSectionName(section_index).to_string(); + + bool section_match = !options_->section_name || + !strcasecmp(options_->section_name, match_name.c_str()); + if (section_match) { + section_found_ = true; + } + + switch (options_->mode) { + case ObjdumpMode::Headers: + printf("%9s start=%#010" PRIzx " end=%#010" PRIzx " (size=%#010" PRIoffset + ") ", + section_name, state->offset, state->offset + size, size); + break; + case ObjdumpMode::Details: + if (section_match) { + printf("%s", section_name); + // All known section types except the Start and DataCount sections have + // a count in which case this line gets completed in OnCount(). + if (section_code == BinarySection::Start || + section_code == BinarySection::DataCount || + section_code == BinarySection::Custom) { + printf(":\n"); + } + print_details_ = true; + } else { + print_details_ = false; + } + break; + case ObjdumpMode::RawData: + if (section_match) { + printf("\nContents of section %s:\n", section_name); + out_stream_->WriteMemoryDump(data_ + state->offset, size, state->offset, + PrintChars::Yes); + } + break; + case ObjdumpMode::Prepass: + case ObjdumpMode::Disassemble: + break; + } + return Result::Ok; +} + +bool BinaryReaderObjdump::ShouldPrintDetails() { + if (options_->mode != ObjdumpMode::Details) { + return false; + } + return print_details_; +} + +void WABT_PRINTF_FORMAT(2, 3) BinaryReaderObjdump::PrintDetails(const char* fmt, + ...) { + if (!ShouldPrintDetails()) { + return; + } + va_list args; + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); +} + +Result BinaryReaderObjdump::OnCount(Index count) { + if (options_->mode == ObjdumpMode::Headers) { + printf("count: %" PRIindex "\n", count); + } else if (options_->mode == ObjdumpMode::Details && print_details_) { + printf("[%" PRIindex "]:\n", count); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::EndModule() { + if (options_->section_name && !section_found_) { + err_stream_->Writef("Section not found: %s\n", options_->section_name); + return Result::Error; + } + + if (options_->relocs) { + if (next_data_reloc_ != objdump_state_->data_relocations.size()) { + err_stream_->Writef("Data reloctions outside of segments\n"); + return Result::Error; + } + } + + return Result::Ok; +} + +Result BinaryReaderObjdump::OnTypeCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) { + if (!ShouldPrintDetails()) { + return Result::Ok; + } + printf(" - type[%" PRIindex "] (", index); + for (Index i = 0; i < param_count; i++) { + if (i != 0) { + printf(", "); + } + printf("%s", param_types[i].GetName()); + } + printf(") -> "); + switch (result_count) { + case 0: + printf("nil"); + break; + case 1: + printf("%s", result_types[0].GetName()); + break; + default: + printf("("); + for (Index i = 0; i < result_count; i++) { + if (i != 0) { + printf(", "); + } + printf("%s", result_types[i].GetName()); + } + printf(")"); + break; + } + printf("\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnStructType(Index index, + Index field_count, + TypeMut* fields) { + if (!ShouldPrintDetails()) { + return Result::Ok; + } + printf(" - type[%" PRIindex "] (struct", index); + for (Index i = 0; i < field_count; i++) { + if (fields[i].mutable_) { + printf(" (mut"); + } + printf(" %s", fields[i].type.GetName()); + if (fields[i].mutable_) { + printf(")"); + } + } + printf(")\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnArrayType(Index index, TypeMut field) { + if (!ShouldPrintDetails()) { + return Result::Ok; + } + printf(" - type[%" PRIindex "] (array", index); + if (field.mutable_) { + printf(" (mut"); + } + printf(" %s", field.type.GetName()); + if (field.mutable_) { + printf(")"); + } + printf(")\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnFunctionCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::OnFunction(Index index, Index sig_index) { + PrintDetails(" - func[%" PRIindex "] sig=%" PRIindex, index, sig_index); + auto name = GetFunctionName(index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails("\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnFunctionBodyCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::BeginFunctionBody(Index index, Offset size) { + PrintDetails(" - func[%" PRIindex "] size=%" PRIzd, index, size); + auto name = GetFunctionName(index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails("\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnStartFunction(Index func_index) { + if (options_->mode == ObjdumpMode::Headers) { + printf("start: %" PRIindex "\n", func_index); + } else { + PrintDetails(" - start function: %" PRIindex, func_index); + auto name = GetFunctionName(func_index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails("\n"); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::OnDataCount(Index count) { + if (options_->mode == ObjdumpMode::Headers) { + printf("count: %" PRIindex "\n", count); + } else { + PrintDetails(" - data count: %" PRIindex "\n", count); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::OnImportCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) { + PrintDetails(" - func[%" PRIindex "] sig=%" PRIindex, func_index, sig_index); + auto name = GetFunctionName(func_index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails(" <- " PRIstringview "." PRIstringview "\n", + WABT_PRINTF_STRING_VIEW_ARG(module_name), + WABT_PRINTF_STRING_VIEW_ARG(field_name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) { + PrintDetails(" - table[%" PRIindex "] type=%s initial=%" PRId64, table_index, + elem_type.GetName(), elem_limits->initial); + if (elem_limits->has_max) { + PrintDetails(" max=%" PRId64, elem_limits->max); + } + PrintDetails(" <- " PRIstringview "." PRIstringview "\n", + WABT_PRINTF_STRING_VIEW_ARG(module_name), + WABT_PRINTF_STRING_VIEW_ARG(field_name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) { + PrintDetails(" - memory[%" PRIindex "] pages: initial=%" PRId64, memory_index, + page_limits->initial); + if (page_limits->has_max) { + PrintDetails(" max=%" PRId64, page_limits->max); + } + if (page_limits->is_shared) { + PrintDetails(" shared"); + } + if (page_limits->is_64) { + PrintDetails(" i64"); + } + PrintDetails(" <- " PRIstringview "." PRIstringview "\n", + WABT_PRINTF_STRING_VIEW_ARG(module_name), + WABT_PRINTF_STRING_VIEW_ARG(field_name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) { + PrintDetails(" - global[%" PRIindex "] %s mutable=%d", global_index, + type.GetName(), mutable_); + PrintDetails(" <- " PRIstringview "." PRIstringview "\n", + WABT_PRINTF_STRING_VIEW_ARG(module_name), + WABT_PRINTF_STRING_VIEW_ARG(field_name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) { + PrintDetails(" - event[%" PRIindex "] sig=%" PRIindex, event_index, + sig_index); + auto name = GetEventName(event_index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails(" <- " PRIstringview "." PRIstringview "\n", + WABT_PRINTF_STRING_VIEW_ARG(module_name), + WABT_PRINTF_STRING_VIEW_ARG(field_name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnMemoryCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::OnMemory(Index index, const Limits* page_limits) { + PrintDetails(" - memory[%" PRIindex "] pages: initial=%" PRId64, index, + page_limits->initial); + if (page_limits->has_max) { + PrintDetails(" max=%" PRId64, page_limits->max); + } + if (page_limits->is_shared) { + PrintDetails(" shared"); + } + if (page_limits->is_64) { + PrintDetails(" i64"); + } + PrintDetails("\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnTableCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::OnTable(Index index, + Type elem_type, + const Limits* elem_limits) { + PrintDetails(" - table[%" PRIindex "] type=%s initial=%" PRId64, index, + elem_type.GetName(), elem_limits->initial); + if (elem_limits->has_max) { + PrintDetails(" max=%" PRId64, elem_limits->max); + } + auto name = GetTableName(index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails("\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnExportCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) { + PrintDetails(" - %s[%" PRIindex "]", GetKindName(kind), item_index); + if (kind == ExternalKind::Func) { + auto name = GetFunctionName(item_index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + } + + PrintDetails(" -> \"" PRIstringview "\"\n", + WABT_PRINTF_STRING_VIEW_ARG(name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnElemSegmentElemExpr_RefNull(Index segment_index, + Type type) { + PrintDetails(" - elem[%" PRIindex "] = ref.null %s\n", + elem_offset_ + elem_index_, type.GetName()); + elem_index_++; + return Result::Ok; +} + +Result BinaryReaderObjdump::OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) { + PrintDetails(" - elem[%" PRIindex "] = func[%" PRIindex "]", + elem_offset_ + elem_index_, func_index); + auto name = GetFunctionName(func_index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails("\n"); + elem_index_++; + return Result::Ok; +} + +Result BinaryReaderObjdump::OnElemSegmentCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::BeginElemSegment(Index index, + Index table_index, + uint8_t flags) { + table_index_ = table_index; + elem_index_ = 0; + elem_flags_ = flags; + return Result::Ok; +} + +Result BinaryReaderObjdump::OnElemSegmentElemType(Index index, Type elem_type) { + // TODO: Add support for this. + return Result::Ok; +} + +Result BinaryReaderObjdump::OnElemSegmentElemExprCount(Index index, + Index count) { + PrintDetails(" - segment[%" PRIindex "] flags=%d table=%" PRIindex + " count=%" PRIindex, + index, elem_flags_, table_index_, count); + if (elem_flags_ & SegPassive) { + PrintDetails("\n"); + } else { + PrintInitExpr(elem_init_expr_); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::OnGlobalCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::BeginGlobal(Index index, Type type, bool mutable_) { + PrintDetails(" - global[%" PRIindex "] %s mutable=%d", index, type.GetName(), + mutable_); + string_view name = GetGlobalName(index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + return Result::Ok; +} + +void BinaryReaderObjdump::PrintInitExpr(const InitExpr& expr) { + switch (expr.type) { + case InitExprType::I32: + PrintDetails(" - init i32=%d\n", expr.value.i32); + break; + case InitExprType::I64: + PrintDetails(" - init i64=%" PRId64 "\n", expr.value.i64); + break; + case InitExprType::F64: { + char buffer[WABT_MAX_DOUBLE_HEX]; + WriteDoubleHex(buffer, sizeof(buffer), expr.value.f64); + PrintDetails(" - init f64=%s\n", buffer); + break; + } + case InitExprType::F32: { + char buffer[WABT_MAX_FLOAT_HEX]; + WriteFloatHex(buffer, sizeof(buffer), expr.value.f32); + PrintDetails(" - init f32=%s\n", buffer); + break; + } + case InitExprType::V128: { + PrintDetails(" - init v128=0x%08x 0x%08x 0x%08x 0x%08x \n", + expr.value.v128_v.u32(0), expr.value.v128_v.u32(1), + expr.value.v128_v.u32(2), expr.value.v128_v.u32(3)); + break; + } + case InitExprType::Global: { + PrintDetails(" - init global=%" PRIindex, expr.value.index); + string_view name = GetGlobalName(expr.value.index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails("\n"); + break; + } + case InitExprType::FuncRef: { + PrintDetails(" - init ref.func:%" PRIindex, expr.value.index); + string_view name = GetFunctionName(expr.value.index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + PrintDetails("\n"); + break; + } + case InitExprType::NullRef: { + PrintDetails(" - init null\n"); + break; + } + } +} + +Result BinaryReaderObjdump::InitExprToConstOffset(const InitExpr& expr, + uint32_t* out_offset) { + switch (expr.type) { + case InitExprType::I32: + *out_offset = expr.value.i32; + break; + case InitExprType::Global: + *out_offset = 0; + break; + case InitExprType::I64: + case InitExprType::F32: + case InitExprType::F64: + case InitExprType::V128: + case InitExprType::FuncRef: + case InitExprType::NullRef: + err_stream_->Writef("Segment/Elem offset must be an i32 init expr"); + return Result::Error; + break; + } + return Result::Ok; +} + +Result BinaryReaderObjdump::HandleInitExpr(const InitExpr& expr) { + if (in_data_section_) { + data_init_expr_ = expr; + return InitExprToConstOffset(expr, &data_offset_); + } else if (in_elem_section_) { + elem_init_expr_ = expr; + return InitExprToConstOffset(expr, &elem_offset_); + } else { + PrintInitExpr(expr); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprF32ConstExpr(Index index, + uint32_t value) { + InitExpr expr; + expr.type = InitExprType::F32; + expr.value.f32 = value; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprF64ConstExpr(Index index, + uint64_t value) { + InitExpr expr; + expr.type = InitExprType::F64; + expr.value.f64 = value; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprV128ConstExpr(Index index, v128 value) { + InitExpr expr; + expr.type = InitExprType::V128; + expr.value.v128_v = value; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprGlobalGetExpr(Index index, + Index global_index) { + InitExpr expr; + expr.type = InitExprType::Global; + expr.value.index = global_index; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprI32ConstExpr(Index index, + uint32_t value) { + InitExpr expr; + expr.type = InitExprType::I32; + expr.value.i32 = value; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprI64ConstExpr(Index index, + uint64_t value) { + InitExpr expr; + expr.type = InitExprType::I64; + expr.value.i64 = value; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprRefNull(Index index, Type type) { + InitExpr expr; + expr.type = InitExprType::NullRef; + expr.value.type = type; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitExprRefFunc(Index index, Index func_index) { + InitExpr expr{InitExprType::FuncRef, {func_index}}; + HandleInitExpr(expr); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnModuleName(string_view name) { + PrintDetails(" - module <" PRIstringview ">\n", + WABT_PRINTF_STRING_VIEW_ARG(name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnFunctionName(Index index, string_view name) { + PrintDetails(" - func[%" PRIindex "] <" PRIstringview ">\n", index, + WABT_PRINTF_STRING_VIEW_ARG(name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnNameEntry(NameSectionSubsection type, + Index index, + string_view name) { + PrintDetails(" - %s[%" PRIindex "] <" PRIstringview ">\n", + GetNameSectionSubsectionName(type), index, + WABT_PRINTF_STRING_VIEW_ARG(name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnLocalName(Index func_index, + Index local_index, + string_view name) { + if (!name.empty()) { + PrintDetails(" - func[%" PRIindex "] local[%" PRIindex "] <" PRIstringview + ">\n", + func_index, local_index, WABT_PRINTF_STRING_VIEW_ARG(name)); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::OnDataSegmentCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) { + data_mem_index_ = memory_index; + data_flags_ = flags; + return Result::Ok; +} + +Result BinaryReaderObjdump::OnDataSegmentData(Index index, + const void* src_data, + Address size) { + if (!ShouldPrintDetails()) { + return Result::Ok; + } + + PrintDetails(" - segment[%" PRIindex "]", index); + auto name = GetSegmentName(index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + if (data_flags_ & SegPassive) { + PrintDetails(" passive"); + } else { + PrintDetails(" memory=%" PRIindex, data_mem_index_); + } + PrintDetails(" size=%" PRIaddress, size); + if (data_flags_ & SegPassive) { + PrintDetails("\n"); + } else { + PrintInitExpr(data_init_expr_); + } + + out_stream_->WriteMemoryDump(src_data, size, data_offset_, PrintChars::Yes, + " - "); + + // Print relocations from this segment. + if (!options_->relocs) { + return Result::Ok; + } + + Offset data_start = GetSectionStart(BinarySection::Data); + Offset segment_start = state->offset - size; + Offset segment_offset = segment_start - data_start; + while (next_data_reloc_ < objdump_state_->data_relocations.size()) { + const Reloc& reloc = objdump_state_->data_relocations[next_data_reloc_]; + Offset abs_offset = data_start + reloc.offset; + if (abs_offset > state->offset) { + break; + } + PrintRelocation(reloc, reloc.offset - segment_offset + data_offset_); + next_data_reloc_++; + } + + return Result::Ok; +} + +Result BinaryReaderObjdump::OnDylinkInfo(uint32_t mem_size, + uint32_t mem_align_log2, + uint32_t table_size, + uint32_t table_align_log2) { + PrintDetails(" - mem_size : %u\n", mem_size); + PrintDetails(" - mem_p2align : %u\n", mem_align_log2); + PrintDetails(" - table_size : %u\n", table_size); + PrintDetails(" - table_p2align: %u\n", table_align_log2); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnDylinkNeededCount(Index count) { + if (count) { + PrintDetails(" - needed_dynlibs[%u]:\n", count); + } + return Result::Ok; +} + +Result BinaryReaderObjdump::OnDylinkNeeded(string_view so_name) { + PrintDetails(" - " PRIstringview "\n", WABT_PRINTF_STRING_VIEW_ARG(so_name)); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnRelocCount(Index count, Index section_index) { + BinaryReaderObjdumpBase::OnRelocCount(count, section_index); + PrintDetails(" - relocations for section: %d (" PRIstringview ") [%d]\n", + section_index, + WABT_PRINTF_STRING_VIEW_ARG(GetSectionName(section_index)), + count); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) { + Offset total_offset = GetSectionStart(reloc_section_) + offset; + PrintDetails(" - %-18s offset=%#08" PRIoffset "(file=%#08" PRIoffset ") ", + GetRelocTypeName(type), offset, total_offset); + if (type == RelocType::TypeIndexLEB) { + PrintDetails("type=%" PRIindex, index); + } else { + PrintDetails("symbol=%" PRIindex " <" PRIstringview ">", index, + WABT_PRINTF_STRING_VIEW_ARG(GetSymbolName(index))); + } + + if (addend) { + int32_t signed_addend = static_cast(addend); + if (signed_addend < 0) { + PrintDetails("-"); + signed_addend = -signed_addend; + } else { + PrintDetails("+"); + } + PrintDetails("%#x", signed_addend); + } + PrintDetails("\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnSymbolCount(Index count) { + PrintDetails(" - symbol table [count=%d]\n", count); + return Result::Ok; +} + +Result BinaryReaderObjdump::PrintSymbolFlags(uint32_t flags) { + if (flags > WABT_SYMBOL_FLAG_MAX) { + err_stream_->Writef("Unknown symbols flags: %x\n", flags); + return Result::Error; + } + + const char* binding_name = nullptr; + SymbolBinding binding = + static_cast(flags & WABT_SYMBOL_MASK_BINDING); + switch (binding) { + case SymbolBinding::Global: + binding_name = "global"; + break; + case SymbolBinding::Local: + binding_name = "local"; + break; + case SymbolBinding::Weak: + binding_name = "weak"; + break; + } + + const char* vis_name = nullptr; + SymbolVisibility vis = + static_cast(flags & WABT_SYMBOL_MASK_VISIBILITY); + switch (vis) { + case SymbolVisibility::Hidden: + vis_name = "hidden"; + break; + case SymbolVisibility::Default: + vis_name = "default"; + break; + } + if (flags & WABT_SYMBOL_FLAG_UNDEFINED) + PrintDetails(" undefined"); + if (flags & WABT_SYMBOL_FLAG_EXPORTED) + PrintDetails(" exported"); + if (flags & WABT_SYMBOL_FLAG_EXPLICIT_NAME) + PrintDetails(" explicit_name"); + if (flags & WABT_SYMBOL_FLAG_NO_STRIP) + PrintDetails(" no_strip"); + + PrintDetails(" binding=%s vis=%s\n", binding_name, vis_name); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnDataSymbol(Index index, + uint32_t flags, + string_view name, + Index segment, + uint32_t offset, + uint32_t size) { + PrintDetails(" - %d: D <" PRIstringview ">", index, + WABT_PRINTF_STRING_VIEW_ARG(name)); + if (!(flags & WABT_SYMBOL_FLAG_UNDEFINED)) + PrintDetails(" segment=%" PRIindex " offset=%d size=%d", segment, offset, + size); + return PrintSymbolFlags(flags); +} + +Result BinaryReaderObjdump::OnFunctionSymbol(Index index, + uint32_t flags, + string_view name, + Index func_index) { + if (name.empty()) { + name = GetFunctionName(func_index); + } + PrintDetails(" - %d: F <" PRIstringview "> func=%" PRIindex, index, + WABT_PRINTF_STRING_VIEW_ARG(name), func_index); + return PrintSymbolFlags(flags); +} + +Result BinaryReaderObjdump::OnGlobalSymbol(Index index, + uint32_t flags, + string_view name, + Index global_index) { + if (name.empty()) { + name = GetGlobalName(global_index); + } + PrintDetails(" - %d: G <" PRIstringview "> global=%" PRIindex, index, + WABT_PRINTF_STRING_VIEW_ARG(name), global_index); + return PrintSymbolFlags(flags); +} + +Result BinaryReaderObjdump::OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) { + auto sym_name = GetSectionName(section_index); + assert(!sym_name.empty()); + PrintDetails(" - %d: S <" PRIstringview "> section=%" PRIindex, index, + WABT_PRINTF_STRING_VIEW_ARG(sym_name), section_index); + return PrintSymbolFlags(flags); +} + +Result BinaryReaderObjdump::OnEventSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) { + if (name.empty()) { + name = GetEventName(event_index); + } + PrintDetails(" - %d: E <" PRIstringview "> event=%" PRIindex, index, + WABT_PRINTF_STRING_VIEW_ARG(name), event_index); + return PrintSymbolFlags(flags); +} + +Result BinaryReaderObjdump::OnTableSymbol(Index index, + uint32_t flags, + string_view name, + Index table_index) { + if (name.empty()) { + name = GetTableName(table_index); + } + PrintDetails(" - %d: T <" PRIstringview "> table=%" PRIindex, index, + WABT_PRINTF_STRING_VIEW_ARG(name), table_index); + return PrintSymbolFlags(flags); +} + +Result BinaryReaderObjdump::OnSegmentInfoCount(Index count) { + PrintDetails(" - segment info [count=%d]\n", count); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnSegmentInfo(Index index, + string_view name, + Address alignment_log2, + uint32_t flags) { + PrintDetails(" - %d: " PRIstringview " p2align=%" PRIaddress " flags=%#x\n", + index, WABT_PRINTF_STRING_VIEW_ARG(name), alignment_log2, flags); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitFunctionCount(Index count) { + PrintDetails(" - init functions [count=%d]\n", count); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnInitFunction(uint32_t priority, + Index function_index) { + PrintDetails(" - %d: priority=%d\n", function_index, priority); + return Result::Ok; +} +Result BinaryReaderObjdump::OnComdatCount(Index count) { + PrintDetails(" - comdat groups [count=%d]\n", count); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnComdatBegin(string_view name, uint32_t flags, Index count) { + PrintDetails(" - " PRIstringview ": [count=%d]\n", + WABT_PRINTF_STRING_VIEW_ARG(name), count); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnComdatEntry(ComdatType kind, Index index) { + switch (kind) { + case ComdatType::Data: { + PrintDetails(" - segment[%" PRIindex "]", index); + auto name = GetSegmentName(index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + break; + } + case ComdatType::Function: { + PrintDetails(" - func[%" PRIindex "]", index); + auto name = GetFunctionName(index); + if (!name.empty()) { + PrintDetails(" <" PRIstringview ">", WABT_PRINTF_STRING_VIEW_ARG(name)); + } + break; + } + } + PrintDetails("\n"); + return Result::Ok; +} + +Result BinaryReaderObjdump::OnEventCount(Index count) { + return OnCount(count); +} + +Result BinaryReaderObjdump::OnEventType(Index index, Index sig_index) { + if (!ShouldPrintDetails()) { + return Result::Ok; + } + printf(" - event[%" PRIindex "] sig=%" PRIindex "\n", index, sig_index); + return Result::Ok; +} + +} // end anonymous namespace + +string_view ObjdumpNames::Get(Index index) const { + auto iter = names.find(index); + if (iter == names.end()) + return string_view(); + return iter->second; +} + +void ObjdumpNames::Set(Index index, string_view name) { + names[index] = name.to_string(); +} + +Result ReadBinaryObjdump(const uint8_t* data, + size_t size, + ObjdumpOptions* options, + ObjdumpState* state) { + Features features; + features.EnableAll(); + const bool kReadDebugNames = true; + const bool kStopOnFirstError = false; + const bool kFailOnCustomSectionError = false; + ReadBinaryOptions read_options(features, options->log_stream, kReadDebugNames, + kStopOnFirstError, kFailOnCustomSectionError); + + switch (options->mode) { + case ObjdumpMode::Prepass: { + BinaryReaderObjdumpPrepass reader(data, size, options, state); + return ReadBinary(data, size, &reader, read_options); + } + case ObjdumpMode::Disassemble: { + BinaryReaderObjdumpDisassemble reader(data, size, options, state); + return ReadBinary(data, size, &reader, read_options); + } + default: { + BinaryReaderObjdump reader(data, size, options, state); + return ReadBinary(data, size, &reader, read_options); + } + } +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.h new file mode 100644 index 0000000..b2874da --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.h @@ -0,0 +1,87 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_READER_OBJDUMP_H_ +#define WABT_BINARY_READER_OBJDUMP_H_ + +#include +#include + +#include "src/common.h" +#include "src/feature.h" +#include "src/stream.h" + +namespace wabt { + +struct Module; +struct ReadBinaryOptions; + +enum class ObjdumpMode { + Prepass, + Headers, + Details, + Disassemble, + RawData, +}; + +struct ObjdumpOptions { + Stream* log_stream; + bool headers; + bool details; + bool raw; + bool disassemble; + bool debug; + bool relocs; + ObjdumpMode mode; + const char* filename; + const char* section_name; +}; + +struct ObjdumpSymbol { + wabt::SymbolType kind; + std::string name; + Index index; +}; + +struct ObjdumpNames { + string_view Get(Index index) const; + void Set(Index index, string_view name); + + std::map names; +}; + +// read_binary_objdump uses this state to store information from previous runs +// and use it to display more useful information. +struct ObjdumpState { + std::vector code_relocations; + std::vector data_relocations; + ObjdumpNames function_names; + ObjdumpNames global_names; + ObjdumpNames section_names; + ObjdumpNames event_names; + ObjdumpNames segment_names; + ObjdumpNames table_names; + std::vector symtab; +}; + +Result ReadBinaryObjdump(const uint8_t* data, + size_t size, + ObjdumpOptions* options, + ObjdumpState* state); + +} // namespace wabt + +#endif /* WABT_BINARY_READER_OBJDUMP_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.cc new file mode 100644 index 0000000..3908660 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.cc @@ -0,0 +1,290 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary-reader-opcnt.h" + +#include +#include +#include +#include +#include + +#include "src/binary-reader-nop.h" +#include "src/common.h" +#include "src/literal.h" +#include "src/stream.h" + +namespace wabt { + +OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind) + : opcode_(opcode), kind_(kind) {} + +template +OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count) + : OpcodeInfo(opcode, kind) { + if (count > 0) { + data_.resize(sizeof(T) * count); + memcpy(data_.data(), data, data_.size()); + } +} + +template +OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count, T extra) + : OpcodeInfo(opcode, kind, data, count) { + data_.resize(data_.size() + sizeof(T)); + memcpy(data_.data() + data_.size() - sizeof(T), &extra, sizeof(T)); +} + +template +std::pair OpcodeInfo::GetDataArray() const { + if (data_.empty()) { + return std::pair(nullptr, 0); + } + + assert(data_.size() % sizeof(T) == 0); + return std::make_pair(reinterpret_cast(data_.data()), + data_.size() / sizeof(T)); +} + +template +const T* OpcodeInfo::GetData(size_t expected_size) const { + auto pair = GetDataArray(); + assert(pair.second == expected_size); + return pair.first; +} + +template +void OpcodeInfo::WriteArray(Stream& stream, F&& write_func) { + auto pair = GetDataArray(); + for (size_t i = 0; i < pair.second; ++i) { + // Write an initial space (to separate from the opcode name) first, then + // comma-separate. + stream.Writef("%s", i == 0 ? " " : ", "); + write_func(pair.first[i]); + } +} + +void OpcodeInfo::Write(Stream& stream) { + stream.Writef("%s", opcode_.GetName()); + + switch (kind_) { + case Kind::Bare: + break; + + case Kind::Uint32: + stream.Writef(" %u (0x%x)", *GetData(), *GetData()); + break; + + case Kind::Uint64: + stream.Writef(" %" PRIu64 " (0x%" PRIx64 ")", *GetData(), + *GetData()); + break; + + case Kind::Index: + stream.Writef(" %" PRIindex, *GetData()); + break; + + case Kind::Float32: { + stream.Writef(" %g", *GetData()); + char buffer[WABT_MAX_FLOAT_HEX + 1]; + WriteFloatHex(buffer, sizeof(buffer), *GetData()); + stream.Writef(" (%s)", buffer); + break; + } + + case Kind::Float64: { + stream.Writef(" %g", *GetData()); + char buffer[WABT_MAX_DOUBLE_HEX + 1]; + WriteDoubleHex(buffer, sizeof(buffer), *GetData()); + stream.Writef(" (%s)", buffer); + break; + } + + case Kind::Uint32Uint32: + WriteArray( + stream, [&stream](uint32_t value) { stream.Writef("%u", value); }); + break; + + case Kind::BlockSig: { + auto type = *GetData(); + if (type.IsIndex()) { + stream.Writef(" type:%d", type.GetIndex()); + } else if (type != Type::Void) { + stream.Writef(" %s", type.GetName()); + } + break; + } + + case Kind::BrTable: { + WriteArray(stream, [&stream](Index index) { + stream.Writef("%" PRIindex, index); + }); + break; + } + } +} + +bool operator==(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { + return lhs.opcode_ == rhs.opcode_ && lhs.kind_ == rhs.kind_ && + lhs.data_ == rhs.data_; +} + +bool operator!=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { + return !(lhs == rhs); +} + +bool operator<(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { + if (lhs.opcode_ < rhs.opcode_) { + return true; + } + if (lhs.opcode_ > rhs.opcode_) { + return false; + } + if (lhs.kind_ < rhs.kind_) { + return true; + } + if (lhs.kind_ > rhs.kind_) { + return false; + } + if (lhs.data_ < rhs.data_) { + return true; + } + if (lhs.data_ > rhs.data_) { + return false; + } + return false; +} + +bool operator<=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { + return lhs < rhs || lhs == rhs; +} + +bool operator>(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { + return !(lhs <= rhs); +} + +bool operator>=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { + return !(lhs < rhs); +} + +namespace { + +class BinaryReaderOpcnt : public BinaryReaderNop { + public: + explicit BinaryReaderOpcnt(OpcodeInfoCounts* counts); + + Result OnOpcode(Opcode opcode) override; + Result OnOpcodeBare() override; + Result OnOpcodeUint32(uint32_t value) override; + Result OnOpcodeIndex(Index value) override; + Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override; + Result OnOpcodeUint64(uint64_t value) override; + Result OnOpcodeF32(uint32_t value) override; + Result OnOpcodeF64(uint64_t value) override; + Result OnOpcodeBlockSig(Type sig_type) override; + Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) override; + Result OnEndExpr() override; + Result OnEndFunc() override; + + private: + template + Result Emplace(Args&&... args); + + OpcodeInfoCounts* opcode_counts_; + Opcode current_opcode_; +}; + +template +Result BinaryReaderOpcnt::Emplace(Args&&... args) { + auto pair = opcode_counts_->emplace( + std::piecewise_construct, std::make_tuple(std::forward(args)...), + std::make_tuple(0)); + + auto& count = pair.first->second; + count++; + return Result::Ok; +} + +BinaryReaderOpcnt::BinaryReaderOpcnt(OpcodeInfoCounts* counts) + : opcode_counts_(counts) {} + +Result BinaryReaderOpcnt::OnOpcode(Opcode opcode) { + current_opcode_ = opcode; + return Result::Ok; +} + +Result BinaryReaderOpcnt::OnOpcodeBare() { + return Emplace(current_opcode_, OpcodeInfo::Kind::Bare); +} + +Result BinaryReaderOpcnt::OnOpcodeUint32(uint32_t value) { + return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32, &value); +} + +Result BinaryReaderOpcnt::OnOpcodeIndex(Index value) { + return Emplace(current_opcode_, OpcodeInfo::Kind::Index, &value); +} + +Result BinaryReaderOpcnt::OnOpcodeUint32Uint32(uint32_t value0, + uint32_t value1) { + uint32_t array[2] = {value0, value1}; + return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32, array, 2); +} + +Result BinaryReaderOpcnt::OnOpcodeUint64(uint64_t value) { + return Emplace(current_opcode_, OpcodeInfo::Kind::Uint64, &value); +} + +Result BinaryReaderOpcnt::OnOpcodeF32(uint32_t value) { + return Emplace(current_opcode_, OpcodeInfo::Kind::Float32, &value); +} + +Result BinaryReaderOpcnt::OnOpcodeF64(uint64_t value) { + return Emplace(current_opcode_, OpcodeInfo::Kind::Float64, &value); +} + +Result BinaryReaderOpcnt::OnOpcodeBlockSig(Type sig_type) { + return Emplace(current_opcode_, OpcodeInfo::Kind::BlockSig, &sig_type); +} + +Result BinaryReaderOpcnt::OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) { + return Emplace(current_opcode_, OpcodeInfo::Kind::BrTable, target_depths, + num_targets, default_target_depth); +} + +Result BinaryReaderOpcnt::OnEndExpr() { + return Emplace(Opcode::End, OpcodeInfo::Kind::Bare); +} + +Result BinaryReaderOpcnt::OnEndFunc() { + return Emplace(Opcode::End, OpcodeInfo::Kind::Bare); +} + +} // end anonymous namespace + +Result ReadBinaryOpcnt(const void* data, + size_t size, + const ReadBinaryOptions& options, + OpcodeInfoCounts* counts) { + BinaryReaderOpcnt reader(counts); + return ReadBinary(data, size, &reader, options); +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.h new file mode 100644 index 0000000..cfdd570 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.h @@ -0,0 +1,93 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_READER_OPCNT_H_ +#define WABT_BINARY_READER_OPCNT_H_ + +#include +#include + +#include "src/common.h" +#include "src/opcode.h" + +namespace wabt { + +struct Module; +struct ReadBinaryOptions; +class Stream; + +class OpcodeInfo { + public: + enum class Kind { + Bare, + Uint32, + Uint64, + Index, + Float32, + Float64, + Uint32Uint32, + BlockSig, + BrTable, + }; + + explicit OpcodeInfo(Opcode, Kind); + template + OpcodeInfo(Opcode, Kind, T* data, size_t count = 1); + template + OpcodeInfo(Opcode, Kind, T* data, size_t count, T extra); + + Opcode opcode() const { return opcode_; } + + void Write(Stream&); + + private: + template + std::pair GetDataArray() const; + template + const T* GetData(size_t expected_size = 1) const; + + template + void WriteArray(Stream& stream, F&& write_func); + + Opcode opcode_; + Kind kind_; + std::vector data_; + + friend bool operator==(const OpcodeInfo&, const OpcodeInfo&); + friend bool operator!=(const OpcodeInfo&, const OpcodeInfo&); + friend bool operator<(const OpcodeInfo&, const OpcodeInfo&); + friend bool operator<=(const OpcodeInfo&, const OpcodeInfo&); + friend bool operator>(const OpcodeInfo&, const OpcodeInfo&); + friend bool operator>=(const OpcodeInfo&, const OpcodeInfo&); +}; + +bool operator==(const OpcodeInfo&, const OpcodeInfo&); +bool operator!=(const OpcodeInfo&, const OpcodeInfo&); +bool operator<(const OpcodeInfo&, const OpcodeInfo&); +bool operator<=(const OpcodeInfo&, const OpcodeInfo&); +bool operator>(const OpcodeInfo&, const OpcodeInfo&); +bool operator>=(const OpcodeInfo&, const OpcodeInfo&); + +typedef std::map OpcodeInfoCounts; + +Result ReadBinaryOpcnt(const void* data, + size_t size, + const ReadBinaryOptions& options, + OpcodeInfoCounts* opcode_counts); + +} // namespace wabt + +#endif /* WABT_BINARY_READER_OPCNT_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.cc new file mode 100644 index 0000000..d770afa --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.cc @@ -0,0 +1,2671 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary-reader.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "src/binary-reader-logging.h" +#include "src/binary.h" +#include "src/leb128.h" +#include "src/stream.h" +#include "src/utf8.h" + +#if HAVE_ALLOCA +#include +#endif + +#define ERROR_IF(expr, ...) \ + do { \ + if (expr) { \ + PrintError(__VA_ARGS__); \ + return Result::Error; \ + } \ + } while (0) + +#define ERROR_UNLESS(expr, ...) ERROR_IF(!(expr), __VA_ARGS__) + +#define ERROR_UNLESS_OPCODE_ENABLED(opcode) \ + do { \ + if (!opcode.IsEnabled(options_.features)) { \ + return ReportUnexpectedOpcode(opcode); \ + } \ + } while (0) + +#define CALLBACK0(member) \ + ERROR_UNLESS(Succeeded(delegate_->member()), #member " callback failed") + +#define CALLBACK(member, ...) \ + ERROR_UNLESS(Succeeded(delegate_->member(__VA_ARGS__)), \ + #member " callback failed") + +namespace wabt { + +namespace { + +class BinaryReader { + public: + BinaryReader(const void* data, + size_t size, + BinaryReaderDelegate* delegate, + const ReadBinaryOptions& options); + + Result ReadModule(); + + private: + template + struct ValueRestoreGuard { + explicit ValueRestoreGuard(BinaryReader* this_) + : this_(this_), previous_value_(this_->*member) {} + ~ValueRestoreGuard() { this_->*member = previous_value_; } + + BinaryReader* this_; + T previous_value_; + }; + + void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* format, ...); + Result ReadOpcode(Opcode* out_value, const char* desc) WABT_WARN_UNUSED; + template + Result ReadT(T* out_value, + const char* type_name, + const char* desc) WABT_WARN_UNUSED; + Result ReadU8(uint8_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadU32(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadF32(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadF64(uint64_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadV128(v128* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadU32Leb128(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadU64Leb128(uint64_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadS32Leb128(uint32_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadS64Leb128(uint64_t* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadType(Type* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadRefType(Type* out_value, const char* desc) WABT_WARN_UNUSED; + Result ReadExternalKind(ExternalKind* out_value, + const char* desc) WABT_WARN_UNUSED; + Result ReadStr(string_view* out_str, const char* desc) WABT_WARN_UNUSED; + Result ReadBytes(const void** out_data, + Address* out_data_size, + const char* desc) WABT_WARN_UNUSED; + Result ReadIndex(Index* index, const char* desc) WABT_WARN_UNUSED; + Result ReadOffset(Offset* offset, const char* desc) WABT_WARN_UNUSED; + Result ReadAlignment(Address* align_log2, const char* desc) WABT_WARN_UNUSED; + Result ReadCount(Index* index, const char* desc) WABT_WARN_UNUSED; + Result ReadField(TypeMut* out_value) WABT_WARN_UNUSED; + + bool IsConcreteType(Type); + bool IsBlockType(Type); + + Index NumTotalFuncs(); + + Result ReadI32InitExpr(Index index) WABT_WARN_UNUSED; + Result ReadInitExpr(Index index, bool require_i32 = false) WABT_WARN_UNUSED; + Result ReadTable(Type* out_elem_type, + Limits* out_elem_limits) WABT_WARN_UNUSED; + Result ReadMemory(Limits* out_page_limits) WABT_WARN_UNUSED; + Result ReadGlobalHeader(Type* out_type, bool* out_mutable) WABT_WARN_UNUSED; + Result ReadEventType(Index* out_sig_index) WABT_WARN_UNUSED; + Result ReadAddress(Address* out_value, + Index memory, + const char* desc) WABT_WARN_UNUSED; + Result ReadFunctionBody(Offset end_offset) WABT_WARN_UNUSED; + Result ReadNameSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadRelocSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadDylinkSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadLinkingSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadCustomSection(Index section_index, + Offset section_size) WABT_WARN_UNUSED; + Result ReadTypeSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadImportSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadFunctionSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadTableSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadMemorySection(Offset section_size) WABT_WARN_UNUSED; + Result ReadGlobalSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadExportSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadStartSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadElemSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadCodeSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadDataSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadDataCountSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadEventSection(Offset section_size) WABT_WARN_UNUSED; + Result ReadSections() WABT_WARN_UNUSED; + Result ReportUnexpectedOpcode(Opcode opcode, const char* message = nullptr); + + size_t read_end_ = 0; // Either the section end or data_size. + BinaryReaderDelegate::State state_; + BinaryReaderLogging logging_delegate_; + BinaryReaderDelegate* delegate_ = nullptr; + TypeVector param_types_; + TypeVector result_types_; + TypeMutVector fields_; + std::vector target_depths_; + const ReadBinaryOptions& options_; + BinarySection last_known_section_ = BinarySection::Invalid; + bool did_read_names_section_ = false; + bool reading_custom_section_ = false; + Index num_func_imports_ = 0; + Index num_table_imports_ = 0; + Index num_memory_imports_ = 0; + Index num_global_imports_ = 0; + Index num_event_imports_ = 0; + Index num_function_signatures_ = 0; + Index num_function_bodies_ = 0; + Index data_count_ = kInvalidIndex; + std::vector memories; + + using ReadEndRestoreGuard = + ValueRestoreGuard; +}; + +BinaryReader::BinaryReader(const void* data, + size_t size, + BinaryReaderDelegate* delegate, + const ReadBinaryOptions& options) + : read_end_(size), + state_(static_cast(data), size), + logging_delegate_(options.log_stream, delegate), + delegate_(options.log_stream ? &logging_delegate_ : delegate), + options_(options), + last_known_section_(BinarySection::Invalid) { + delegate->OnSetState(&state_); +} + +void WABT_PRINTF_FORMAT(2, 3) BinaryReader::PrintError(const char* format, + ...) { + ErrorLevel error_level = + reading_custom_section_ && !options_.fail_on_custom_section_error + ? ErrorLevel::Warning + : ErrorLevel::Error; + + WABT_SNPRINTF_ALLOCA(buffer, length, format); + Error error(error_level, Location(state_.offset), buffer); + bool handled = delegate_->OnError(error); + + if (!handled) { + // Not great to just print, but we don't want to eat the error either. + fprintf(stderr, "%07" PRIzx ": %s: %s\n", state_.offset, + GetErrorLevelName(error_level), buffer); + } +} + +Result BinaryReader::ReportUnexpectedOpcode(Opcode opcode, const char* where) { + std::string message = "unexpected opcode"; + if (where) { + message += ' '; + message += where; + } + + message += ":"; + + std::vector bytes = opcode.GetBytes(); + assert(bytes.size() > 0); + + for (uint8_t byte : bytes) { + message += StringPrintf(" 0x%x", byte); + } + + PrintError("%s", message.c_str()); + return Result::Error; +} + +Result BinaryReader::ReadOpcode(Opcode* out_value, const char* desc) { + uint8_t value = 0; + CHECK_RESULT(ReadU8(&value, desc)); + + if (Opcode::IsPrefixByte(value)) { + uint32_t code; + CHECK_RESULT(ReadU32Leb128(&code, desc)); + *out_value = Opcode::FromCode(value, code); + } else { + *out_value = Opcode::FromCode(value); + } + return Result::Ok; +} + +template +Result BinaryReader::ReadT(T* out_value, + const char* type_name, + const char* desc) { + if (state_.offset + sizeof(T) > read_end_) { + PrintError("unable to read %s: %s", type_name, desc); + return Result::Error; + } +#if WABT_BIG_ENDIAN + uint8_t tmp[sizeof(T)]; + memcpy(tmp, state_.data + state_.offset, sizeof(tmp)); + SwapBytesSized(tmp, sizeof(tmp)); + memcpy(out_value, tmp, sizeof(T)); +#else + memcpy(out_value, state_.data + state_.offset, sizeof(T)); +#endif + state_.offset += sizeof(T); + return Result::Ok; +} + +Result BinaryReader::ReadU8(uint8_t* out_value, const char* desc) { + return ReadT(out_value, "uint8_t", desc); +} + +Result BinaryReader::ReadU32(uint32_t* out_value, const char* desc) { + return ReadT(out_value, "uint32_t", desc); +} + +Result BinaryReader::ReadF32(uint32_t* out_value, const char* desc) { + return ReadT(out_value, "float", desc); +} + +Result BinaryReader::ReadF64(uint64_t* out_value, const char* desc) { + return ReadT(out_value, "double", desc); +} + +Result BinaryReader::ReadV128(v128* out_value, const char* desc) { + return ReadT(out_value, "v128", desc); +} + +Result BinaryReader::ReadU32Leb128(uint32_t* out_value, const char* desc) { + const uint8_t* p = state_.data + state_.offset; + const uint8_t* end = state_.data + read_end_; + size_t bytes_read = wabt::ReadU32Leb128(p, end, out_value); + ERROR_UNLESS(bytes_read > 0, "unable to read u32 leb128: %s", desc); + state_.offset += bytes_read; + return Result::Ok; +} + +Result BinaryReader::ReadU64Leb128(uint64_t* out_value, const char* desc) { + const uint8_t* p = state_.data + state_.offset; + const uint8_t* end = state_.data + read_end_; + size_t bytes_read = wabt::ReadU64Leb128(p, end, out_value); + ERROR_UNLESS(bytes_read > 0, "unable to read u64 leb128: %s", desc); + state_.offset += bytes_read; + return Result::Ok; +} + +Result BinaryReader::ReadS32Leb128(uint32_t* out_value, const char* desc) { + const uint8_t* p = state_.data + state_.offset; + const uint8_t* end = state_.data + read_end_; + size_t bytes_read = wabt::ReadS32Leb128(p, end, out_value); + ERROR_UNLESS(bytes_read > 0, "unable to read i32 leb128: %s", desc); + state_.offset += bytes_read; + return Result::Ok; +} + +Result BinaryReader::ReadS64Leb128(uint64_t* out_value, const char* desc) { + const uint8_t* p = state_.data + state_.offset; + const uint8_t* end = state_.data + read_end_; + size_t bytes_read = wabt::ReadS64Leb128(p, end, out_value); + ERROR_UNLESS(bytes_read > 0, "unable to read i64 leb128: %s", desc); + state_.offset += bytes_read; + return Result::Ok; +} + +Result BinaryReader::ReadType(Type* out_value, const char* desc) { + uint32_t type = 0; + CHECK_RESULT(ReadS32Leb128(&type, desc)); + *out_value = static_cast(type); + return Result::Ok; +} + +Result BinaryReader::ReadRefType(Type* out_value, const char* desc) { + uint32_t type = 0; + CHECK_RESULT(ReadS32Leb128(&type, desc)); + *out_value = static_cast(type); + ERROR_UNLESS(out_value->IsRef(), "%s must be a reference type", desc); + return Result::Ok; +} + +Result BinaryReader::ReadExternalKind(ExternalKind* out_value, + const char* desc) { + uint8_t value = 0; + CHECK_RESULT(ReadU8(&value, desc)); + ERROR_UNLESS(value < kExternalKindCount, "invalid export external kind: %d", + value); + *out_value = static_cast(value); + return Result::Ok; +} + +Result BinaryReader::ReadStr(string_view* out_str, const char* desc) { + uint32_t str_len = 0; + CHECK_RESULT(ReadU32Leb128(&str_len, "string length")); + + ERROR_UNLESS(state_.offset + str_len <= read_end_, + "unable to read string: %s", desc); + + *out_str = string_view( + reinterpret_cast(state_.data) + state_.offset, str_len); + state_.offset += str_len; + + ERROR_UNLESS(IsValidUtf8(out_str->data(), out_str->length()), + "invalid utf-8 encoding: %s", desc); + return Result::Ok; +} + +Result BinaryReader::ReadBytes(const void** out_data, + Address* out_data_size, + const char* desc) { + uint32_t data_size = 0; + CHECK_RESULT(ReadU32Leb128(&data_size, "data size")); + + ERROR_UNLESS(state_.offset + data_size <= read_end_, + "unable to read data: %s", desc); + + *out_data = static_cast(state_.data) + state_.offset; + *out_data_size = data_size; + state_.offset += data_size; + return Result::Ok; +} + +Result BinaryReader::ReadIndex(Index* index, const char* desc) { + uint32_t value; + CHECK_RESULT(ReadU32Leb128(&value, desc)); + *index = value; + return Result::Ok; +} + +Result BinaryReader::ReadOffset(Offset* offset, const char* desc) { + uint32_t value; + CHECK_RESULT(ReadU32Leb128(&value, desc)); + *offset = value; + return Result::Ok; +} + +Result BinaryReader::ReadAlignment(Address* alignment_log2, const char* desc) { + uint32_t value; + CHECK_RESULT(ReadU32Leb128(&value, desc)); + if (value >= 32) { + PrintError("invalid %s: %u", desc, value); + return Result::Error; + } + *alignment_log2 = value; + return Result::Ok; +} + +Result BinaryReader::ReadCount(Index* count, const char* desc) { + CHECK_RESULT(ReadIndex(count, desc)); + + // This check assumes that each item follows in this section, and takes at + // least 1 byte. It's possible that this check passes but reading fails + // later. It is still useful to check here, though, because it early-outs + // when an erroneous large count is used, before allocating memory for it. + size_t section_remaining = read_end_ - state_.offset; + if (*count > section_remaining) { + PrintError("invalid %s %" PRIindex ", only %" PRIzd + " bytes left in section", + desc, *count, section_remaining); + return Result::Error; + } + return Result::Ok; +} + +Result BinaryReader::ReadField(TypeMut* out_value) { + // TODO: Reuse for global header too? + Type field_type; + CHECK_RESULT(ReadType(&field_type, "field type")); + ERROR_UNLESS(IsConcreteType(field_type), + "expected valid field type (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(field_type)); + + uint8_t mutable_ = 0; + CHECK_RESULT(ReadU8(&mutable_, "field mutability")); + ERROR_UNLESS(mutable_ <= 1, "field mutability must be 0 or 1"); + out_value->type = field_type; + out_value->mutable_ = mutable_; + return Result::Ok; +} + +bool BinaryReader::IsConcreteType(Type type) { + switch (type) { + case Type::I32: + case Type::I64: + case Type::F32: + case Type::F64: + return true; + + case Type::V128: + return options_.features.simd_enabled(); + + case Type::FuncRef: + case Type::ExternRef: + return options_.features.reference_types_enabled(); + + default: + return false; + } +} + +bool BinaryReader::IsBlockType(Type type) { + if (IsConcreteType(type) || type == Type::Void) { + return true; + } + + if (!(options_.features.multi_value_enabled() && type.IsIndex())) { + return false; + } + + return true; +} + +Index BinaryReader::NumTotalFuncs() { + return num_func_imports_ + num_function_signatures_; +} + +Result BinaryReader::ReadI32InitExpr(Index index) { + return ReadInitExpr(index, true); +} + +Result BinaryReader::ReadInitExpr(Index index, bool require_i32) { + Opcode opcode; + CHECK_RESULT(ReadOpcode(&opcode, "opcode")); + ERROR_UNLESS_OPCODE_ENABLED(opcode); + + switch (opcode) { + case Opcode::I32Const: { + uint32_t value = 0; + CHECK_RESULT(ReadS32Leb128(&value, "init_expr i32.const value")); + CALLBACK(OnInitExprI32ConstExpr, index, value); + break; + } + + case Opcode::I64Const: { + uint64_t value = 0; + CHECK_RESULT(ReadS64Leb128(&value, "init_expr i64.const value")); + CALLBACK(OnInitExprI64ConstExpr, index, value); + break; + } + + case Opcode::F32Const: { + uint32_t value_bits = 0; + CHECK_RESULT(ReadF32(&value_bits, "init_expr f32.const value")); + CALLBACK(OnInitExprF32ConstExpr, index, value_bits); + break; + } + + case Opcode::F64Const: { + uint64_t value_bits = 0; + CHECK_RESULT(ReadF64(&value_bits, "init_expr f64.const value")); + CALLBACK(OnInitExprF64ConstExpr, index, value_bits); + break; + } + + case Opcode::V128Const: { + v128 value_bits; + ZeroMemory(value_bits); + CHECK_RESULT(ReadV128(&value_bits, "init_expr v128.const value")); + CALLBACK(OnInitExprV128ConstExpr, index, value_bits); + break; + } + + case Opcode::GlobalGet: { + Index global_index; + CHECK_RESULT(ReadIndex(&global_index, "init_expr global.get index")); + CALLBACK(OnInitExprGlobalGetExpr, index, global_index); + break; + } + + case Opcode::RefNull: { + Type type; + CHECK_RESULT(ReadRefType(&type, "ref.null type")); + CALLBACK(OnInitExprRefNull, index, type); + break; + } + + case Opcode::RefFunc: { + Index func_index; + CHECK_RESULT(ReadIndex(&func_index, "init_expr ref.func index")); + CALLBACK(OnInitExprRefFunc, index, func_index); + break; + } + + case Opcode::End: + return Result::Ok; + + default: + return ReportUnexpectedOpcode(opcode, "in initializer expression"); + } + + if (require_i32 && opcode != Opcode::I32Const && + opcode != Opcode::GlobalGet) { + PrintError("expected i32 init_expr"); + return Result::Error; + } + + CHECK_RESULT(ReadOpcode(&opcode, "opcode")); + ERROR_UNLESS(opcode == Opcode::End, + "expected END opcode after initializer expression"); + return Result::Ok; +} + +Result BinaryReader::ReadTable(Type* out_elem_type, Limits* out_elem_limits) { + CHECK_RESULT(ReadRefType(out_elem_type, "table elem type")); + + uint8_t flags; + uint32_t initial; + uint32_t max = 0; + CHECK_RESULT(ReadU8(&flags, "table flags")); + bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG; + bool is_shared = flags & WABT_BINARY_LIMITS_IS_SHARED_FLAG; + bool is_64 = flags & WABT_BINARY_LIMITS_IS_64_FLAG; + const uint8_t unknown_flags = flags & ~WABT_BINARY_LIMITS_ALL_FLAGS; + ERROR_IF(is_shared, "tables may not be shared"); + ERROR_IF(is_64, "tables may not be 64-bit"); + ERROR_UNLESS(unknown_flags == 0, "malformed table limits flag: %d", flags); + CHECK_RESULT(ReadU32Leb128(&initial, "table initial elem count")); + if (has_max) { + CHECK_RESULT(ReadU32Leb128(&max, "table max elem count")); + } + + out_elem_limits->has_max = has_max; + out_elem_limits->initial = initial; + out_elem_limits->max = max; + return Result::Ok; +} + +Result BinaryReader::ReadMemory(Limits* out_page_limits) { + uint8_t flags; + uint32_t initial; + uint32_t max = 0; + CHECK_RESULT(ReadU8(&flags, "memory flags")); + bool has_max = flags & WABT_BINARY_LIMITS_HAS_MAX_FLAG; + bool is_shared = flags & WABT_BINARY_LIMITS_IS_SHARED_FLAG; + bool is_64 = flags & WABT_BINARY_LIMITS_IS_64_FLAG; + const uint8_t unknown_flags = flags & ~WABT_BINARY_LIMITS_ALL_FLAGS; + ERROR_UNLESS(unknown_flags == 0, "malformed memory limits flag: %d", flags); + ERROR_IF(is_shared && !options_.features.threads_enabled(), + "memory may not be shared: threads not allowed"); + ERROR_IF(is_64 && !options_.features.memory64_enabled(), + "memory64 not allowed"); + CHECK_RESULT(ReadU32Leb128(&initial, "memory initial page count")); + if (has_max) { + CHECK_RESULT(ReadU32Leb128(&max, "memory max page count")); + } + + out_page_limits->has_max = has_max; + out_page_limits->is_shared = is_shared; + out_page_limits->is_64 = is_64; + out_page_limits->initial = initial; + out_page_limits->max = max; + + // Have to keep a copy of these, to know how to interpret load/stores. + memories.push_back(*out_page_limits); + return Result::Ok; +} + +Result BinaryReader::ReadGlobalHeader(Type* out_type, bool* out_mutable) { + Type global_type = Type::Void; + uint8_t mutable_ = 0; + CHECK_RESULT(ReadType(&global_type, "global type")); + ERROR_UNLESS(IsConcreteType(global_type), "invalid global type: %#x", + static_cast(global_type)); + + CHECK_RESULT(ReadU8(&mutable_, "global mutability")); + ERROR_UNLESS(mutable_ <= 1, "global mutability must be 0 or 1"); + + *out_type = global_type; + *out_mutable = mutable_; + return Result::Ok; +} + +Result BinaryReader::ReadAddress(Address* out_value, + Index memory, + const char* desc) { + ERROR_UNLESS(memory < memories.size(), + "load/store memory %u out of range %zu", memory, + memories.size()); + if (memories[memory].is_64) { + return ReadU64Leb128(out_value, desc); + } else { + uint32_t val; + Result res = ReadU32Leb128(&val, desc); + *out_value = val; + return res; + } +} + +Result BinaryReader::ReadFunctionBody(Offset end_offset) { + bool seen_end_opcode = false; + while (state_.offset < end_offset) { + Opcode opcode; + CHECK_RESULT(ReadOpcode(&opcode, "opcode")); + CALLBACK(OnOpcode, opcode); + ERROR_UNLESS_OPCODE_ENABLED(opcode); + + switch (opcode) { + case Opcode::Unreachable: + CALLBACK0(OnUnreachableExpr); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::Block: { + Type sig_type; + CHECK_RESULT(ReadType(&sig_type, "block signature type")); + ERROR_UNLESS(IsBlockType(sig_type), + "expected valid block signature type"); + CALLBACK(OnBlockExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); + break; + } + + case Opcode::Loop: { + Type sig_type; + CHECK_RESULT(ReadType(&sig_type, "loop signature type")); + ERROR_UNLESS(IsBlockType(sig_type), + "expected valid block signature type"); + CALLBACK(OnLoopExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); + break; + } + + case Opcode::If: { + Type sig_type; + CHECK_RESULT(ReadType(&sig_type, "if signature type")); + ERROR_UNLESS(IsBlockType(sig_type), + "expected valid block signature type"); + CALLBACK(OnIfExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); + break; + } + + case Opcode::Else: + CALLBACK0(OnElseExpr); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::SelectT: { + Index num_results; + CHECK_RESULT(ReadCount(&num_results, "num result types")); + + result_types_.resize(num_results); + for (Index i = 0; i < num_results; ++i) { + Type result_type; + CHECK_RESULT(ReadType(&result_type, "select result type")); + ERROR_UNLESS(IsConcreteType(result_type), + "expected valid select result type (got " PRItypecode + ")", + WABT_PRINTF_TYPE_CODE(result_type)); + result_types_[i] = result_type; + } + + Type* result_types = num_results ? result_types_.data() : nullptr; + CALLBACK(OnSelectExpr, num_results, result_types); + CALLBACK0(OnOpcodeBare); + break; + } + + case Opcode::Select: + CALLBACK(OnSelectExpr, 0, nullptr); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::Br: { + Index depth; + CHECK_RESULT(ReadIndex(&depth, "br depth")); + CALLBACK(OnBrExpr, depth); + CALLBACK(OnOpcodeIndex, depth); + break; + } + + case Opcode::BrIf: { + Index depth; + CHECK_RESULT(ReadIndex(&depth, "br_if depth")); + CALLBACK(OnBrIfExpr, depth); + CALLBACK(OnOpcodeIndex, depth); + break; + } + + case Opcode::BrTable: { + Index num_targets; + CHECK_RESULT(ReadCount(&num_targets, "br_table target count")); + target_depths_.resize(num_targets); + + for (Index i = 0; i < num_targets; ++i) { + Index target_depth; + CHECK_RESULT(ReadIndex(&target_depth, "br_table target depth")); + target_depths_[i] = target_depth; + } + + Index default_target_depth; + CHECK_RESULT( + ReadIndex(&default_target_depth, "br_table default target depth")); + + Index* target_depths = num_targets ? target_depths_.data() : nullptr; + + CALLBACK(OnBrTableExpr, num_targets, target_depths, + default_target_depth); + break; + } + + case Opcode::Return: + CALLBACK0(OnReturnExpr); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::Nop: + CALLBACK0(OnNopExpr); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::Drop: + CALLBACK0(OnDropExpr); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::End: + if (state_.offset == end_offset) { + seen_end_opcode = true; + CALLBACK0(OnEndFunc); + } else { + CALLBACK0(OnEndExpr); + } + break; + + case Opcode::I32Const: { + uint32_t value; + CHECK_RESULT(ReadS32Leb128(&value, "i32.const value")); + CALLBACK(OnI32ConstExpr, value); + CALLBACK(OnOpcodeUint32, value); + break; + } + + case Opcode::I64Const: { + uint64_t value; + CHECK_RESULT(ReadS64Leb128(&value, "i64.const value")); + CALLBACK(OnI64ConstExpr, value); + CALLBACK(OnOpcodeUint64, value); + break; + } + + case Opcode::F32Const: { + uint32_t value_bits = 0; + CHECK_RESULT(ReadF32(&value_bits, "f32.const value")); + CALLBACK(OnF32ConstExpr, value_bits); + CALLBACK(OnOpcodeF32, value_bits); + break; + } + + case Opcode::F64Const: { + uint64_t value_bits = 0; + CHECK_RESULT(ReadF64(&value_bits, "f64.const value")); + CALLBACK(OnF64ConstExpr, value_bits); + CALLBACK(OnOpcodeF64, value_bits); + break; + } + + case Opcode::V128Const: { + v128 value_bits; + ZeroMemory(value_bits); + CHECK_RESULT(ReadV128(&value_bits, "v128.const value")); + CALLBACK(OnV128ConstExpr, value_bits); + CALLBACK(OnOpcodeV128, value_bits); + break; + } + + case Opcode::GlobalGet: { + Index global_index; + CHECK_RESULT(ReadIndex(&global_index, "global.get global index")); + CALLBACK(OnGlobalGetExpr, global_index); + CALLBACK(OnOpcodeIndex, global_index); + break; + } + + case Opcode::LocalGet: { + Index local_index; + CHECK_RESULT(ReadIndex(&local_index, "local.get local index")); + CALLBACK(OnLocalGetExpr, local_index); + CALLBACK(OnOpcodeIndex, local_index); + break; + } + + case Opcode::GlobalSet: { + Index global_index; + CHECK_RESULT(ReadIndex(&global_index, "global.set global index")); + CALLBACK(OnGlobalSetExpr, global_index); + CALLBACK(OnOpcodeIndex, global_index); + break; + } + + case Opcode::LocalSet: { + Index local_index; + CHECK_RESULT(ReadIndex(&local_index, "local.set local index")); + CALLBACK(OnLocalSetExpr, local_index); + CALLBACK(OnOpcodeIndex, local_index); + break; + } + + case Opcode::Call: { + Index func_index; + CHECK_RESULT(ReadIndex(&func_index, "call function index")); + CALLBACK(OnCallExpr, func_index); + CALLBACK(OnOpcodeIndex, func_index); + break; + } + + case Opcode::CallIndirect: { + Index sig_index; + CHECK_RESULT(ReadIndex(&sig_index, "call_indirect signature index")); + Index table_index = 0; + if (options_.features.reference_types_enabled()) { + CHECK_RESULT(ReadIndex(&table_index, "call_indirect table index")); + } else { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "call_indirect reserved")); + ERROR_UNLESS(reserved == 0, "call_indirect reserved value must be 0"); + } + CALLBACK(OnCallIndirectExpr, sig_index, table_index); + CALLBACK(OnOpcodeUint32Uint32, sig_index, table_index); + break; + } + + case Opcode::ReturnCall: { + Index func_index; + CHECK_RESULT(ReadIndex(&func_index, "return_call")); + CALLBACK(OnReturnCallExpr, func_index); + CALLBACK(OnOpcodeIndex, func_index); + break; + } + + case Opcode::ReturnCallIndirect: { + Index sig_index; + CHECK_RESULT(ReadIndex(&sig_index, "return_call_indirect")); + Index table_index = 0; + if (options_.features.reference_types_enabled()) { + CHECK_RESULT( + ReadIndex(&table_index, "return_call_indirect table index")); + } else { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "return_call_indirect reserved")); + ERROR_UNLESS(reserved == 0, + "return_call_indirect reserved value must be 0"); + } + CALLBACK(OnReturnCallIndirectExpr, sig_index, table_index); + CALLBACK(OnOpcodeUint32Uint32, sig_index, table_index); + break; + } + + case Opcode::LocalTee: { + Index local_index; + CHECK_RESULT(ReadIndex(&local_index, "local.tee local index")); + CALLBACK(OnLocalTeeExpr, local_index); + CALLBACK(OnOpcodeIndex, local_index); + break; + } + + case Opcode::I32Load8S: + case Opcode::I32Load8U: + case Opcode::I32Load16S: + case Opcode::I32Load16U: + case Opcode::I64Load8S: + case Opcode::I64Load8U: + case Opcode::I64Load16S: + case Opcode::I64Load16U: + case Opcode::I64Load32S: + case Opcode::I64Load32U: + case Opcode::I32Load: + case Opcode::I64Load: + case Opcode::F32Load: + case Opcode::F64Load: + case Opcode::V128Load: + case Opcode::V128Load8X8S: + case Opcode::V128Load8X8U: + case Opcode::V128Load16X4S: + case Opcode::V128Load16X4U: + case Opcode::V128Load32X2S: + case Opcode::V128Load32X2U: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "load offset")); + CALLBACK(OnLoadExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::I32Store8: + case Opcode::I32Store16: + case Opcode::I64Store8: + case Opcode::I64Store16: + case Opcode::I64Store32: + case Opcode::I32Store: + case Opcode::I64Store: + case Opcode::F32Store: + case Opcode::F64Store: + case Opcode::V128Store: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "store alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "store offset")); + + CALLBACK(OnStoreExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::MemorySize: { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "memory.size reserved")); + ERROR_UNLESS(reserved == 0, "memory.size reserved value must be 0"); + CALLBACK0(OnMemorySizeExpr); + CALLBACK(OnOpcodeUint32, reserved); + break; + } + + case Opcode::MemoryGrow: { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "memory.grow reserved")); + ERROR_UNLESS(reserved == 0, "memory.grow reserved value must be 0"); + CALLBACK0(OnMemoryGrowExpr); + CALLBACK(OnOpcodeUint32, reserved); + break; + } + + case Opcode::I32Add: + case Opcode::I32Sub: + case Opcode::I32Mul: + case Opcode::I32DivS: + case Opcode::I32DivU: + case Opcode::I32RemS: + case Opcode::I32RemU: + case Opcode::I32And: + case Opcode::I32Or: + case Opcode::I32Xor: + case Opcode::I32Shl: + case Opcode::I32ShrU: + case Opcode::I32ShrS: + case Opcode::I32Rotr: + case Opcode::I32Rotl: + case Opcode::I64Add: + case Opcode::I64Sub: + case Opcode::I64Mul: + case Opcode::I64DivS: + case Opcode::I64DivU: + case Opcode::I64RemS: + case Opcode::I64RemU: + case Opcode::I64And: + case Opcode::I64Or: + case Opcode::I64Xor: + case Opcode::I64Shl: + case Opcode::I64ShrU: + case Opcode::I64ShrS: + case Opcode::I64Rotr: + case Opcode::I64Rotl: + case Opcode::F32Add: + case Opcode::F32Sub: + case Opcode::F32Mul: + case Opcode::F32Div: + case Opcode::F32Min: + case Opcode::F32Max: + case Opcode::F32Copysign: + case Opcode::F64Add: + case Opcode::F64Sub: + case Opcode::F64Mul: + case Opcode::F64Div: + case Opcode::F64Min: + case Opcode::F64Max: + case Opcode::F64Copysign: + case Opcode::I8X16Add: + case Opcode::I16X8Add: + case Opcode::I32X4Add: + case Opcode::I64X2Add: + case Opcode::I8X16Sub: + case Opcode::I16X8Sub: + case Opcode::I32X4Sub: + case Opcode::I64X2Sub: + case Opcode::I16X8Mul: + case Opcode::I32X4Mul: + case Opcode::I64X2Mul: + case Opcode::I8X16AddSatS: + case Opcode::I8X16AddSatU: + case Opcode::I16X8AddSatS: + case Opcode::I16X8AddSatU: + case Opcode::I8X16SubSatS: + case Opcode::I8X16SubSatU: + case Opcode::I16X8SubSatS: + case Opcode::I16X8SubSatU: + case Opcode::I8X16MinS: + case Opcode::I16X8MinS: + case Opcode::I32X4MinS: + case Opcode::I8X16MinU: + case Opcode::I16X8MinU: + case Opcode::I32X4MinU: + case Opcode::I8X16MaxS: + case Opcode::I16X8MaxS: + case Opcode::I32X4MaxS: + case Opcode::I8X16MaxU: + case Opcode::I16X8MaxU: + case Opcode::I32X4MaxU: + case Opcode::I8X16Shl: + case Opcode::I16X8Shl: + case Opcode::I32X4Shl: + case Opcode::I64X2Shl: + case Opcode::I8X16ShrS: + case Opcode::I8X16ShrU: + case Opcode::I16X8ShrS: + case Opcode::I16X8ShrU: + case Opcode::I32X4ShrS: + case Opcode::I32X4ShrU: + case Opcode::I64X2ShrS: + case Opcode::I64X2ShrU: + case Opcode::V128And: + case Opcode::V128Or: + case Opcode::V128Xor: + case Opcode::F32X4Min: + case Opcode::F32X4PMin: + case Opcode::F64X2Min: + case Opcode::F64X2PMin: + case Opcode::F32X4Max: + case Opcode::F32X4PMax: + case Opcode::F64X2Max: + case Opcode::F64X2PMax: + case Opcode::F32X4Add: + case Opcode::F64X2Add: + case Opcode::F32X4Sub: + case Opcode::F64X2Sub: + case Opcode::F32X4Div: + case Opcode::F64X2Div: + case Opcode::F32X4Mul: + case Opcode::F64X2Mul: + case Opcode::I8X16Swizzle: + case Opcode::I8X16NarrowI16X8S: + case Opcode::I8X16NarrowI16X8U: + case Opcode::I16X8NarrowI32X4S: + case Opcode::I16X8NarrowI32X4U: + case Opcode::V128Andnot: + case Opcode::I8X16AvgrU: + case Opcode::I16X8AvgrU: + CALLBACK(OnBinaryExpr, opcode); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::I32Eq: + case Opcode::I32Ne: + case Opcode::I32LtS: + case Opcode::I32LeS: + case Opcode::I32LtU: + case Opcode::I32LeU: + case Opcode::I32GtS: + case Opcode::I32GeS: + case Opcode::I32GtU: + case Opcode::I32GeU: + case Opcode::I64Eq: + case Opcode::I64Ne: + case Opcode::I64LtS: + case Opcode::I64LeS: + case Opcode::I64LtU: + case Opcode::I64LeU: + case Opcode::I64GtS: + case Opcode::I64GeS: + case Opcode::I64GtU: + case Opcode::I64GeU: + case Opcode::F32Eq: + case Opcode::F32Ne: + case Opcode::F32Lt: + case Opcode::F32Le: + case Opcode::F32Gt: + case Opcode::F32Ge: + case Opcode::F64Eq: + case Opcode::F64Ne: + case Opcode::F64Lt: + case Opcode::F64Le: + case Opcode::F64Gt: + case Opcode::F64Ge: + case Opcode::I8X16Eq: + case Opcode::I16X8Eq: + case Opcode::I32X4Eq: + case Opcode::F32X4Eq: + case Opcode::F64X2Eq: + case Opcode::I8X16Ne: + case Opcode::I16X8Ne: + case Opcode::I32X4Ne: + case Opcode::F32X4Ne: + case Opcode::F64X2Ne: + case Opcode::I8X16LtS: + case Opcode::I8X16LtU: + case Opcode::I16X8LtS: + case Opcode::I16X8LtU: + case Opcode::I32X4LtS: + case Opcode::I32X4LtU: + case Opcode::F32X4Lt: + case Opcode::F64X2Lt: + case Opcode::I8X16LeS: + case Opcode::I8X16LeU: + case Opcode::I16X8LeS: + case Opcode::I16X8LeU: + case Opcode::I32X4LeS: + case Opcode::I32X4LeU: + case Opcode::F32X4Le: + case Opcode::F64X2Le: + case Opcode::I8X16GtS: + case Opcode::I8X16GtU: + case Opcode::I16X8GtS: + case Opcode::I16X8GtU: + case Opcode::I32X4GtS: + case Opcode::I32X4GtU: + case Opcode::F32X4Gt: + case Opcode::F64X2Gt: + case Opcode::I8X16GeS: + case Opcode::I8X16GeU: + case Opcode::I16X8GeS: + case Opcode::I16X8GeU: + case Opcode::I32X4GeS: + case Opcode::I32X4GeU: + case Opcode::F32X4Ge: + case Opcode::F64X2Ge: + CALLBACK(OnCompareExpr, opcode); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::I32Clz: + case Opcode::I32Ctz: + case Opcode::I32Popcnt: + case Opcode::I64Clz: + case Opcode::I64Ctz: + case Opcode::I64Popcnt: + case Opcode::F32Abs: + case Opcode::F32Neg: + case Opcode::F32Ceil: + case Opcode::F32Floor: + case Opcode::F32Trunc: + case Opcode::F32Nearest: + case Opcode::F32Sqrt: + case Opcode::F64Abs: + case Opcode::F64Neg: + case Opcode::F64Ceil: + case Opcode::F64Floor: + case Opcode::F64Trunc: + case Opcode::F64Nearest: + case Opcode::F64Sqrt: + case Opcode::I8X16Splat: + case Opcode::I16X8Splat: + case Opcode::I32X4Splat: + case Opcode::I64X2Splat: + case Opcode::F32X4Splat: + case Opcode::F64X2Splat: + case Opcode::I8X16Neg: + case Opcode::I16X8Neg: + case Opcode::I32X4Neg: + case Opcode::I64X2Neg: + case Opcode::V128Not: + case Opcode::I8X16AnyTrue: + case Opcode::I16X8AnyTrue: + case Opcode::I32X4AnyTrue: + case Opcode::I8X16Bitmask: + case Opcode::I16X8Bitmask: + case Opcode::I32X4Bitmask: + case Opcode::I8X16AllTrue: + case Opcode::I16X8AllTrue: + case Opcode::I32X4AllTrue: + case Opcode::F32X4Ceil: + case Opcode::F64X2Ceil: + case Opcode::F32X4Floor: + case Opcode::F64X2Floor: + case Opcode::F32X4Trunc: + case Opcode::F64X2Trunc: + case Opcode::F32X4Nearest: + case Opcode::F64X2Nearest: + case Opcode::F32X4Neg: + case Opcode::F64X2Neg: + case Opcode::F32X4Abs: + case Opcode::F64X2Abs: + case Opcode::F32X4Sqrt: + case Opcode::F64X2Sqrt: + case Opcode::I16X8WidenLowI8X16S: + case Opcode::I16X8WidenHighI8X16S: + case Opcode::I16X8WidenLowI8X16U: + case Opcode::I16X8WidenHighI8X16U: + case Opcode::I32X4WidenLowI16X8S: + case Opcode::I32X4WidenHighI16X8S: + case Opcode::I32X4WidenLowI16X8U: + case Opcode::I32X4WidenHighI16X8U: + case Opcode::I8X16Abs: + case Opcode::I16X8Abs: + case Opcode::I32X4Abs: + CALLBACK(OnUnaryExpr, opcode); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::V128BitSelect: + CALLBACK(OnTernaryExpr, opcode); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::I8X16ExtractLaneS: + case Opcode::I8X16ExtractLaneU: + case Opcode::I16X8ExtractLaneS: + case Opcode::I16X8ExtractLaneU: + case Opcode::I32X4ExtractLane: + case Opcode::I64X2ExtractLane: + case Opcode::F32X4ExtractLane: + case Opcode::F64X2ExtractLane: + case Opcode::I8X16ReplaceLane: + case Opcode::I16X8ReplaceLane: + case Opcode::I32X4ReplaceLane: + case Opcode::I64X2ReplaceLane: + case Opcode::F32X4ReplaceLane: + case Opcode::F64X2ReplaceLane: { + uint8_t lane_val; + CHECK_RESULT(ReadU8(&lane_val, "Lane idx")); + CALLBACK(OnSimdLaneOpExpr, opcode, lane_val); + CALLBACK(OnOpcodeUint64, lane_val); + break; + } + + case Opcode::I8X16Shuffle: { + v128 value; + CHECK_RESULT(ReadV128(&value, "Lane idx [16]")); + CALLBACK(OnSimdShuffleOpExpr, opcode, value); + CALLBACK(OnOpcodeV128, value); + break; + } + + case Opcode::V128Load8Splat: + case Opcode::V128Load16Splat: + case Opcode::V128Load32Splat: + case Opcode::V128Load64Splat: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "load offset")); + + CALLBACK(OnLoadSplatExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + case Opcode::I32TruncF32S: + case Opcode::I32TruncF64S: + case Opcode::I32TruncF32U: + case Opcode::I32TruncF64U: + case Opcode::I32WrapI64: + case Opcode::I64TruncF32S: + case Opcode::I64TruncF64S: + case Opcode::I64TruncF32U: + case Opcode::I64TruncF64U: + case Opcode::I64ExtendI32S: + case Opcode::I64ExtendI32U: + case Opcode::F32ConvertI32S: + case Opcode::F32ConvertI32U: + case Opcode::F32ConvertI64S: + case Opcode::F32ConvertI64U: + case Opcode::F32DemoteF64: + case Opcode::F32ReinterpretI32: + case Opcode::F64ConvertI32S: + case Opcode::F64ConvertI32U: + case Opcode::F64ConvertI64S: + case Opcode::F64ConvertI64U: + case Opcode::F64PromoteF32: + case Opcode::F64ReinterpretI64: + case Opcode::I32ReinterpretF32: + case Opcode::I64ReinterpretF64: + case Opcode::I32Eqz: + case Opcode::I64Eqz: + case Opcode::F32X4ConvertI32X4S: + case Opcode::F32X4ConvertI32X4U: + case Opcode::I32X4TruncSatF32X4S: + case Opcode::I32X4TruncSatF32X4U: + CALLBACK(OnConvertExpr, opcode); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::Try: { + Type sig_type; + CHECK_RESULT(ReadType(&sig_type, "try signature type")); + ERROR_UNLESS(IsBlockType(sig_type), + "expected valid block signature type"); + CALLBACK(OnTryExpr, sig_type); + CALLBACK(OnOpcodeBlockSig, sig_type); + break; + } + + case Opcode::Catch: { + Index index; + CHECK_RESULT(ReadIndex(&index, "event index")); + CALLBACK(OnCatchExpr, index); + CALLBACK(OnOpcodeIndex, index); + break; + } + + case Opcode::CatchAll: { + CALLBACK(OnCatchAllExpr); + CALLBACK(OnOpcodeBare); + break; + } + + case Opcode::Unwind: { + CALLBACK0(OnUnwindExpr); + CALLBACK0(OnOpcodeBare); + break; + } + + case Opcode::Delegate: { + Index index; + CHECK_RESULT(ReadIndex(&index, "depth")); + CALLBACK(OnDelegateExpr, index); + CALLBACK(OnOpcodeIndex, index); + break; + } + + case Opcode::Rethrow: { + Index depth; + CHECK_RESULT(ReadIndex(&depth, "catch depth")); + CALLBACK(OnRethrowExpr, depth); + CALLBACK(OnOpcodeIndex, depth); + break; + } + + case Opcode::Throw: { + Index index; + CHECK_RESULT(ReadIndex(&index, "event index")); + CALLBACK(OnThrowExpr, index); + CALLBACK(OnOpcodeIndex, index); + break; + } + + case Opcode::I32Extend8S: + case Opcode::I32Extend16S: + case Opcode::I64Extend8S: + case Opcode::I64Extend16S: + case Opcode::I64Extend32S: + CALLBACK(OnUnaryExpr, opcode); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::I32TruncSatF32S: + case Opcode::I32TruncSatF32U: + case Opcode::I32TruncSatF64S: + case Opcode::I32TruncSatF64U: + case Opcode::I64TruncSatF32S: + case Opcode::I64TruncSatF32U: + case Opcode::I64TruncSatF64S: + case Opcode::I64TruncSatF64U: + CALLBACK(OnConvertExpr, opcode); + CALLBACK0(OnOpcodeBare); + break; + + case Opcode::MemoryAtomicNotify: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "load offset")); + + CALLBACK(OnAtomicNotifyExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::MemoryAtomicWait32: + case Opcode::MemoryAtomicWait64: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "load offset")); + + CALLBACK(OnAtomicWaitExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::AtomicFence: { + uint8_t consistency_model; + CHECK_RESULT(ReadU8(&consistency_model, "consistency model")); + ERROR_UNLESS(consistency_model == 0, + "atomic.fence consistency model must be 0"); + CALLBACK(OnAtomicFenceExpr, consistency_model); + CALLBACK(OnOpcodeUint32, consistency_model); + break; + } + + case Opcode::I32AtomicLoad8U: + case Opcode::I32AtomicLoad16U: + case Opcode::I64AtomicLoad8U: + case Opcode::I64AtomicLoad16U: + case Opcode::I64AtomicLoad32U: + case Opcode::I32AtomicLoad: + case Opcode::I64AtomicLoad: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "load alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "load offset")); + + CALLBACK(OnAtomicLoadExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::I32AtomicStore8: + case Opcode::I32AtomicStore16: + case Opcode::I64AtomicStore8: + case Opcode::I64AtomicStore16: + case Opcode::I64AtomicStore32: + case Opcode::I32AtomicStore: + case Opcode::I64AtomicStore: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "store alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "store offset")); + + CALLBACK(OnAtomicStoreExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::I32AtomicRmwAdd: + case Opcode::I64AtomicRmwAdd: + case Opcode::I32AtomicRmw8AddU: + case Opcode::I32AtomicRmw16AddU: + case Opcode::I64AtomicRmw8AddU: + case Opcode::I64AtomicRmw16AddU: + case Opcode::I64AtomicRmw32AddU: + case Opcode::I32AtomicRmwSub: + case Opcode::I64AtomicRmwSub: + case Opcode::I32AtomicRmw8SubU: + case Opcode::I32AtomicRmw16SubU: + case Opcode::I64AtomicRmw8SubU: + case Opcode::I64AtomicRmw16SubU: + case Opcode::I64AtomicRmw32SubU: + case Opcode::I32AtomicRmwAnd: + case Opcode::I64AtomicRmwAnd: + case Opcode::I32AtomicRmw8AndU: + case Opcode::I32AtomicRmw16AndU: + case Opcode::I64AtomicRmw8AndU: + case Opcode::I64AtomicRmw16AndU: + case Opcode::I64AtomicRmw32AndU: + case Opcode::I32AtomicRmwOr: + case Opcode::I64AtomicRmwOr: + case Opcode::I32AtomicRmw8OrU: + case Opcode::I32AtomicRmw16OrU: + case Opcode::I64AtomicRmw8OrU: + case Opcode::I64AtomicRmw16OrU: + case Opcode::I64AtomicRmw32OrU: + case Opcode::I32AtomicRmwXor: + case Opcode::I64AtomicRmwXor: + case Opcode::I32AtomicRmw8XorU: + case Opcode::I32AtomicRmw16XorU: + case Opcode::I64AtomicRmw8XorU: + case Opcode::I64AtomicRmw16XorU: + case Opcode::I64AtomicRmw32XorU: + case Opcode::I32AtomicRmwXchg: + case Opcode::I64AtomicRmwXchg: + case Opcode::I32AtomicRmw8XchgU: + case Opcode::I32AtomicRmw16XchgU: + case Opcode::I64AtomicRmw8XchgU: + case Opcode::I64AtomicRmw16XchgU: + case Opcode::I64AtomicRmw32XchgU: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "memory alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "memory offset")); + + CALLBACK(OnAtomicRmwExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::I32AtomicRmwCmpxchg: + case Opcode::I64AtomicRmwCmpxchg: + case Opcode::I32AtomicRmw8CmpxchgU: + case Opcode::I32AtomicRmw16CmpxchgU: + case Opcode::I64AtomicRmw8CmpxchgU: + case Opcode::I64AtomicRmw16CmpxchgU: + case Opcode::I64AtomicRmw32CmpxchgU: { + Address alignment_log2; + CHECK_RESULT(ReadAlignment(&alignment_log2, "memory alignment")); + Address offset; + CHECK_RESULT(ReadAddress(&offset, 0, "memory offset")); + + CALLBACK(OnAtomicRmwCmpxchgExpr, opcode, alignment_log2, offset); + CALLBACK(OnOpcodeUint32Uint32, alignment_log2, offset); + break; + } + + case Opcode::TableInit: { + Index segment; + CHECK_RESULT(ReadIndex(&segment, "elem segment index")); + Index table_index; + CHECK_RESULT(ReadIndex(&table_index, "reserved table index")); + CALLBACK(OnTableInitExpr, segment, table_index); + CALLBACK(OnOpcodeUint32Uint32, segment, table_index); + break; + } + + case Opcode::MemoryInit: { + Index segment; + ERROR_IF(data_count_ == kInvalidIndex, + "memory.init requires data count section"); + CHECK_RESULT(ReadIndex(&segment, "elem segment index")); + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); + ERROR_UNLESS(reserved == 0, "reserved value must be 0"); + CALLBACK(OnMemoryInitExpr, segment); + CALLBACK(OnOpcodeUint32Uint32, segment, reserved); + break; + } + + case Opcode::DataDrop: + ERROR_IF(data_count_ == kInvalidIndex, + "data.drop requires data count section"); + // Fallthrough. + case Opcode::ElemDrop: { + Index segment; + CHECK_RESULT(ReadIndex(&segment, "segment index")); + if (opcode == Opcode::DataDrop) { + CALLBACK(OnDataDropExpr, segment); + } else { + CALLBACK(OnElemDropExpr, segment); + } + CALLBACK(OnOpcodeUint32, segment); + break; + } + + case Opcode::MemoryFill: { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); + ERROR_UNLESS(reserved == 0, "reserved value must be 0"); + CALLBACK(OnMemoryFillExpr); + CALLBACK(OnOpcodeUint32, reserved); + break; + } + case Opcode::MemoryCopy: { + uint8_t reserved; + CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); + ERROR_UNLESS(reserved == 0, "reserved value must be 0"); + CHECK_RESULT(ReadU8(&reserved, "reserved memory index")); + ERROR_UNLESS(reserved == 0, "reserved value must be 0"); + CALLBACK(OnMemoryCopyExpr); + CALLBACK(OnOpcodeUint32Uint32, reserved, reserved); + break; + } + + case Opcode::TableCopy: { + Index table_dst; + Index table_src; + CHECK_RESULT(ReadIndex(&table_dst, "reserved table index")); + CHECK_RESULT(ReadIndex(&table_src, "table src")); + CALLBACK(OnTableCopyExpr, table_dst, table_src); + CALLBACK(OnOpcodeUint32Uint32, table_dst, table_src); + break; + } + + case Opcode::TableGet: { + Index table; + CHECK_RESULT(ReadIndex(&table, "table index")); + CALLBACK(OnTableGetExpr, table); + CALLBACK(OnOpcodeUint32, table); + break; + } + + case Opcode::TableSet: { + Index table; + CHECK_RESULT(ReadIndex(&table, "table index")); + CALLBACK(OnTableSetExpr, table); + CALLBACK(OnOpcodeUint32, table); + break; + } + + case Opcode::TableGrow: { + Index table; + CHECK_RESULT(ReadIndex(&table, "table index")); + CALLBACK(OnTableGrowExpr, table); + CALLBACK(OnOpcodeUint32, table); + break; + } + + case Opcode::TableSize: { + Index table; + CHECK_RESULT(ReadIndex(&table, "table index")); + CALLBACK(OnTableSizeExpr, table); + CALLBACK(OnOpcodeUint32, table); + break; + } + + case Opcode::TableFill: { + Index table; + CHECK_RESULT(ReadIndex(&table, "table index")); + CALLBACK(OnTableFillExpr, table); + CALLBACK(OnOpcodeUint32, table); + break; + } + + case Opcode::RefFunc: { + Index func; + CHECK_RESULT(ReadIndex(&func, "func index")); + CALLBACK(OnRefFuncExpr, func); + CALLBACK(OnOpcodeUint32, func); + break; + } + + case Opcode::RefNull: { + Type type; + CHECK_RESULT(ReadRefType(&type, "ref.null type")); + CALLBACK(OnRefNullExpr, type); + CALLBACK(OnOpcodeType, type); + break; + } + + case Opcode::RefIsNull: + CALLBACK(OnRefIsNullExpr); + CALLBACK(OnOpcodeBare); + break; + + default: + return ReportUnexpectedOpcode(opcode); + } + } + ERROR_UNLESS(state_.offset == end_offset, + "function body longer than given size"); + ERROR_UNLESS(seen_end_opcode, "function body must end with END opcode"); + return Result::Ok; +} + +Result BinaryReader::ReadNameSection(Offset section_size) { + CALLBACK(BeginNamesSection, section_size); + Index i = 0; + uint32_t previous_subsection_type = 0; + while (state_.offset < read_end_) { + uint32_t name_type; + Offset subsection_size; + CHECK_RESULT(ReadU32Leb128(&name_type, "name type")); + if (i != 0) { + ERROR_UNLESS(name_type != previous_subsection_type, + "duplicate sub-section"); + ERROR_UNLESS(name_type >= previous_subsection_type, + "out-of-order sub-section"); + } + previous_subsection_type = name_type; + CHECK_RESULT(ReadOffset(&subsection_size, "subsection size")); + size_t subsection_end = state_.offset + subsection_size; + ERROR_UNLESS(subsection_end <= read_end_, + "invalid sub-section size: extends past end"); + ReadEndRestoreGuard guard(this); + read_end_ = subsection_end; + + NameSectionSubsection type = static_cast(name_type); + if (type <= NameSectionSubsection::Last) { + CALLBACK(OnNameSubsection, i, type, subsection_size); + } + + switch (type) { + case NameSectionSubsection::Module: + CALLBACK(OnModuleNameSubsection, i, name_type, subsection_size); + if (subsection_size) { + string_view name; + CHECK_RESULT(ReadStr(&name, "module name")); + CALLBACK(OnModuleName, name); + } + break; + case NameSectionSubsection::Function: + CALLBACK(OnFunctionNameSubsection, i, name_type, subsection_size); + if (subsection_size) { + Index num_names; + CHECK_RESULT(ReadCount(&num_names, "name count")); + CALLBACK(OnFunctionNamesCount, num_names); + Index last_function_index = kInvalidIndex; + + for (Index j = 0; j < num_names; ++j) { + Index function_index; + string_view function_name; + + CHECK_RESULT(ReadIndex(&function_index, "function index")); + ERROR_UNLESS(function_index != last_function_index, + "duplicate function name: %u", function_index); + ERROR_UNLESS(last_function_index == kInvalidIndex || + function_index > last_function_index, + "function index out of order: %u", function_index); + last_function_index = function_index; + ERROR_UNLESS(function_index < NumTotalFuncs(), + "invalid function index: %" PRIindex, function_index); + CHECK_RESULT(ReadStr(&function_name, "function name")); + CALLBACK(OnFunctionName, function_index, function_name); + } + } + break; + case NameSectionSubsection::Local: + CALLBACK(OnLocalNameSubsection, i, name_type, subsection_size); + if (subsection_size) { + Index num_funcs; + CHECK_RESULT(ReadCount(&num_funcs, "function count")); + CALLBACK(OnLocalNameFunctionCount, num_funcs); + Index last_function_index = kInvalidIndex; + for (Index j = 0; j < num_funcs; ++j) { + Index function_index; + CHECK_RESULT(ReadIndex(&function_index, "function index")); + ERROR_UNLESS(function_index < NumTotalFuncs(), + "invalid function index: %u", function_index); + ERROR_UNLESS(last_function_index == kInvalidIndex || + function_index > last_function_index, + "locals function index out of order: %u", + function_index); + last_function_index = function_index; + Index num_locals; + CHECK_RESULT(ReadCount(&num_locals, "local count")); + CALLBACK(OnLocalNameLocalCount, function_index, num_locals); + Index last_local_index = kInvalidIndex; + for (Index k = 0; k < num_locals; ++k) { + Index local_index; + string_view local_name; + + CHECK_RESULT(ReadIndex(&local_index, "named index")); + ERROR_UNLESS(local_index != last_local_index, + "duplicate local index: %u", local_index); + ERROR_UNLESS(last_local_index == kInvalidIndex || + local_index > last_local_index, + "local index out of order: %u", local_index); + last_local_index = local_index; + CHECK_RESULT(ReadStr(&local_name, "name")); + CALLBACK(OnLocalName, function_index, local_index, local_name); + } + } + } + break; + case NameSectionSubsection::Label: + // TODO(sbc): Implement label names. These are slightly more complicated + // since they refer to offsets in the code section / instruction stream. + state_.offset = subsection_end; + break; + case NameSectionSubsection::Type: + case NameSectionSubsection::Table: + case NameSectionSubsection::Memory: + case NameSectionSubsection::Global: + case NameSectionSubsection::ElemSegment: + case NameSectionSubsection::DataSegment: + if (subsection_size) { + Index num_names; + CHECK_RESULT(ReadCount(&num_names, "name count")); + CALLBACK(OnNameCount, num_names); + for (Index j = 0; j < num_names; ++j) { + Index index; + string_view name; + + CHECK_RESULT(ReadIndex(&index, "index")); + CHECK_RESULT(ReadStr(&name, "name")); + CALLBACK(OnNameEntry, type, index, name); + } + } + state_.offset = subsection_end; + break; + default: + // Unknown subsection, skip it. + state_.offset = subsection_end; + break; + } + ++i; + ERROR_UNLESS(state_.offset == subsection_end, + "unfinished sub-section (expected end: 0x%" PRIzx ")", + subsection_end); + } + CALLBACK0(EndNamesSection); + return Result::Ok; +} + +Result BinaryReader::ReadRelocSection(Offset section_size) { + CALLBACK(BeginRelocSection, section_size); + uint32_t section_index; + CHECK_RESULT(ReadU32Leb128(§ion_index, "section index")); + Index num_relocs; + CHECK_RESULT(ReadCount(&num_relocs, "relocation count")); + CALLBACK(OnRelocCount, num_relocs, section_index); + for (Index i = 0; i < num_relocs; ++i) { + Offset offset; + Index index; + uint32_t reloc_type, addend = 0; + CHECK_RESULT(ReadU32Leb128(&reloc_type, "relocation type")); + CHECK_RESULT(ReadOffset(&offset, "offset")); + CHECK_RESULT(ReadIndex(&index, "index")); + RelocType type = static_cast(reloc_type); + switch (type) { + case RelocType::MemoryAddressLEB: + case RelocType::MemoryAddressLEB64: + case RelocType::MemoryAddressSLEB: + case RelocType::MemoryAddressSLEB64: + case RelocType::MemoryAddressRelSLEB: + case RelocType::MemoryAddressRelSLEB64: + case RelocType::MemoryAddressI32: + case RelocType::MemoryAddressI64: + case RelocType::FunctionOffsetI32: + case RelocType::SectionOffsetI32: + case RelocType::MemoryAddressTLSSLEB: + case RelocType::MemoryAddressTLSI32: + CHECK_RESULT(ReadS32Leb128(&addend, "addend")); + break; + + case RelocType::FuncIndexLEB: + case RelocType::TableIndexSLEB: + case RelocType::TableIndexSLEB64: + case RelocType::TableIndexI32: + case RelocType::TableIndexI64: + case RelocType::TypeIndexLEB: + case RelocType::GlobalIndexLEB: + case RelocType::GlobalIndexI32: + case RelocType::EventIndexLEB: + case RelocType::TableIndexRelSLEB: + case RelocType::TableNumberLEB: + break; + + default: + PrintError("unknown reloc type: %s", GetRelocTypeName(type)); + return Result::Error; + } + CALLBACK(OnReloc, type, offset, index, addend); + } + CALLBACK0(EndRelocSection); + return Result::Ok; +} + +Result BinaryReader::ReadDylinkSection(Offset section_size) { + CALLBACK(BeginDylinkSection, section_size); + uint32_t mem_size; + uint32_t mem_align; + uint32_t table_size; + uint32_t table_align; + + CHECK_RESULT(ReadU32Leb128(&mem_size, "mem_size")); + CHECK_RESULT(ReadU32Leb128(&mem_align, "mem_align")); + CHECK_RESULT(ReadU32Leb128(&table_size, "table_size")); + CHECK_RESULT(ReadU32Leb128(&table_align, "table_align")); + CALLBACK(OnDylinkInfo, mem_size, mem_align, table_size, table_align); + + uint32_t count; + CHECK_RESULT(ReadU32Leb128(&count, "needed_dynlibs")); + CALLBACK(OnDylinkNeededCount, count); + while (count--) { + string_view so_name; + CHECK_RESULT(ReadStr(&so_name, "dylib so_name")); + CALLBACK(OnDylinkNeeded, so_name); + } + + CALLBACK0(EndDylinkSection); + return Result::Ok; +} + +Result BinaryReader::ReadLinkingSection(Offset section_size) { + CALLBACK(BeginLinkingSection, section_size); + uint32_t version; + CHECK_RESULT(ReadU32Leb128(&version, "version")); + ERROR_UNLESS(version == 2, "invalid linking metadata version: %u", version); + while (state_.offset < read_end_) { + uint32_t linking_type; + Offset subsection_size; + CHECK_RESULT(ReadU32Leb128(&linking_type, "type")); + CHECK_RESULT(ReadOffset(&subsection_size, "subsection size")); + size_t subsection_end = state_.offset + subsection_size; + ERROR_UNLESS(subsection_end <= read_end_, + "invalid sub-section size: extends past end"); + ReadEndRestoreGuard guard(this); + read_end_ = subsection_end; + + uint32_t count; + switch (static_cast(linking_type)) { + case LinkingEntryType::SymbolTable: + CHECK_RESULT(ReadU32Leb128(&count, "sym count")); + CALLBACK(OnSymbolCount, count); + for (Index i = 0; i < count; ++i) { + string_view name; + uint32_t flags = 0; + uint32_t kind = 0; + CHECK_RESULT(ReadU32Leb128(&kind, "sym type")); + CHECK_RESULT(ReadU32Leb128(&flags, "sym flags")); + SymbolType sym_type = static_cast(kind); + CALLBACK(OnSymbol, i, sym_type, flags); + switch (sym_type) { + case SymbolType::Function: + case SymbolType::Global: + case SymbolType::Event: + case SymbolType::Table: { + uint32_t index = 0; + CHECK_RESULT(ReadU32Leb128(&index, "index")); + if ((flags & WABT_SYMBOL_FLAG_UNDEFINED) == 0 || + (flags & WABT_SYMBOL_FLAG_EXPLICIT_NAME) != 0) + CHECK_RESULT(ReadStr(&name, "symbol name")); + switch (sym_type) { + case SymbolType::Function: + CALLBACK(OnFunctionSymbol, i, flags, name, index); + break; + case SymbolType::Global: + CALLBACK(OnGlobalSymbol, i, flags, name, index); + break; + case SymbolType::Event: + CALLBACK(OnEventSymbol, i, flags, name, index); + break; + case SymbolType::Table: + CALLBACK(OnTableSymbol, i, flags, name, index); + break; + default: + WABT_UNREACHABLE; + } + break; + } + case SymbolType::Data: { + uint32_t segment = 0; + uint32_t offset = 0; + uint32_t size = 0; + CHECK_RESULT(ReadStr(&name, "symbol name")); + if ((flags & WABT_SYMBOL_FLAG_UNDEFINED) == 0) { + CHECK_RESULT(ReadU32Leb128(&segment, "segment")); + CHECK_RESULT(ReadU32Leb128(&offset, "offset")); + CHECK_RESULT(ReadU32Leb128(&size, "size")); + } + CALLBACK(OnDataSymbol, i, flags, name, segment, offset, size); + break; + } + case SymbolType::Section: { + uint32_t index = 0; + CHECK_RESULT(ReadU32Leb128(&index, "index")); + CALLBACK(OnSectionSymbol, i, flags, index); + break; + } + } + } + break; + case LinkingEntryType::SegmentInfo: + CHECK_RESULT(ReadU32Leb128(&count, "info count")); + CALLBACK(OnSegmentInfoCount, count); + for (Index i = 0; i < count; i++) { + string_view name; + Address alignment_log2; + uint32_t flags; + CHECK_RESULT(ReadStr(&name, "segment name")); + CHECK_RESULT(ReadAlignment(&alignment_log2, "segment alignment")); + CHECK_RESULT(ReadU32Leb128(&flags, "segment flags")); + CALLBACK(OnSegmentInfo, i, name, alignment_log2, flags); + } + break; + case LinkingEntryType::InitFunctions: + CHECK_RESULT(ReadU32Leb128(&count, "info count")); + CALLBACK(OnInitFunctionCount, count); + while (count--) { + uint32_t priority; + uint32_t func; + CHECK_RESULT(ReadU32Leb128(&priority, "priority")); + CHECK_RESULT(ReadU32Leb128(&func, "function index")); + CALLBACK(OnInitFunction, priority, func); + } + break; + case LinkingEntryType::ComdatInfo: + CHECK_RESULT(ReadU32Leb128(&count, "count")); + CALLBACK(OnComdatCount, count); + while (count--) { + uint32_t flags; + uint32_t entry_count; + string_view name; + CHECK_RESULT(ReadStr(&name, "comdat name")); + CHECK_RESULT(ReadU32Leb128(&flags, "flags")); + CHECK_RESULT(ReadU32Leb128(&entry_count, "entry count")); + CALLBACK(OnComdatBegin, name, flags, entry_count); + while (entry_count--) { + uint32_t kind; + uint32_t index; + CHECK_RESULT(ReadU32Leb128(&kind, "kind")); + CHECK_RESULT(ReadU32Leb128(&index, "index")); + ComdatType comdat_type = static_cast(kind); + CALLBACK(OnComdatEntry, comdat_type, index); + } + } + break; + default: + // Unknown subsection, skip it. + state_.offset = subsection_end; + break; + } + ERROR_UNLESS(state_.offset == subsection_end, + "unfinished sub-section (expected end: 0x%" PRIzx ")", + subsection_end); + } + CALLBACK0(EndLinkingSection); + return Result::Ok; +} + +Result BinaryReader::ReadEventType(Index* out_sig_index) { + uint32_t attribute; + CHECK_RESULT(ReadU32Leb128(&attribute, "event attribute")); + ERROR_UNLESS(attribute == 0, "event attribute must be 0"); + CHECK_RESULT(ReadIndex(out_sig_index, "event signature index")); + return Result::Ok; +} + +Result BinaryReader::ReadEventSection(Offset section_size) { + CALLBACK(BeginEventSection, section_size); + Index num_events; + CHECK_RESULT(ReadCount(&num_events, "event count")); + CALLBACK(OnEventCount, num_events); + + for (Index i = 0; i < num_events; ++i) { + Index event_index = num_event_imports_ + i; + Index sig_index; + CHECK_RESULT(ReadEventType(&sig_index)); + CALLBACK(OnEventType, event_index, sig_index); + } + + CALLBACK(EndEventSection); + return Result::Ok; +} + +Result BinaryReader::ReadCustomSection(Index section_index, + Offset section_size) { + string_view section_name; + CHECK_RESULT(ReadStr(§ion_name, "section name")); + CALLBACK(BeginCustomSection, section_index, section_size, section_name); + ValueRestoreGuard guard(this); + reading_custom_section_ = true; + + if (options_.read_debug_names && section_name == WABT_BINARY_SECTION_NAME) { + CHECK_RESULT(ReadNameSection(section_size)); + did_read_names_section_ = true; + } else if (section_name == WABT_BINARY_SECTION_DYLINK) { + CHECK_RESULT(ReadDylinkSection(section_size)); + } else if (section_name.rfind(WABT_BINARY_SECTION_RELOC, 0) == 0) { + // Reloc sections always begin with "reloc." + CHECK_RESULT(ReadRelocSection(section_size)); + } else if (section_name == WABT_BINARY_SECTION_LINKING) { + CHECK_RESULT(ReadLinkingSection(section_size)); + } else { + // This is an unknown custom section, skip it. + state_.offset = read_end_; + } + CALLBACK0(EndCustomSection); + return Result::Ok; +} + +Result BinaryReader::ReadTypeSection(Offset section_size) { + CALLBACK(BeginTypeSection, section_size); + Index num_signatures; + CHECK_RESULT(ReadCount(&num_signatures, "type count")); + CALLBACK(OnTypeCount, num_signatures); + + for (Index i = 0; i < num_signatures; ++i) { + Type form; + CHECK_RESULT(ReadType(&form, "type form")); + + switch (form) { + case Type::Func: { + Index num_params; + CHECK_RESULT(ReadCount(&num_params, "function param count")); + + param_types_.resize(num_params); + + for (Index j = 0; j < num_params; ++j) { + Type param_type; + CHECK_RESULT(ReadType(¶m_type, "function param type")); + ERROR_UNLESS(IsConcreteType(param_type), + "expected valid param type (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(param_type)); + param_types_[j] = param_type; + } + + Index num_results; + CHECK_RESULT(ReadCount(&num_results, "function result count")); + + result_types_.resize(num_results); + + for (Index j = 0; j < num_results; ++j) { + Type result_type; + CHECK_RESULT(ReadType(&result_type, "function result type")); + ERROR_UNLESS(IsConcreteType(result_type), + "expected valid result type (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(result_type)); + result_types_[j] = result_type; + } + + Type* param_types = num_params ? param_types_.data() : nullptr; + Type* result_types = num_results ? result_types_.data() : nullptr; + + CALLBACK(OnFuncType, i, num_params, param_types, num_results, + result_types); + break; + } + + case Type::Struct: { + ERROR_UNLESS(options_.features.gc_enabled(), + "invalid type form: struct not allowed"); + Index num_fields; + CHECK_RESULT(ReadCount(&num_fields, "field count")); + + fields_.resize(num_fields); + for (Index j = 0; j < num_fields; ++j) { + CHECK_RESULT(ReadField(&fields_[j])); + } + + CALLBACK(OnStructType, i, fields_.size(), fields_.data()); + break; + } + + case Type::Array: { + ERROR_UNLESS(options_.features.gc_enabled(), + "invalid type form: array not allowed"); + + TypeMut field; + CHECK_RESULT(ReadField(&field)); + CALLBACK(OnArrayType, i, field); + break; + }; + + default: + PrintError("unexpected type form (got " PRItypecode ")", + WABT_PRINTF_TYPE_CODE(form)); + return Result::Error; + } + } + CALLBACK0(EndTypeSection); + return Result::Ok; +} + +Result BinaryReader::ReadImportSection(Offset section_size) { + CALLBACK(BeginImportSection, section_size); + Index num_imports; + CHECK_RESULT(ReadCount(&num_imports, "import count")); + CALLBACK(OnImportCount, num_imports); + for (Index i = 0; i < num_imports; ++i) { + string_view module_name; + CHECK_RESULT(ReadStr(&module_name, "import module name")); + string_view field_name; + CHECK_RESULT(ReadStr(&field_name, "import field name")); + + uint8_t kind; + CHECK_RESULT(ReadU8(&kind, "import kind")); + CALLBACK(OnImport, i, static_cast(kind), module_name, + field_name); + switch (static_cast(kind)) { + case ExternalKind::Func: { + Index sig_index; + CHECK_RESULT(ReadIndex(&sig_index, "import signature index")); + CALLBACK(OnImportFunc, i, module_name, field_name, num_func_imports_, + sig_index); + num_func_imports_++; + break; + } + + case ExternalKind::Table: { + Type elem_type; + Limits elem_limits; + CHECK_RESULT(ReadTable(&elem_type, &elem_limits)); + CALLBACK(OnImportTable, i, module_name, field_name, num_table_imports_, + elem_type, &elem_limits); + num_table_imports_++; + break; + } + + case ExternalKind::Memory: { + Limits page_limits; + CHECK_RESULT(ReadMemory(&page_limits)); + CALLBACK(OnImportMemory, i, module_name, field_name, + num_memory_imports_, &page_limits); + num_memory_imports_++; + break; + } + + case ExternalKind::Global: { + Type type; + bool mutable_; + CHECK_RESULT(ReadGlobalHeader(&type, &mutable_)); + CALLBACK(OnImportGlobal, i, module_name, field_name, + num_global_imports_, type, mutable_); + num_global_imports_++; + break; + } + + case ExternalKind::Event: { + ERROR_UNLESS(options_.features.exceptions_enabled(), + "invalid import event kind: exceptions not allowed"); + Index sig_index; + CHECK_RESULT(ReadEventType(&sig_index)); + CALLBACK(OnImportEvent, i, module_name, field_name, num_event_imports_, + sig_index); + num_event_imports_++; + break; + } + + default: + PrintError("malformed import kind: %d", kind); + return Result::Error; + } + } + + CALLBACK0(EndImportSection); + return Result::Ok; +} + +Result BinaryReader::ReadFunctionSection(Offset section_size) { + CALLBACK(BeginFunctionSection, section_size); + CHECK_RESULT( + ReadCount(&num_function_signatures_, "function signature count")); + CALLBACK(OnFunctionCount, num_function_signatures_); + for (Index i = 0; i < num_function_signatures_; ++i) { + Index func_index = num_func_imports_ + i; + Index sig_index; + CHECK_RESULT(ReadIndex(&sig_index, "function signature index")); + CALLBACK(OnFunction, func_index, sig_index); + } + CALLBACK0(EndFunctionSection); + return Result::Ok; +} + +Result BinaryReader::ReadTableSection(Offset section_size) { + CALLBACK(BeginTableSection, section_size); + Index num_tables; + CHECK_RESULT(ReadCount(&num_tables, "table count")); + CALLBACK(OnTableCount, num_tables); + for (Index i = 0; i < num_tables; ++i) { + Index table_index = num_table_imports_ + i; + Type elem_type; + Limits elem_limits; + CHECK_RESULT(ReadTable(&elem_type, &elem_limits)); + CALLBACK(OnTable, table_index, elem_type, &elem_limits); + } + CALLBACK0(EndTableSection); + return Result::Ok; +} + +Result BinaryReader::ReadMemorySection(Offset section_size) { + CALLBACK(BeginMemorySection, section_size); + Index num_memories; + CHECK_RESULT(ReadCount(&num_memories, "memory count")); + CALLBACK(OnMemoryCount, num_memories); + for (Index i = 0; i < num_memories; ++i) { + Index memory_index = num_memory_imports_ + i; + Limits page_limits; + CHECK_RESULT(ReadMemory(&page_limits)); + CALLBACK(OnMemory, memory_index, &page_limits); + } + CALLBACK0(EndMemorySection); + return Result::Ok; +} + +Result BinaryReader::ReadGlobalSection(Offset section_size) { + CALLBACK(BeginGlobalSection, section_size); + Index num_globals; + CHECK_RESULT(ReadCount(&num_globals, "global count")); + CALLBACK(OnGlobalCount, num_globals); + for (Index i = 0; i < num_globals; ++i) { + Index global_index = num_global_imports_ + i; + Type global_type; + bool mutable_; + CHECK_RESULT(ReadGlobalHeader(&global_type, &mutable_)); + CALLBACK(BeginGlobal, global_index, global_type, mutable_); + CALLBACK(BeginGlobalInitExpr, global_index); + CHECK_RESULT(ReadInitExpr(global_index)); + CALLBACK(EndGlobalInitExpr, global_index); + CALLBACK(EndGlobal, global_index); + } + CALLBACK0(EndGlobalSection); + return Result::Ok; +} + +Result BinaryReader::ReadExportSection(Offset section_size) { + CALLBACK(BeginExportSection, section_size); + Index num_exports; + CHECK_RESULT(ReadCount(&num_exports, "export count")); + CALLBACK(OnExportCount, num_exports); + for (Index i = 0; i < num_exports; ++i) { + string_view name; + CHECK_RESULT(ReadStr(&name, "export item name")); + + ExternalKind kind; + CHECK_RESULT(ReadExternalKind(&kind, "export kind")); + + Index item_index; + CHECK_RESULT(ReadIndex(&item_index, "export item index")); + if (kind == ExternalKind::Event) { + ERROR_UNLESS(options_.features.exceptions_enabled(), + "invalid export event kind: exceptions not allowed"); + } + + CALLBACK(OnExport, i, static_cast(kind), item_index, name); + } + CALLBACK0(EndExportSection); + return Result::Ok; +} + +Result BinaryReader::ReadStartSection(Offset section_size) { + CALLBACK(BeginStartSection, section_size); + Index func_index; + CHECK_RESULT(ReadIndex(&func_index, "start function index")); + CALLBACK(OnStartFunction, func_index); + CALLBACK0(EndStartSection); + return Result::Ok; +} + +Result BinaryReader::ReadElemSection(Offset section_size) { + CALLBACK(BeginElemSection, section_size); + Index num_elem_segments; + CHECK_RESULT(ReadCount(&num_elem_segments, "elem segment count")); + CALLBACK(OnElemSegmentCount, num_elem_segments); + for (Index i = 0; i < num_elem_segments; ++i) { + uint32_t flags; + CHECK_RESULT(ReadU32Leb128(&flags, "elem segment flags")); + ERROR_IF(flags > SegFlagMax, "invalid elem segment flags: %#x", flags); + Index table_index(0); + if ((flags & (SegPassive | SegExplicitIndex)) == SegExplicitIndex) { + CHECK_RESULT(ReadIndex(&table_index, "elem segment table index")); + } + Type elem_type = Type::FuncRef; + + CALLBACK(BeginElemSegment, i, table_index, flags); + + if (!(flags & SegPassive)) { + CALLBACK(BeginElemSegmentInitExpr, i); + CHECK_RESULT(ReadI32InitExpr(i)); + CALLBACK(EndElemSegmentInitExpr, i); + } + + // For backwards compat we support not declaring the element kind. + if (flags & (SegPassive | SegExplicitIndex)) { + if (flags & SegUseElemExprs) { + CHECK_RESULT(ReadRefType(&elem_type, "table elem type")); + } else { + ExternalKind kind; + CHECK_RESULT(ReadExternalKind(&kind, "export kind")); + ERROR_UNLESS(kind == ExternalKind::Func, + "segment elem type must be func (%s)", + elem_type.GetName()); + elem_type = Type::FuncRef; + } + } + + CALLBACK(OnElemSegmentElemType, i, elem_type); + + Index num_elem_exprs; + CHECK_RESULT(ReadCount(&num_elem_exprs, "elem count")); + + CALLBACK(OnElemSegmentElemExprCount, i, num_elem_exprs); + for (Index j = 0; j < num_elem_exprs; ++j) { + if (flags & SegUseElemExprs) { + Opcode opcode; + CHECK_RESULT(ReadOpcode(&opcode, "elem expr opcode")); + if (opcode == Opcode::RefNull) { + Type type; + CHECK_RESULT(ReadRefType(&type, "elem expr ref.null type")); + CALLBACK(OnElemSegmentElemExpr_RefNull, i, type); + } else if (opcode == Opcode::RefFunc) { + Index func_index; + CHECK_RESULT(ReadIndex(&func_index, "elem expr func index")); + CALLBACK(OnElemSegmentElemExpr_RefFunc, i, func_index); + } else { + PrintError( + "expected ref.null or ref.func in passive element segment"); + } + CHECK_RESULT(ReadOpcode(&opcode, "opcode")); + ERROR_UNLESS(opcode == Opcode::End, + "expected END opcode after element expression"); + } else { + Index func_index; + CHECK_RESULT(ReadIndex(&func_index, "elem expr func index")); + CALLBACK(OnElemSegmentElemExpr_RefFunc, i, func_index); + } + } + CALLBACK(EndElemSegment, i); + } + CALLBACK0(EndElemSection); + return Result::Ok; +} + +Result BinaryReader::ReadCodeSection(Offset section_size) { + CALLBACK(BeginCodeSection, section_size); + CHECK_RESULT(ReadCount(&num_function_bodies_, "function body count")); + ERROR_UNLESS(num_function_signatures_ == num_function_bodies_, + "function signature count != function body count"); + CALLBACK(OnFunctionBodyCount, num_function_bodies_); + for (Index i = 0; i < num_function_bodies_; ++i) { + Index func_index = num_func_imports_ + i; + Offset func_offset = state_.offset; + state_.offset = func_offset; + uint32_t body_size; + CHECK_RESULT(ReadU32Leb128(&body_size, "function body size")); + Offset body_start_offset = state_.offset; + Offset end_offset = body_start_offset + body_size; + CALLBACK(BeginFunctionBody, func_index, body_size); + + uint64_t total_locals = 0; + Index num_local_decls; + CHECK_RESULT(ReadCount(&num_local_decls, "local declaration count")); + CALLBACK(OnLocalDeclCount, num_local_decls); + for (Index k = 0; k < num_local_decls; ++k) { + Index num_local_types; + CHECK_RESULT(ReadIndex(&num_local_types, "local type count")); + total_locals += num_local_types; + ERROR_UNLESS(total_locals < UINT32_MAX, + "local count must be < 0x10000000"); + Type local_type; + CHECK_RESULT(ReadType(&local_type, "local type")); + ERROR_UNLESS(IsConcreteType(local_type), "expected valid local type"); + CALLBACK(OnLocalDecl, k, num_local_types, local_type); + } + + CHECK_RESULT(ReadFunctionBody(end_offset)); + + CALLBACK(EndFunctionBody, func_index); + } + CALLBACK0(EndCodeSection); + return Result::Ok; +} + +Result BinaryReader::ReadDataSection(Offset section_size) { + CALLBACK(BeginDataSection, section_size); + Index num_data_segments; + CHECK_RESULT(ReadCount(&num_data_segments, "data segment count")); + CALLBACK(OnDataSegmentCount, num_data_segments); + // If the DataCount section is not present, then data_count_ will be invalid. + ERROR_UNLESS(data_count_ == kInvalidIndex || data_count_ == num_data_segments, + "data segment count does not equal count in DataCount section"); + for (Index i = 0; i < num_data_segments; ++i) { + uint32_t flags; + CHECK_RESULT(ReadU32Leb128(&flags, "data segment flags")); + ERROR_IF(flags != 0 && !options_.features.bulk_memory_enabled(), + "invalid memory index %d: bulk memory not allowed", flags); + ERROR_IF(flags > SegFlagMax, "invalid data segment flags: %#x", flags); + Index memory_index(0); + if (flags & SegExplicitIndex) { + CHECK_RESULT(ReadIndex(&memory_index, "data segment memory index")); + } + CALLBACK(BeginDataSegment, i, memory_index, flags); + if (!(flags & SegPassive)) { + CALLBACK(BeginDataSegmentInitExpr, i); + CHECK_RESULT(ReadI32InitExpr(i)); + CALLBACK(EndDataSegmentInitExpr, i); + } + + Address data_size; + const void* data; + CHECK_RESULT(ReadBytes(&data, &data_size, "data segment data")); + CALLBACK(OnDataSegmentData, i, data, data_size); + CALLBACK(EndDataSegment, i); + } + CALLBACK0(EndDataSection); + return Result::Ok; +} + +Result BinaryReader::ReadDataCountSection(Offset section_size) { + CALLBACK(BeginDataCountSection, section_size); + Index data_count; + CHECK_RESULT(ReadIndex(&data_count, "data count")); + CALLBACK(OnDataCount, data_count); + CALLBACK0(EndDataCountSection); + data_count_ = data_count; + return Result::Ok; +} + +Result BinaryReader::ReadSections() { + Result result = Result::Ok; + Index section_index = 0; + bool seen_section_code[static_cast(BinarySection::Last) + 1] = {false}; + + for (; state_.offset < state_.size; ++section_index) { + uint8_t section_code; + Offset section_size; + CHECK_RESULT(ReadU8(§ion_code, "section code")); + CHECK_RESULT(ReadOffset(§ion_size, "section size")); + ReadEndRestoreGuard guard(this); + read_end_ = state_.offset + section_size; + if (section_code >= kBinarySectionCount) { + PrintError("invalid section code: %u", section_code); + return Result::Error; + } + + BinarySection section = static_cast(section_code); + if (section != BinarySection::Custom) { + if (seen_section_code[section_code]) { + PrintError("multiple %s sections", GetSectionName(section)); + return Result::Error; + } + seen_section_code[section_code] = true; + } + + ERROR_UNLESS(read_end_ <= state_.size, + "invalid section size: extends past end"); + + ERROR_UNLESS( + last_known_section_ == BinarySection::Invalid || + section == BinarySection::Custom || + GetSectionOrder(section) > GetSectionOrder(last_known_section_), + "section %s out of order", GetSectionName(section)); + + ERROR_UNLESS(!did_read_names_section_ || section == BinarySection::Custom, + "%s section can not occur after Name section", + GetSectionName(section)); + + CALLBACK(BeginSection, section_index, section, section_size); + + bool stop_on_first_error = options_.stop_on_first_error; + Result section_result = Result::Error; + switch (section) { + case BinarySection::Custom: + section_result = ReadCustomSection(section_index, section_size); + if (options_.fail_on_custom_section_error) { + result |= section_result; + } else { + stop_on_first_error = false; + } + break; + case BinarySection::Type: + section_result = ReadTypeSection(section_size); + result |= section_result; + break; + case BinarySection::Import: + section_result = ReadImportSection(section_size); + result |= section_result; + break; + case BinarySection::Function: + section_result = ReadFunctionSection(section_size); + result |= section_result; + break; + case BinarySection::Table: + section_result = ReadTableSection(section_size); + result |= section_result; + break; + case BinarySection::Memory: + section_result = ReadMemorySection(section_size); + result |= section_result; + break; + case BinarySection::Global: + section_result = ReadGlobalSection(section_size); + result |= section_result; + break; + case BinarySection::Export: + section_result = ReadExportSection(section_size); + result |= section_result; + break; + case BinarySection::Start: + section_result = ReadStartSection(section_size); + result |= section_result; + break; + case BinarySection::Elem: + section_result = ReadElemSection(section_size); + result |= section_result; + break; + case BinarySection::Code: + section_result = ReadCodeSection(section_size); + result |= section_result; + break; + case BinarySection::Data: + section_result = ReadDataSection(section_size); + result |= section_result; + break; + case BinarySection::Event: + ERROR_UNLESS(options_.features.exceptions_enabled(), + "invalid section code: %u", + static_cast(section)); + section_result = ReadEventSection(section_size); + result |= section_result; + break; + case BinarySection::DataCount: + ERROR_UNLESS(options_.features.bulk_memory_enabled(), + "invalid section code: %u", + static_cast(section)); + section_result = ReadDataCountSection(section_size); + result |= section_result; + break; + case BinarySection::Invalid: + WABT_UNREACHABLE; + } + + if (Succeeded(section_result) && state_.offset != read_end_) { + PrintError("unfinished section (expected end: 0x%" PRIzx ")", read_end_); + section_result = Result::Error; + result |= section_result; + } + + if (Failed(section_result)) { + if (stop_on_first_error) { + return Result::Error; + } + + // If we're continuing after failing to read this section, move the + // offset to the expected section end. This way we may be able to read + // further sections. + state_.offset = read_end_; + } + + if (section != BinarySection::Custom) { + last_known_section_ = section; + } + } + + return result; +} + +Result BinaryReader::ReadModule() { + uint32_t magic = 0; + CHECK_RESULT(ReadU32(&magic, "magic")); + ERROR_UNLESS(magic == WABT_BINARY_MAGIC, "bad magic value"); + uint32_t version = 0; + CHECK_RESULT(ReadU32(&version, "version")); + ERROR_UNLESS(version == WABT_BINARY_VERSION, + "bad wasm file version: %#x (expected %#x)", version, + WABT_BINARY_VERSION); + + CALLBACK(BeginModule, version); + CHECK_RESULT(ReadSections()); + // This is checked in ReadCodeSection, but it must be checked at the end too, + // in case the code section was omitted. + ERROR_UNLESS(num_function_signatures_ == num_function_bodies_, + "function signature count != function body count"); + CALLBACK0(EndModule); + + return Result::Ok; +} + +} // end anonymous namespace + +Result ReadBinary(const void* data, + size_t size, + BinaryReaderDelegate* delegate, + const ReadBinaryOptions& options) { + BinaryReader reader(data, size, delegate, options); + return reader.ReadModule(); +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.h new file mode 100644 index 0000000..19643aa --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.h @@ -0,0 +1,466 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_READER_H_ +#define WABT_BINARY_READER_H_ + +#include +#include + +#include "src/binary.h" +#include "src/common.h" +#include "src/error.h" +#include "src/feature.h" +#include "src/opcode.h" +#include "src/string-view.h" + +namespace wabt { + +class Stream; + +struct ReadBinaryOptions { + ReadBinaryOptions() = default; + ReadBinaryOptions(const Features& features, + Stream* log_stream, + bool read_debug_names, + bool stop_on_first_error, + bool fail_on_custom_section_error) + : features(features), + log_stream(log_stream), + read_debug_names(read_debug_names), + stop_on_first_error(stop_on_first_error), + fail_on_custom_section_error(fail_on_custom_section_error) {} + + Features features; + Stream* log_stream = nullptr; + bool read_debug_names = false; + bool stop_on_first_error = true; + bool fail_on_custom_section_error = true; +}; + +// TODO: Move somewhere else? +struct TypeMut { + Type type; + bool mutable_; +}; +using TypeMutVector = std::vector; + +class BinaryReaderDelegate { + public: + struct State { + State(const uint8_t* data, Offset size) + : data(data), size(size), offset(0) {} + + const uint8_t* data; + Offset size; + Offset offset; + }; + + virtual ~BinaryReaderDelegate() {} + + virtual bool OnError(const Error&) = 0; + virtual void OnSetState(const State* s) { state = s; } + + /* Module */ + virtual Result BeginModule(uint32_t version) = 0; + virtual Result EndModule() = 0; + + virtual Result BeginSection(Index section_index, + BinarySection section_type, + Offset size) = 0; + + /* Custom section */ + virtual Result BeginCustomSection(Index section_index, + Offset size, + string_view section_name) = 0; + virtual Result EndCustomSection() = 0; + + /* Type section */ + virtual Result BeginTypeSection(Offset size) = 0; + virtual Result OnTypeCount(Index count) = 0; + virtual Result OnFuncType(Index index, + Index param_count, + Type* param_types, + Index result_count, + Type* result_types) = 0; + virtual Result OnStructType(Index index, + Index field_count, + TypeMut* fields) = 0; + virtual Result OnArrayType(Index index, TypeMut field) = 0; + virtual Result EndTypeSection() = 0; + + /* Import section */ + virtual Result BeginImportSection(Offset size) = 0; + virtual Result OnImportCount(Index count) = 0; + virtual Result OnImport(Index index, + ExternalKind kind, + string_view module_name, + string_view field_name) = 0; + virtual Result OnImportFunc(Index import_index, + string_view module_name, + string_view field_name, + Index func_index, + Index sig_index) = 0; + virtual Result OnImportTable(Index import_index, + string_view module_name, + string_view field_name, + Index table_index, + Type elem_type, + const Limits* elem_limits) = 0; + virtual Result OnImportMemory(Index import_index, + string_view module_name, + string_view field_name, + Index memory_index, + const Limits* page_limits) = 0; + virtual Result OnImportGlobal(Index import_index, + string_view module_name, + string_view field_name, + Index global_index, + Type type, + bool mutable_) = 0; + virtual Result OnImportEvent(Index import_index, + string_view module_name, + string_view field_name, + Index event_index, + Index sig_index) = 0; + virtual Result EndImportSection() = 0; + + /* Function section */ + virtual Result BeginFunctionSection(Offset size) = 0; + virtual Result OnFunctionCount(Index count) = 0; + virtual Result OnFunction(Index index, Index sig_index) = 0; + virtual Result EndFunctionSection() = 0; + + /* Table section */ + virtual Result BeginTableSection(Offset size) = 0; + virtual Result OnTableCount(Index count) = 0; + virtual Result OnTable(Index index, + Type elem_type, + const Limits* elem_limits) = 0; + virtual Result EndTableSection() = 0; + + /* Memory section */ + virtual Result BeginMemorySection(Offset size) = 0; + virtual Result OnMemoryCount(Index count) = 0; + virtual Result OnMemory(Index index, const Limits* limits) = 0; + virtual Result EndMemorySection() = 0; + + /* Global section */ + virtual Result BeginGlobalSection(Offset size) = 0; + virtual Result OnGlobalCount(Index count) = 0; + virtual Result BeginGlobal(Index index, Type type, bool mutable_) = 0; + virtual Result BeginGlobalInitExpr(Index index) = 0; + virtual Result EndGlobalInitExpr(Index index) = 0; + virtual Result EndGlobal(Index index) = 0; + virtual Result EndGlobalSection() = 0; + + /* Exports section */ + virtual Result BeginExportSection(Offset size) = 0; + virtual Result OnExportCount(Index count) = 0; + virtual Result OnExport(Index index, + ExternalKind kind, + Index item_index, + string_view name) = 0; + virtual Result EndExportSection() = 0; + + /* Start section */ + virtual Result BeginStartSection(Offset size) = 0; + virtual Result OnStartFunction(Index func_index) = 0; + virtual Result EndStartSection() = 0; + + /* Code section */ + virtual Result BeginCodeSection(Offset size) = 0; + virtual Result OnFunctionBodyCount(Index count) = 0; + virtual Result BeginFunctionBody(Index index, Offset size) = 0; + virtual Result OnLocalDeclCount(Index count) = 0; + virtual Result OnLocalDecl(Index decl_index, Index count, Type type) = 0; + + /* Function expressions; called between BeginFunctionBody and + EndFunctionBody */ + virtual Result OnOpcode(Opcode Opcode) = 0; + virtual Result OnOpcodeBare() = 0; + virtual Result OnOpcodeUint32(uint32_t value) = 0; + virtual Result OnOpcodeIndex(Index value) = 0; + virtual Result OnOpcodeIndexIndex(Index value, Index value2) = 0; + virtual Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) = 0; + virtual Result OnOpcodeUint64(uint64_t value) = 0; + virtual Result OnOpcodeF32(uint32_t value) = 0; + virtual Result OnOpcodeF64(uint64_t value) = 0; + virtual Result OnOpcodeV128(v128 value) = 0; + virtual Result OnOpcodeBlockSig(Type sig_type) = 0; + virtual Result OnOpcodeType(Type type) = 0; + virtual Result OnAtomicLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnAtomicStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnAtomicRmwExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnAtomicRmwCmpxchgExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnAtomicWaitExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnAtomicFenceExpr(uint32_t consistency_model) = 0; + virtual Result OnAtomicNotifyExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnBinaryExpr(Opcode opcode) = 0; + virtual Result OnBlockExpr(Type sig_type) = 0; + virtual Result OnBrExpr(Index depth) = 0; + virtual Result OnBrIfExpr(Index depth) = 0; + virtual Result OnBrTableExpr(Index num_targets, + Index* target_depths, + Index default_target_depth) = 0; + virtual Result OnCallExpr(Index func_index) = 0; + virtual Result OnCallIndirectExpr(Index sig_index, Index table_index) = 0; + virtual Result OnCatchExpr(Index event_index) = 0; + virtual Result OnCatchAllExpr() = 0; + virtual Result OnCompareExpr(Opcode opcode) = 0; + virtual Result OnConvertExpr(Opcode opcode) = 0; + virtual Result OnDelegateExpr(Index depth) = 0; + virtual Result OnDropExpr() = 0; + virtual Result OnElseExpr() = 0; + virtual Result OnEndExpr() = 0; + virtual Result OnEndFunc() = 0; + virtual Result OnF32ConstExpr(uint32_t value_bits) = 0; + virtual Result OnF64ConstExpr(uint64_t value_bits) = 0; + virtual Result OnV128ConstExpr(v128 value_bits) = 0; + virtual Result OnGlobalGetExpr(Index global_index) = 0; + virtual Result OnGlobalSetExpr(Index global_index) = 0; + virtual Result OnI32ConstExpr(uint32_t value) = 0; + virtual Result OnI64ConstExpr(uint64_t value) = 0; + virtual Result OnIfExpr(Type sig_type) = 0; + virtual Result OnLoadExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnLocalGetExpr(Index local_index) = 0; + virtual Result OnLocalSetExpr(Index local_index) = 0; + virtual Result OnLocalTeeExpr(Index local_index) = 0; + virtual Result OnLoopExpr(Type sig_type) = 0; + virtual Result OnMemoryCopyExpr() = 0; + virtual Result OnDataDropExpr(Index segment_index) = 0; + virtual Result OnMemoryFillExpr() = 0; + virtual Result OnMemoryGrowExpr() = 0; + virtual Result OnMemoryInitExpr(Index segment_index) = 0; + virtual Result OnMemorySizeExpr() = 0; + virtual Result OnTableCopyExpr(Index dst_index, Index src_index) = 0; + virtual Result OnElemDropExpr(Index segment_index) = 0; + virtual Result OnTableInitExpr(Index segment_index, Index table_index) = 0; + virtual Result OnTableGetExpr(Index table_index) = 0; + virtual Result OnTableSetExpr(Index table_index) = 0; + virtual Result OnTableGrowExpr(Index table_index) = 0; + virtual Result OnTableSizeExpr(Index table_index) = 0; + virtual Result OnTableFillExpr(Index table_index) = 0; + virtual Result OnRefFuncExpr(Index func_index) = 0; + virtual Result OnRefNullExpr(Type type) = 0; + virtual Result OnRefIsNullExpr() = 0; + virtual Result OnNopExpr() = 0; + virtual Result OnRethrowExpr(Index depth) = 0; + virtual Result OnReturnExpr() = 0; + virtual Result OnReturnCallExpr(Index func_index) = 0; + virtual Result OnReturnCallIndirectExpr(Index sig_index, + Index table_index) = 0; + virtual Result OnSelectExpr(Index result_count, Type* result_types) = 0; + virtual Result OnStoreExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + virtual Result OnThrowExpr(Index event_index) = 0; + virtual Result OnTryExpr(Type sig_type) = 0; + + virtual Result OnUnaryExpr(Opcode opcode) = 0; + virtual Result OnTernaryExpr(Opcode opcode) = 0; + virtual Result OnUnreachableExpr() = 0; + virtual Result OnUnwindExpr() = 0; + virtual Result EndFunctionBody(Index index) = 0; + virtual Result EndCodeSection() = 0; + + /* Simd instructions with Lane Imm operand*/ + virtual Result OnSimdLaneOpExpr(Opcode opcode, uint64_t value) = 0; + virtual Result OnSimdShuffleOpExpr(Opcode opcode, v128 value) = 0; + + virtual Result OnLoadSplatExpr(Opcode opcode, + Address alignment_log2, + Address offset) = 0; + + /* Elem section */ + virtual Result BeginElemSection(Offset size) = 0; + virtual Result OnElemSegmentCount(Index count) = 0; + virtual Result BeginElemSegment(Index index, + Index table_index, + uint8_t flags) = 0; + virtual Result BeginElemSegmentInitExpr(Index index) = 0; + virtual Result EndElemSegmentInitExpr(Index index) = 0; + virtual Result OnElemSegmentElemType(Index index, Type elem_type) = 0; + virtual Result OnElemSegmentElemExprCount(Index index, Index count) = 0; + virtual Result OnElemSegmentElemExpr_RefNull(Index segment_index, + Type type) = 0; + virtual Result OnElemSegmentElemExpr_RefFunc(Index segment_index, + Index func_index) = 0; + virtual Result EndElemSegment(Index index) = 0; + virtual Result EndElemSection() = 0; + + /* Data section */ + virtual Result BeginDataSection(Offset size) = 0; + virtual Result OnDataSegmentCount(Index count) = 0; + virtual Result BeginDataSegment(Index index, + Index memory_index, + uint8_t flags) = 0; + virtual Result BeginDataSegmentInitExpr(Index index) = 0; + virtual Result EndDataSegmentInitExpr(Index index) = 0; + virtual Result OnDataSegmentData(Index index, + const void* data, + Address size) = 0; + virtual Result EndDataSegment(Index index) = 0; + virtual Result EndDataSection() = 0; + + /* DataCount section */ + virtual Result BeginDataCountSection(Offset size) = 0; + virtual Result OnDataCount(Index count) = 0; + virtual Result EndDataCountSection() = 0; + + /* Names section */ + virtual Result BeginNamesSection(Offset size) = 0; + virtual Result OnModuleNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) = 0; + virtual Result OnModuleName(string_view name) = 0; + virtual Result OnFunctionNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) = 0; + virtual Result OnFunctionNamesCount(Index num_functions) = 0; + virtual Result OnFunctionName(Index function_index, + string_view function_name) = 0; + virtual Result OnLocalNameSubsection(Index index, + uint32_t name_type, + Offset subsection_size) = 0; + virtual Result OnLocalNameFunctionCount(Index num_functions) = 0; + virtual Result OnLocalNameLocalCount(Index function_index, + Index num_locals) = 0; + virtual Result OnLocalName(Index function_index, + Index local_index, + string_view local_name) = 0; + virtual Result OnNameSubsection(Index index, + NameSectionSubsection subsection_type, + Offset subsection_size) = 0; + virtual Result OnNameCount(Index num_names) = 0; + virtual Result OnNameEntry(NameSectionSubsection type, + Index index, + string_view name) = 0; + virtual Result EndNamesSection() = 0; + + /* Reloc section */ + virtual Result BeginRelocSection(Offset size) = 0; + virtual Result OnRelocCount(Index count, + Index section_index) = 0; + virtual Result OnReloc(RelocType type, + Offset offset, + Index index, + uint32_t addend) = 0; + virtual Result EndRelocSection() = 0; + + /* Dylink section */ + virtual Result BeginDylinkSection(Offset size) = 0; + virtual Result OnDylinkInfo(uint32_t mem_size, + uint32_t mem_align_log2, + uint32_t table_size, + uint32_t table_align_log2) = 0; + virtual Result OnDylinkNeededCount(Index count) = 0; + virtual Result OnDylinkNeeded(string_view so_name) = 0; + virtual Result EndDylinkSection() = 0; + + /* Linking section */ + virtual Result BeginLinkingSection(Offset size) = 0; + virtual Result OnSymbolCount(Index count) = 0; + virtual Result OnSymbol(Index index, SymbolType type, uint32_t flags) = 0; + virtual Result OnDataSymbol(Index index, + uint32_t flags, + string_view name, + Index segment, + uint32_t offset, + uint32_t size) = 0; + virtual Result OnFunctionSymbol(Index index, + uint32_t flags, + string_view name, + Index function_index) = 0; + virtual Result OnGlobalSymbol(Index index, + uint32_t flags, + string_view name, + Index global_index) = 0; + virtual Result OnSectionSymbol(Index index, + uint32_t flags, + Index section_index) = 0; + virtual Result OnEventSymbol(Index index, + uint32_t flags, + string_view name, + Index event_index) = 0; + virtual Result OnTableSymbol(Index index, + uint32_t flags, + string_view name, + Index table_index) = 0; + virtual Result OnSegmentInfoCount(Index count) = 0; + virtual Result OnSegmentInfo(Index index, + string_view name, + Address alignment_log2, + uint32_t flags) = 0; + virtual Result OnInitFunctionCount(Index count) = 0; + virtual Result OnInitFunction(uint32_t priority, Index function_index) = 0; + virtual Result OnComdatCount(Index count) = 0; + virtual Result OnComdatBegin(string_view name, + uint32_t flags, + Index count) = 0; + virtual Result OnComdatEntry(ComdatType kind, Index index) = 0; + virtual Result EndLinkingSection() = 0; + + /* Event section */ + virtual Result BeginEventSection(Offset size) = 0; + virtual Result OnEventCount(Index count) = 0; + virtual Result OnEventType(Index index, Index sig_index) = 0; + virtual Result EndEventSection() = 0; + + /* InitExpr - used by elem, data and global sections; these functions are + * only called between calls to Begin*InitExpr and End*InitExpr */ + virtual Result OnInitExprF32ConstExpr(Index index, uint32_t value) = 0; + virtual Result OnInitExprF64ConstExpr(Index index, uint64_t value) = 0; + virtual Result OnInitExprV128ConstExpr(Index index, v128 value) = 0; + virtual Result OnInitExprGlobalGetExpr(Index index, Index global_index) = 0; + virtual Result OnInitExprI32ConstExpr(Index index, uint32_t value) = 0; + virtual Result OnInitExprI64ConstExpr(Index index, uint64_t value) = 0; + virtual Result OnInitExprRefNull(Index index, Type type) = 0; + virtual Result OnInitExprRefFunc(Index index, Index func_index) = 0; + + const State* state = nullptr; +}; + +Result ReadBinary(const void* data, + size_t size, + BinaryReaderDelegate* reader, + const ReadBinaryOptions& options); + +size_t ReadU32Leb128(const uint8_t* ptr, + const uint8_t* end, + uint32_t* out_value); + +size_t ReadI32Leb128(const uint8_t* ptr, + const uint8_t* end, + uint32_t* out_value); + +} // namespace wabt + +#endif /* WABT_BINARY_READER_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.cc new file mode 100644 index 0000000..13e7112 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.cc @@ -0,0 +1,630 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary-writer-spec.h" + +#include +#include + +#include "config.h" + +#include "src/binary-writer.h" +#include "src/binary.h" +#include "src/cast.h" +#include "src/filenames.h" +#include "src/ir.h" +#include "src/literal.h" +#include "src/stream.h" +#include "src/string-view.h" + +namespace wabt { + +namespace { + +class BinaryWriterSpec { + public: + BinaryWriterSpec(Stream* json_stream, + WriteBinarySpecStreamFactory module_stream_factory, + string_view source_filename, + string_view module_filename_noext, + const WriteBinaryOptions& options); + + Result WriteScript(const Script& script); + + private: + std::string GetModuleFilename(const char* extension); + void WriteString(const char* s); + void WriteKey(const char* key); + void WriteSeparator(); + void WriteEscapedString(string_view); + void WriteCommandType(const Command& command); + void WriteLocation(const Location& loc); + void WriteVar(const Var& var); + void WriteTypeObject(Type type); + void WriteF32(uint32_t, ExpectedNan); + void WriteF64(uint64_t, ExpectedNan); + void WriteRefBits(uintptr_t ref_bits); + void WriteConst(const Const& const_); + void WriteConstVector(const ConstVector& consts); + void WriteAction(const Action& action); + void WriteActionResultType(const Action& action); + void WriteModule(string_view filename, const Module& module); + void WriteScriptModule(string_view filename, + const ScriptModule& script_module); + void WriteInvalidModule(const ScriptModule& module, string_view text); + void WriteCommands(); + + const Script* script_ = nullptr; + Stream* json_stream_ = nullptr; + WriteBinarySpecStreamFactory module_stream_factory_; + std::string source_filename_; + std::string module_filename_noext_; + const WriteBinaryOptions& options_; + Result result_ = Result::Ok; + size_t num_modules_ = 0; +}; + +BinaryWriterSpec::BinaryWriterSpec( + Stream* json_stream, + WriteBinarySpecStreamFactory module_stream_factory, + string_view source_filename, + string_view module_filename_noext, + const WriteBinaryOptions& options) + : json_stream_(json_stream), + module_stream_factory_(module_stream_factory), + source_filename_(source_filename), + module_filename_noext_(module_filename_noext), + options_(options) {} + +std::string BinaryWriterSpec::GetModuleFilename(const char* extension) { + std::string result = module_filename_noext_; + result += '.'; + result += std::to_string(num_modules_); + result += extension; + ConvertBackslashToSlash(&result); + return result; +} + +void BinaryWriterSpec::WriteString(const char* s) { + json_stream_->Writef("\"%s\"", s); +} + +void BinaryWriterSpec::WriteKey(const char* key) { + json_stream_->Writef("\"%s\": ", key); +} + +void BinaryWriterSpec::WriteSeparator() { + json_stream_->Writef(", "); +} + +void BinaryWriterSpec::WriteEscapedString(string_view s) { + json_stream_->WriteChar('"'); + for (size_t i = 0; i < s.length(); ++i) { + uint8_t c = s[i]; + if (c < 0x20 || c == '\\' || c == '"') { + json_stream_->Writef("\\u%04x", c); + } else { + json_stream_->WriteChar(c); + } + } + json_stream_->WriteChar('"'); +} + +void BinaryWriterSpec::WriteCommandType(const Command& command) { + static const char* s_command_names[] = { + "module", + "action", + "register", + "assert_malformed", + "assert_invalid", + "assert_unlinkable", + "assert_uninstantiable", + "assert_return", + "assert_trap", + "assert_exhaustion", + }; + WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_command_names) == kCommandTypeCount); + + WriteKey("type"); + assert(s_command_names[static_cast(command.type)]); + WriteString(s_command_names[static_cast(command.type)]); +} + +void BinaryWriterSpec::WriteLocation(const Location& loc) { + WriteKey("line"); + json_stream_->Writef("%d", loc.line); +} + +void BinaryWriterSpec::WriteVar(const Var& var) { + if (var.is_index()) { + json_stream_->Writef("\"%" PRIindex "\"", var.index()); + } else { + WriteEscapedString(var.name()); + } +} + +void BinaryWriterSpec::WriteTypeObject(Type type) { + json_stream_->Writef("{"); + WriteKey("type"); + WriteString(type.GetName()); + json_stream_->Writef("}"); +} + +void BinaryWriterSpec::WriteF32(uint32_t f32_bits, ExpectedNan expected) { + switch (expected) { + case ExpectedNan::None: + json_stream_->Writef("\"%u\"", f32_bits); + break; + + case ExpectedNan::Arithmetic: + WriteString("nan:arithmetic"); + break; + + case ExpectedNan::Canonical: + WriteString("nan:canonical"); + break; + } +} + +void BinaryWriterSpec::WriteF64(uint64_t f64_bits, ExpectedNan expected) { + switch (expected) { + case ExpectedNan::None: + json_stream_->Writef("\"%" PRIu64 "\"", f64_bits); + break; + + case ExpectedNan::Arithmetic: + WriteString("nan:arithmetic"); + break; + + case ExpectedNan::Canonical: + WriteString("nan:canonical"); + break; + } +} + +void BinaryWriterSpec::WriteRefBits(uintptr_t ref_bits) { + if (ref_bits == Const::kRefNullBits) { + json_stream_->Writef("\"null\""); + } else { + json_stream_->Writef("\"%" PRIuPTR "\"", ref_bits); + } +} + +void BinaryWriterSpec::WriteConst(const Const& const_) { + json_stream_->Writef("{"); + WriteKey("type"); + + /* Always write the values as strings, even though they may be representable + * as JSON numbers. This way the formatting is consistent. */ + switch (const_.type()) { + case Type::I32: + WriteString("i32"); + WriteSeparator(); + WriteKey("value"); + json_stream_->Writef("\"%u\"", const_.u32()); + break; + + case Type::I64: + WriteString("i64"); + WriteSeparator(); + WriteKey("value"); + json_stream_->Writef("\"%" PRIu64 "\"", const_.u64()); + break; + + case Type::F32: + WriteString("f32"); + WriteSeparator(); + WriteKey("value"); + WriteF32(const_.f32_bits(), const_.expected_nan()); + break; + + case Type::F64: + WriteString("f64"); + WriteSeparator(); + WriteKey("value"); + WriteF64(const_.f64_bits(), const_.expected_nan()); + break; + + case Type::FuncRef: { + WriteString("funcref"); + WriteSeparator(); + WriteKey("value"); + WriteRefBits(const_.ref_bits()); + break; + } + + case Type::ExternRef: { + WriteString("externref"); + WriteSeparator(); + WriteKey("value"); + WriteRefBits(const_.ref_bits()); + break; + } + + case Type::V128: { + WriteString("v128"); + WriteSeparator(); + WriteKey("lane_type"); + WriteString(const_.lane_type().GetName()); + WriteSeparator(); + WriteKey("value"); + json_stream_->Writef("["); + + for (int lane = 0; lane < const_.lane_count(); ++lane) { + switch (const_.lane_type()) { + case Type::I8: + json_stream_->Writef("\"%u\"", const_.v128_lane(lane)); + break; + + case Type::I16: + json_stream_->Writef("\"%u\"", const_.v128_lane(lane)); + break; + + case Type::I32: + json_stream_->Writef("\"%u\"", const_.v128_lane(lane)); + break; + + case Type::I64: + json_stream_->Writef("\"%" PRIu64 "\"", + const_.v128_lane(lane)); + break; + + case Type::F32: + WriteF32(const_.v128_lane(lane), + const_.expected_nan(lane)); + break; + + case Type::F64: + WriteF64(const_.v128_lane(lane), + const_.expected_nan(lane)); + break; + + default: + WABT_UNREACHABLE; + } + + if (lane != const_.lane_count() - 1) { + WriteSeparator(); + } + } + + json_stream_->Writef("]"); + + break; + } + + default: + WABT_UNREACHABLE; + } + + json_stream_->Writef("}"); +} + +void BinaryWriterSpec::WriteConstVector(const ConstVector& consts) { + json_stream_->Writef("["); + for (size_t i = 0; i < consts.size(); ++i) { + const Const& const_ = consts[i]; + WriteConst(const_); + if (i != consts.size() - 1) { + WriteSeparator(); + } + } + json_stream_->Writef("]"); +} + +void BinaryWriterSpec::WriteAction(const Action& action) { + WriteKey("action"); + json_stream_->Writef("{"); + WriteKey("type"); + if (action.type() == ActionType::Invoke) { + WriteString("invoke"); + } else { + assert(action.type() == ActionType::Get); + WriteString("get"); + } + WriteSeparator(); + if (action.module_var.is_name()) { + WriteKey("module"); + WriteVar(action.module_var); + WriteSeparator(); + } + if (action.type() == ActionType::Invoke) { + WriteKey("field"); + WriteEscapedString(action.name); + WriteSeparator(); + WriteKey("args"); + WriteConstVector(cast(&action)->args); + } else { + WriteKey("field"); + WriteEscapedString(action.name); + } + json_stream_->Writef("}"); +} + +void BinaryWriterSpec::WriteActionResultType(const Action& action) { + const Module* module = script_->GetModule(action.module_var); + const Export* export_; + json_stream_->Writef("["); + switch (action.type()) { + case ActionType::Invoke: { + export_ = module->GetExport(action.name); + assert(export_->kind == ExternalKind::Func); + const Func* func = module->GetFunc(export_->var); + Index num_results = func->GetNumResults(); + for (Index i = 0; i < num_results; ++i) + WriteTypeObject(func->GetResultType(i)); + break; + } + + case ActionType::Get: { + export_ = module->GetExport(action.name); + assert(export_->kind == ExternalKind::Global); + const Global* global = module->GetGlobal(export_->var); + WriteTypeObject(global->type); + break; + } + } + json_stream_->Writef("]"); +} + +void BinaryWriterSpec::WriteModule(string_view filename, const Module& module) { + result_ |= + WriteBinaryModule(module_stream_factory_(filename), &module, options_); +} + +void BinaryWriterSpec::WriteScriptModule(string_view filename, + const ScriptModule& script_module) { + switch (script_module.type()) { + case ScriptModuleType::Text: + WriteModule(filename, cast(&script_module)->module); + break; + + case ScriptModuleType::Binary: + module_stream_factory_(filename)->WriteData( + cast(&script_module)->data, ""); + break; + + case ScriptModuleType::Quoted: + module_stream_factory_(filename)->WriteData( + cast(&script_module)->data, ""); + break; + } +} + +void BinaryWriterSpec::WriteInvalidModule(const ScriptModule& module, + string_view text) { + const char* extension = ""; + const char* module_type = ""; + switch (module.type()) { + case ScriptModuleType::Text: + extension = kWasmExtension; + module_type = "binary"; + break; + + case ScriptModuleType::Binary: + extension = kWasmExtension; + module_type = "binary"; + break; + + case ScriptModuleType::Quoted: + extension = kWatExtension; + module_type = "text"; + break; + } + + WriteLocation(module.location()); + WriteSeparator(); + std::string filename = GetModuleFilename(extension); + WriteKey("filename"); + WriteEscapedString(GetBasename(filename)); + WriteSeparator(); + WriteKey("text"); + WriteEscapedString(text); + WriteSeparator(); + WriteKey("module_type"); + WriteString(module_type); + WriteScriptModule(filename, module); +} + +void BinaryWriterSpec::WriteCommands() { + json_stream_->Writef("{\"source_filename\": "); + WriteEscapedString(source_filename_); + json_stream_->Writef(",\n \"commands\": [\n"); + Index last_module_index = kInvalidIndex; + for (size_t i = 0; i < script_->commands.size(); ++i) { + const Command* command = script_->commands[i].get(); + + if (i != 0) { + WriteSeparator(); + json_stream_->Writef("\n"); + } + + json_stream_->Writef(" {"); + WriteCommandType(*command); + WriteSeparator(); + + switch (command->type) { + case CommandType::Module: { + const Module& module = cast(command)->module; + std::string filename = GetModuleFilename(kWasmExtension); + WriteLocation(module.loc); + WriteSeparator(); + if (!module.name.empty()) { + WriteKey("name"); + WriteEscapedString(module.name); + WriteSeparator(); + } + WriteKey("filename"); + WriteEscapedString(GetBasename(filename)); + WriteModule(filename, module); + num_modules_++; + last_module_index = i; + break; + } + + case CommandType::Action: { + const Action& action = *cast(command)->action; + WriteLocation(action.loc); + WriteSeparator(); + WriteAction(action); + WriteSeparator(); + WriteKey("expected"); + WriteActionResultType(action); + break; + } + + case CommandType::Register: { + auto* register_command = cast(command); + const Var& var = register_command->var; + WriteLocation(var.loc); + WriteSeparator(); + if (var.is_name()) { + WriteKey("name"); + WriteVar(var); + WriteSeparator(); + } else { + /* If we're not registering by name, then we should only be + * registering the last module. */ + WABT_USE(last_module_index); + assert(var.index() == last_module_index); + } + WriteKey("as"); + WriteEscapedString(register_command->module_name); + break; + } + + case CommandType::AssertMalformed: { + auto* assert_malformed_command = cast(command); + WriteInvalidModule(*assert_malformed_command->module, + assert_malformed_command->text); + num_modules_++; + break; + } + + case CommandType::AssertInvalid: { + auto* assert_invalid_command = cast(command); + WriteInvalidModule(*assert_invalid_command->module, + assert_invalid_command->text); + num_modules_++; + break; + } + + case CommandType::AssertUnlinkable: { + auto* assert_unlinkable_command = + cast(command); + WriteInvalidModule(*assert_unlinkable_command->module, + assert_unlinkable_command->text); + num_modules_++; + break; + } + + case CommandType::AssertUninstantiable: { + auto* assert_uninstantiable_command = + cast(command); + WriteInvalidModule(*assert_uninstantiable_command->module, + assert_uninstantiable_command->text); + num_modules_++; + break; + } + + case CommandType::AssertReturn: { + auto* assert_return_command = cast(command); + WriteLocation(assert_return_command->action->loc); + WriteSeparator(); + WriteAction(*assert_return_command->action); + WriteSeparator(); + WriteKey("expected"); + WriteConstVector(assert_return_command->expected); + break; + } + + case CommandType::AssertTrap: { + auto* assert_trap_command = cast(command); + WriteLocation(assert_trap_command->action->loc); + WriteSeparator(); + WriteAction(*assert_trap_command->action); + WriteSeparator(); + WriteKey("text"); + WriteEscapedString(assert_trap_command->text); + WriteSeparator(); + WriteKey("expected"); + WriteActionResultType(*assert_trap_command->action); + break; + } + + case CommandType::AssertExhaustion: { + auto* assert_exhaustion_command = + cast(command); + WriteLocation(assert_exhaustion_command->action->loc); + WriteSeparator(); + WriteAction(*assert_exhaustion_command->action); + WriteSeparator(); + WriteKey("text"); + WriteEscapedString(assert_exhaustion_command->text); + WriteSeparator(); + WriteKey("expected"); + WriteActionResultType(*assert_exhaustion_command->action); + break; + } + } + + json_stream_->Writef("}"); + } + json_stream_->Writef("]}\n"); +} + +Result BinaryWriterSpec::WriteScript(const Script& script) { + script_ = &script; + WriteCommands(); + return result_; +} + +} // end anonymous namespace + +Result WriteBinarySpecScript(Stream* json_stream, + WriteBinarySpecStreamFactory module_stream_factory, + Script* script, + string_view source_filename, + string_view module_filename_noext, + const WriteBinaryOptions& options) { + BinaryWriterSpec binary_writer_spec(json_stream, module_stream_factory, + source_filename, module_filename_noext, + options); + return binary_writer_spec.WriteScript(*script); +} + +Result WriteBinarySpecScript( + Stream* json_stream, + Script* script, + string_view source_filename, + string_view module_filename_noext, + const WriteBinaryOptions& options, + std::vector* out_module_streams, + Stream* log_stream) { + WriteBinarySpecStreamFactory module_stream_factory = + [&](string_view filename) { + out_module_streams->emplace_back(filename, + MakeUnique(log_stream)); + return out_module_streams->back().stream.get(); + }; + + BinaryWriterSpec binary_writer_spec(json_stream, module_stream_factory, + source_filename, module_filename_noext, + options); + return binary_writer_spec.WriteScript(*script); +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.h new file mode 100644 index 0000000..197d6f2 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.h @@ -0,0 +1,60 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_WRITER_SPEC_H_ +#define WABT_BINARY_WRITER_SPEC_H_ + +#include +#include +#include + +#include "src/binary-writer.h" +#include "src/common.h" +#include "src/ir.h" + +namespace wabt { + +struct FilenameMemoryStreamPair { + FilenameMemoryStreamPair(string_view filename, + std::unique_ptr stream) + : filename(filename), stream(std::move(stream)) {} + std::string filename; + std::unique_ptr stream; +}; + +typedef std::function + WriteBinarySpecStreamFactory; + +Result WriteBinarySpecScript(Stream* json_stream, + WriteBinarySpecStreamFactory module_stream_factory, + Script*, + string_view source_filename, + string_view module_filename_noext, + const WriteBinaryOptions&); + +// Convenience function for producing MemoryStream outputs all modules. +Result WriteBinarySpecScript( + Stream* json_stream, + Script*, + string_view source_filename, + string_view module_filename_noext, + const WriteBinaryOptions&, + std::vector* out_module_streams, + Stream* log_stream = nullptr); + +} // namespace wabt + +#endif /* WABT_BINARY_WRITER_SPEC_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.cc new file mode 100644 index 0000000..c744aca --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.cc @@ -0,0 +1,1645 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary-writer.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "src/binary.h" +#include "src/cast.h" +#include "src/ir.h" +#include "src/leb128.h" +#include "src/stream.h" +#include "src/string-view.h" + +#define PRINT_HEADER_NO_INDEX -1 +#define MAX_U32_LEB128_BYTES 5 + +namespace wabt { + +void WriteStr(Stream* stream, + string_view s, + const char* desc, + PrintChars print_chars) { + WriteU32Leb128(stream, s.length(), "string length"); + stream->WriteData(s.data(), s.length(), desc, print_chars); +} + +void WriteOpcode(Stream* stream, Opcode opcode) { + if (opcode.HasPrefix()) { + stream->WriteU8(opcode.GetPrefix(), "prefix"); + WriteU32Leb128(stream, opcode.GetCode(), opcode.GetName()); + } else { + stream->WriteU8(opcode.GetCode(), opcode.GetName()); + } +} + +void WriteType(Stream* stream, Type type, const char* desc) { + WriteS32Leb128(stream, type, desc ? desc : type.GetName()); +} + +void WriteLimits(Stream* stream, const Limits* limits) { + uint32_t flags = limits->has_max ? WABT_BINARY_LIMITS_HAS_MAX_FLAG : 0; + flags |= limits->is_shared ? WABT_BINARY_LIMITS_IS_SHARED_FLAG : 0; + flags |= limits->is_64 ? WABT_BINARY_LIMITS_IS_64_FLAG : 0; + WriteU32Leb128(stream, flags, "limits: flags"); + WriteU32Leb128(stream, limits->initial, "limits: initial"); + if (limits->has_max) { + WriteU32Leb128(stream, limits->max, "limits: max"); + } +} + +void WriteDebugName(Stream* stream, string_view name, const char* desc) { + string_view stripped_name = name; + if (!stripped_name.empty()) { + // Strip leading $ from name + assert(stripped_name.front() == '$'); + stripped_name.remove_prefix(1); + } + WriteStr(stream, stripped_name, desc, PrintChars::Yes); +} + +namespace { + +/* TODO(binji): better leb size guess. Some sections we know will only be 1 + byte, but others we can be fairly certain will be larger. */ +static const size_t LEB_SECTION_SIZE_GUESS = 1; + +#define ALLOC_FAILURE \ + fprintf(stderr, "%s:%d: allocation failed\n", __FILE__, __LINE__) + +struct RelocSection { + RelocSection(const char* name, Index index) + : name(name), section_index(index) {} + + const char* name; + Index section_index; + std::vector relocations; +}; + +class Symbol { + public: + struct Function { + static const SymbolType type = SymbolType::Function; + Index index; + }; + struct Data { + static const SymbolType type = SymbolType::Data; + Index index; + Offset offset; + Address size; + }; + struct Global { + static const SymbolType type = SymbolType::Global; + Index index; + }; + struct Section { + static const SymbolType type = SymbolType::Section; + Index section; + }; + struct Event { + static const SymbolType type = SymbolType::Event; + Index index; + }; + struct Table { + static const SymbolType type = SymbolType::Table; + Index index; + }; + + private: + SymbolType type_; + string_view name_; + uint8_t flags_; + union { + Function function_; + Data data_; + Global global_; + Section section_; + Event event_; + Table table_; + }; + + public: + Symbol(const string_view& name, uint8_t flags, const Function& f) + : type_(Function::type), name_(name), flags_(flags), function_(f) {} + Symbol(const string_view& name, uint8_t flags, const Data& d) + : type_(Data::type), name_(name), flags_(flags), data_(d) {} + Symbol(const string_view& name, uint8_t flags, const Global& g) + : type_(Global::type), name_(name), flags_(flags), global_(g) {} + Symbol(const string_view& name, uint8_t flags, const Section& s) + : type_(Section::type), name_(name), flags_(flags), section_(s) {} + Symbol(const string_view& name, uint8_t flags, const Event& e) + : type_(Event::type), name_(name), flags_(flags), event_(e) {} + Symbol(const string_view& name, uint8_t flags, const Table& t) + : type_(Table::type), name_(name), flags_(flags), table_(t) {} + + SymbolType type() const { return type_; } + const string_view& name() const { return name_; } + uint8_t flags() const { return flags_; } + + SymbolVisibility visibility() const { + return static_cast(flags() & WABT_SYMBOL_MASK_VISIBILITY); + } + SymbolBinding binding() const { + return static_cast(flags() & WABT_SYMBOL_MASK_BINDING); + } + bool undefined() const { return flags() & WABT_SYMBOL_FLAG_UNDEFINED; } + bool defined() const { return !undefined(); } + bool exported() const { return flags() & WABT_SYMBOL_FLAG_EXPORTED; } + bool explicit_name() const { return flags() & WABT_SYMBOL_FLAG_EXPLICIT_NAME; } + bool no_strip() const { return flags() & WABT_SYMBOL_FLAG_NO_STRIP; } + + bool IsFunction() const { return type() == Function::type; } + bool IsData() const { return type() == Data::type; } + bool IsGlobal() const { return type() == Global::type; } + bool IsSection() const { return type() == Section::type; } + bool IsEvent() const { return type() == Event::type; } + bool IsTable() const { return type() == Table::type; } + + const Function& AsFunction() const { + assert(IsFunction()); + return function_; + } + const Data& AsData() const { + assert(IsData()); + return data_; + } + const Global& AsGlobal() const { + assert(IsGlobal()); + return global_; + } + const Section& AsSection() const { + assert(IsSection()); + return section_; + } + const Event& AsEvent() const { + assert(IsEvent()); + return event_; + } + const Table& AsTable() const { + assert(IsTable()); + return table_; + } +}; + +class SymbolTable { + WABT_DISALLOW_COPY_AND_ASSIGN(SymbolTable); + + std::vector symbols_; + + std::vector functions_; + std::vector tables_; + std::vector globals_; + + std::set seen_names_; + + Result EnsureUnique(const string_view& name) { + if (seen_names_.count(name)) { + fprintf(stderr, "error: duplicate symbol when writing relocatable " + "binary: %s\n", &name[0]); + return Result::Error; + } + seen_names_.insert(name); + return Result::Ok; + }; + + template + Result AddSymbol(std::vector* map, string_view name, + bool imported, bool exported, T&& sym) { + uint8_t flags = 0; + if (imported) { + flags |= WABT_SYMBOL_FLAG_UNDEFINED; + // Wabt currently has no way for a user to explicitly specify the name of + // an import, so never set the EXPLICIT_NAME flag, and ignore any display + // name fabricated by wabt. + name = string_view(); + } else { + if (name.empty()) { + // Definitions without a name are local. + flags |= uint8_t(SymbolBinding::Local); + flags |= uint8_t(SymbolVisibility::Hidden); + } else { + // Otherwise, strip the dollar off the name; a definition $foo is + // available for linking as "foo". + assert(name[0] == '$'); + name.remove_prefix(1); + } + + if (exported) { + CHECK_RESULT(EnsureUnique(name)); + flags |= uint8_t(SymbolVisibility::Hidden); + flags |= WABT_SYMBOL_FLAG_NO_STRIP; + } + } + if (exported) { + flags |= WABT_SYMBOL_FLAG_EXPORTED; + } + + map->push_back(symbols_.size()); + symbols_.emplace_back(name, flags, sym); + return Result::Ok; + }; + + Index SymbolIndex(const std::vector& table, Index index) const { + // For well-formed modules, an index into (e.g.) functions_ will always be + // within bounds; the out-of-bounds case here is just to allow --relocatable + // to write known-invalid modules. + return index < table.size() ? table[index] : kInvalidIndex; + } + + public: + SymbolTable() {} + + Result Populate(const Module* module) { + std::set exported_funcs; + std::set exported_globals; + std::set exported_events; + std::set exported_tables; + + for (const Export* export_ : module->exports) { + switch (export_->kind) { + case ExternalKind::Func: + exported_funcs.insert(module->GetFuncIndex(export_->var)); + break; + case ExternalKind::Table: + exported_tables.insert(module->GetTableIndex(export_->var)); + break; + case ExternalKind::Memory: + break; + case ExternalKind::Global: + exported_globals.insert(module->GetGlobalIndex(export_->var)); + break; + case ExternalKind::Event: + exported_events.insert(module->GetEventIndex(export_->var)); + break; + } + } + + // We currently only create symbol table entries for function, table, and + // global symbols. + for (size_t i = 0; i < module->funcs.size(); ++i) { + const Func* func = module->funcs[i]; + bool imported = i < module->num_func_imports; + bool exported = exported_funcs.count(i); + CHECK_RESULT(AddSymbol(&functions_, func->name, imported, exported, + Symbol::Function{Index(i)})); + } + + for (size_t i = 0; i < module->tables.size(); ++i) { + const Table* table = module->tables[i]; + bool imported = i < module->num_table_imports; + bool exported = exported_tables.count(i); + CHECK_RESULT(AddSymbol(&tables_, table->name, imported, exported, + Symbol::Table{Index(i)})); + } + + for (size_t i = 0; i < module->globals.size(); ++i) { + const Global* global = module->globals[i]; + bool imported = i < module->num_global_imports; + bool exported = exported_globals.count(i); + CHECK_RESULT(AddSymbol(&globals_, global->name, imported, exported, + Symbol::Global{Index(i)})); + } + + return Result::Ok; + } + + const std::vector& symbols() const { return symbols_; } + Index FunctionSymbolIndex(Index index) const { + return SymbolIndex(functions_, index); + } + Index TableSymbolIndex(Index index) const { + return SymbolIndex(tables_, index); + } + Index GlobalSymbolIndex(Index index) const { + return SymbolIndex(globals_, index); + } +}; + +class BinaryWriter { + WABT_DISALLOW_COPY_AND_ASSIGN(BinaryWriter); + + public: + BinaryWriter(Stream*, + const WriteBinaryOptions& options, + const Module* module); + + Result WriteModule(); + + private: + void WriteHeader(const char* name, int index); + Offset WriteU32Leb128Space(Offset leb_size_guess, const char* desc); + Offset WriteFixupU32Leb128Size(Offset offset, + Offset leb_size_guess, + const char* desc); + void BeginKnownSection(BinarySection section_code); + void BeginCustomSection(const char* name); + void WriteSectionHeader(const char* desc, BinarySection section_code); + void EndSection(); + void BeginSubsection(const char* name); + void EndSubsection(); + Index GetLabelVarDepth(const Var* var); + Index GetEventVarDepth(const Var* var); + Index GetLocalIndex(const Func* func, const Var& var); + Index GetSymbolIndex(RelocType reloc_type, Index index); + void AddReloc(RelocType reloc_type, Index index); + void WriteBlockDecl(const BlockDeclaration& decl); + void WriteU32Leb128WithReloc(Index index, + const char* desc, + RelocType reloc_type); + void WriteS32Leb128WithReloc(int32_t value, + const char* desc, + RelocType reloc_type); + void WriteTableNumberWithReloc(Index table_number, const char* desc); + template + void WriteLoadStoreExpr(const Func* func, const Expr* expr, const char* desc); + void WriteExpr(const Func* func, const Expr* expr); + void WriteExprList(const Func* func, const ExprList& exprs); + void WriteInitExpr(const ExprList& expr); + void WriteFuncLocals(const Func* func, const LocalTypes& local_types); + void WriteFunc(const Func* func); + void WriteTable(const Table* table); + void WriteMemory(const Memory* memory); + void WriteGlobalHeader(const Global* global); + void WriteEventType(const Event* event); + void WriteRelocSection(const RelocSection* reloc_section); + void WriteLinkingSection(); + template + void WriteNames(const std::vector& elems, NameSectionSubsection type); + + Stream* stream_; + const WriteBinaryOptions& options_; + const Module* module_; + + SymbolTable symtab_; + std::vector reloc_sections_; + RelocSection* current_reloc_section_ = nullptr; + + Index section_count_ = 0; + size_t last_section_offset_ = 0; + size_t last_section_leb_size_guess_ = 0; + BinarySection last_section_type_ = BinarySection::Invalid; + size_t last_section_payload_offset_ = 0; + + size_t last_subsection_offset_ = 0; + size_t last_subsection_leb_size_guess_ = 0; + size_t last_subsection_payload_offset_ = 0; + + // Information about the data count section, so it can be removed if it is + // not needed, and relocs relative to the code section patched up. + size_t code_start_ = 0; + size_t data_count_start_ = 0; + size_t data_count_end_ = 0; + bool has_data_segment_instruction_ = false; +}; + +static uint8_t log2_u32(uint32_t x) { + uint8_t result = 0; + while (x > 1) { + x >>= 1; + result++; + } + return result; +} + +BinaryWriter::BinaryWriter(Stream* stream, + const WriteBinaryOptions& options, + const Module* module) + : stream_(stream), options_(options), module_(module) {} + +void BinaryWriter::WriteHeader(const char* name, int index) { + if (stream_->has_log_stream()) { + if (index == PRINT_HEADER_NO_INDEX) { + stream_->log_stream().Writef("; %s\n", name); + } else { + stream_->log_stream().Writef("; %s %d\n", name, index); + } + } +} + +/* returns offset of leb128 */ +Offset BinaryWriter::WriteU32Leb128Space(Offset leb_size_guess, + const char* desc) { + assert(leb_size_guess <= MAX_U32_LEB128_BYTES); + uint8_t data[MAX_U32_LEB128_BYTES] = {0}; + Offset result = stream_->offset(); + Offset bytes_to_write = + options_.canonicalize_lebs ? leb_size_guess : MAX_U32_LEB128_BYTES; + stream_->WriteData(data, bytes_to_write, desc); + return result; +} + +Offset BinaryWriter::WriteFixupU32Leb128Size(Offset offset, + Offset leb_size_guess, + const char* desc) { + if (options_.canonicalize_lebs) { + Offset size = stream_->offset() - offset - leb_size_guess; + Offset leb_size = U32Leb128Length(size); + Offset delta = leb_size - leb_size_guess; + if (delta != 0) { + Offset src_offset = offset + leb_size_guess; + Offset dst_offset = offset + leb_size; + stream_->MoveData(dst_offset, src_offset, size); + } + WriteU32Leb128At(stream_, offset, size, desc); + stream_->AddOffset(delta); + return delta; + } else { + Offset size = stream_->offset() - offset - MAX_U32_LEB128_BYTES; + WriteFixedU32Leb128At(stream_, offset, size, desc); + return 0; + } +} + +void BinaryWriter::WriteBlockDecl(const BlockDeclaration& decl) { + if (decl.sig.GetNumParams() == 0 && decl.sig.GetNumResults() <= 1) { + if (decl.sig.GetNumResults() == 0) { + WriteType(stream_, Type::Void); + } else if (decl.sig.GetNumResults() == 1) { + WriteType(stream_, decl.sig.GetResultType(0)); + } + return; + } + + Index index = decl.has_func_type ? module_->GetFuncTypeIndex(decl.type_var) + : module_->GetFuncTypeIndex(decl.sig); + assert(index != kInvalidIndex); + WriteS32Leb128WithReloc(index, "block type function index", RelocType::TypeIndexLEB); +} + +void BinaryWriter::WriteSectionHeader(const char* desc, + BinarySection section_code) { + assert(last_section_leb_size_guess_ == 0); + WriteHeader(desc, PRINT_HEADER_NO_INDEX); + stream_->WriteU8Enum(section_code, "section code"); + last_section_type_ = section_code; + last_section_leb_size_guess_ = LEB_SECTION_SIZE_GUESS; + last_section_offset_ = + WriteU32Leb128Space(LEB_SECTION_SIZE_GUESS, "section size (guess)"); + last_section_payload_offset_ = stream_->offset(); +} + +void BinaryWriter::BeginKnownSection(BinarySection section_code) { + char desc[100]; + wabt_snprintf(desc, sizeof(desc), "section \"%s\" (%u)", + GetSectionName(section_code), + static_cast(section_code)); + WriteSectionHeader(desc, section_code); +} + +void BinaryWriter::BeginCustomSection(const char* name) { + char desc[100]; + wabt_snprintf(desc, sizeof(desc), "section \"%s\"", name); + WriteSectionHeader(desc, BinarySection::Custom); + WriteStr(stream_, name, "custom section name", PrintChars::Yes); +} + +void BinaryWriter::EndSection() { + assert(last_section_leb_size_guess_ != 0); + WriteFixupU32Leb128Size(last_section_offset_, last_section_leb_size_guess_, + "FIXUP section size"); + last_section_leb_size_guess_ = 0; + section_count_++; +} + +void BinaryWriter::BeginSubsection(const char* name) { + assert(last_subsection_leb_size_guess_ == 0); + last_subsection_leb_size_guess_ = LEB_SECTION_SIZE_GUESS; + last_subsection_offset_ = + WriteU32Leb128Space(LEB_SECTION_SIZE_GUESS, "subsection size (guess)"); + last_subsection_payload_offset_ = stream_->offset(); +} + +void BinaryWriter::EndSubsection() { + assert(last_subsection_leb_size_guess_ != 0); + WriteFixupU32Leb128Size(last_subsection_offset_, + last_subsection_leb_size_guess_, + "FIXUP subsection size"); + last_subsection_leb_size_guess_ = 0; +} + +Index BinaryWriter::GetLabelVarDepth(const Var* var) { + return var->index(); +} + +Index BinaryWriter::GetEventVarDepth(const Var* var) { + return var->index(); +} + +Index BinaryWriter::GetSymbolIndex(RelocType reloc_type, Index index) { + switch (reloc_type) { + case RelocType::FuncIndexLEB: + return symtab_.FunctionSymbolIndex(index); + case RelocType::TableNumberLEB: + return symtab_.TableSymbolIndex(index); + case RelocType::GlobalIndexLEB: + return symtab_.GlobalSymbolIndex(index); + case RelocType::TypeIndexLEB: + // Type indexes don't create entries in the symbol table; instead their + // index is used directly. + return index; + default: + fprintf(stderr, "warning: unsupported relocation type: %s\n", + GetRelocTypeName(reloc_type)); + return kInvalidIndex; + } +} + +void BinaryWriter::AddReloc(RelocType reloc_type, Index index) { + // Add a new reloc section if needed + if (!current_reloc_section_ || + current_reloc_section_->section_index != section_count_) { + reloc_sections_.emplace_back(GetSectionName(last_section_type_), section_count_); + current_reloc_section_ = &reloc_sections_.back(); + } + + // Add a new relocation to the curent reloc section + size_t offset = stream_->offset() - last_section_payload_offset_; + Index symbol_index = GetSymbolIndex(reloc_type, index); + if (symbol_index == kInvalidIndex) { + // The file is invalid, for example a reference to function 42 where only 10 + // functions are defined. The user must have already passed --no-check, so + // no extra warning here is needed. + return; + } + current_reloc_section_->relocations.emplace_back(reloc_type, offset, + symbol_index); +} + +void BinaryWriter::WriteU32Leb128WithReloc(Index index, + const char* desc, + RelocType reloc_type) { + if (options_.relocatable) { + AddReloc(reloc_type, index); + WriteFixedU32Leb128(stream_, index, desc); + } else { + WriteU32Leb128(stream_, index, desc); + } +} + +void BinaryWriter::WriteS32Leb128WithReloc(int32_t value, + const char* desc, + RelocType reloc_type) { + if (options_.relocatable) { + AddReloc(reloc_type, value); + WriteFixedS32Leb128(stream_, value, desc); + } else { + WriteS32Leb128(stream_, value, desc); + } +} + +void BinaryWriter::WriteTableNumberWithReloc(Index value, + const char* desc) { + // Unless reference types are enabled, all references to tables refer to table + // 0, so no relocs need be emitted when making relocatable binaries. + if (options_.relocatable && options_.features.reference_types_enabled()) { + AddReloc(RelocType::TableNumberLEB, value); + WriteFixedS32Leb128(stream_, value, desc); + } else { + WriteS32Leb128(stream_, value, desc); + } +} + +Index BinaryWriter::GetLocalIndex(const Func* func, const Var& var) { + // func can be nullptr when using local.get/local.set/local.tee in an + // init_expr. + if (func) { + return func->GetLocalIndex(var); + } else if (var.is_index()) { + return var.index(); + } else { + return kInvalidIndex; + } +} + +// TODO(binji): Rename this, it is used for more than loads/stores now. +template +void BinaryWriter::WriteLoadStoreExpr(const Func* func, + const Expr* expr, + const char* desc) { + auto* typed_expr = cast(expr); + WriteOpcode(stream_, typed_expr->opcode); + Address align = typed_expr->opcode.GetAlignment(typed_expr->align); + stream_->WriteU8(log2_u32(align), "alignment"); + WriteU32Leb128(stream_, typed_expr->offset, desc); +} + +void BinaryWriter::WriteExpr(const Func* func, const Expr* expr) { + switch (expr->type()) { + case ExprType::AtomicLoad: + WriteLoadStoreExpr(func, expr, "memory offset"); + break; + case ExprType::AtomicRmw: + WriteLoadStoreExpr(func, expr, "memory offset"); + break; + case ExprType::AtomicRmwCmpxchg: + WriteLoadStoreExpr(func, expr, "memory offset"); + break; + case ExprType::AtomicStore: + WriteLoadStoreExpr(func, expr, "memory offset"); + break; + case ExprType::AtomicWait: + WriteLoadStoreExpr(func, expr, "memory offset"); + break; + case ExprType::AtomicFence: { + auto* fence_expr = cast(expr); + WriteOpcode(stream_, Opcode::AtomicFence); + WriteU32Leb128(stream_, fence_expr->consistency_model, + "consistency model"); + break; + } + case ExprType::AtomicNotify: + WriteLoadStoreExpr(func, expr, "memory offset"); + break; + case ExprType::Binary: + WriteOpcode(stream_, cast(expr)->opcode); + break; + case ExprType::Block: + WriteOpcode(stream_, Opcode::Block); + WriteBlockDecl(cast(expr)->block.decl); + WriteExprList(func, cast(expr)->block.exprs); + WriteOpcode(stream_, Opcode::End); + break; + case ExprType::Br: + WriteOpcode(stream_, Opcode::Br); + WriteU32Leb128(stream_, GetLabelVarDepth(&cast(expr)->var), + "break depth"); + break; + case ExprType::BrIf: + WriteOpcode(stream_, Opcode::BrIf); + WriteU32Leb128(stream_, GetLabelVarDepth(&cast(expr)->var), + "break depth"); + break; + case ExprType::BrTable: { + auto* br_table_expr = cast(expr); + WriteOpcode(stream_, Opcode::BrTable); + WriteU32Leb128(stream_, br_table_expr->targets.size(), "num targets"); + Index depth; + for (const Var& var : br_table_expr->targets) { + depth = GetLabelVarDepth(&var); + WriteU32Leb128(stream_, depth, "break depth"); + } + depth = GetLabelVarDepth(&br_table_expr->default_target); + WriteU32Leb128(stream_, depth, "break depth for default"); + break; + } + case ExprType::Call:{ + Index index = module_->GetFuncIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::Call); + WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB); + break; + } + case ExprType::ReturnCall: { + Index index = module_->GetFuncIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::ReturnCall); + WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB); + break; + } + case ExprType::CallIndirect:{ + Index sig_index = + module_->GetFuncTypeIndex(cast(expr)->decl); + Index table_index = + module_->GetTableIndex(cast(expr)->table); + WriteOpcode(stream_, Opcode::CallIndirect); + WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB); + WriteTableNumberWithReloc(table_index, "table index"); + break; + } + case ExprType::ReturnCallIndirect: { + Index sig_index = + module_->GetFuncTypeIndex(cast(expr)->decl); + Index table_index = + module_->GetTableIndex(cast(expr)->table); + WriteOpcode(stream_, Opcode::ReturnCallIndirect); + WriteU32Leb128WithReloc(sig_index, "signature index", RelocType::TypeIndexLEB); + WriteTableNumberWithReloc(table_index, "table index"); + break; + } + case ExprType::Compare: + WriteOpcode(stream_, cast(expr)->opcode); + break; + case ExprType::Const: { + const Const& const_ = cast(expr)->const_; + switch (const_.type()) { + case Type::I32: { + WriteOpcode(stream_, Opcode::I32Const); + WriteS32Leb128(stream_, const_.u32(), "i32 literal"); + break; + } + case Type::I64: + WriteOpcode(stream_, Opcode::I64Const); + WriteS64Leb128(stream_, const_.u64(), "i64 literal"); + break; + case Type::F32: + WriteOpcode(stream_, Opcode::F32Const); + stream_->WriteU32(const_.f32_bits(), "f32 literal"); + break; + case Type::F64: + WriteOpcode(stream_, Opcode::F64Const); + stream_->WriteU64(const_.f64_bits(), "f64 literal"); + break; + case Type::V128: + WriteOpcode(stream_, Opcode::V128Const); + stream_->WriteU128(const_.vec128(), "v128 literal"); + break; + default: + assert(0); + } + break; + } + case ExprType::Convert: + WriteOpcode(stream_, cast(expr)->opcode); + break; + case ExprType::Drop: + WriteOpcode(stream_, Opcode::Drop); + break; + case ExprType::GlobalGet: { + Index index = module_->GetGlobalIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::GlobalGet); + WriteU32Leb128WithReloc(index, "global index", RelocType::GlobalIndexLEB); + break; + } + case ExprType::GlobalSet: { + Index index = module_->GetGlobalIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::GlobalSet); + WriteU32Leb128WithReloc(index, "global index", RelocType::GlobalIndexLEB); + break; + } + case ExprType::If: { + auto* if_expr = cast(expr); + WriteOpcode(stream_, Opcode::If); + WriteBlockDecl(if_expr->true_.decl); + WriteExprList(func, if_expr->true_.exprs); + if (!if_expr->false_.empty()) { + WriteOpcode(stream_, Opcode::Else); + WriteExprList(func, if_expr->false_); + } + WriteOpcode(stream_, Opcode::End); + break; + } + case ExprType::Load: + WriteLoadStoreExpr(func, expr, "load offset"); + break; + case ExprType::LocalGet: { + Index index = GetLocalIndex(func, cast(expr)->var); + WriteOpcode(stream_, Opcode::LocalGet); + WriteU32Leb128(stream_, index, "local index"); + break; + } + case ExprType::LocalSet: { + Index index = GetLocalIndex(func, cast(expr)->var); + WriteOpcode(stream_, Opcode::LocalSet); + WriteU32Leb128(stream_, index, "local index"); + break; + } + case ExprType::LocalTee: { + Index index = GetLocalIndex(func, cast(expr)->var); + WriteOpcode(stream_, Opcode::LocalTee); + WriteU32Leb128(stream_, index, "local index"); + break; + } + case ExprType::Loop: + WriteOpcode(stream_, Opcode::Loop); + WriteBlockDecl(cast(expr)->block.decl); + WriteExprList(func, cast(expr)->block.exprs); + WriteOpcode(stream_, Opcode::End); + break; + case ExprType::MemoryCopy: + WriteOpcode(stream_, Opcode::MemoryCopy); + WriteU32Leb128(stream_, 0, "memory.copy reserved"); + WriteU32Leb128(stream_, 0, "memory.copy reserved"); + break; + case ExprType::DataDrop: { + Index index = + module_->GetDataSegmentIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::DataDrop); + WriteU32Leb128(stream_, index, "data.drop segment"); + has_data_segment_instruction_ = true; + break; + } + case ExprType::MemoryFill: + WriteOpcode(stream_, Opcode::MemoryFill); + WriteU32Leb128(stream_, 0, "memory.fill reserved"); + break; + case ExprType::MemoryGrow: + WriteOpcode(stream_, Opcode::MemoryGrow); + WriteU32Leb128(stream_, 0, "memory.grow reserved"); + break; + case ExprType::MemoryInit: { + Index index = + module_->GetDataSegmentIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::MemoryInit); + WriteU32Leb128(stream_, index, "memory.init segment"); + WriteU32Leb128(stream_, 0, "memory.init reserved"); + has_data_segment_instruction_ = true; + break; + } + case ExprType::MemorySize: + WriteOpcode(stream_, Opcode::MemorySize); + WriteU32Leb128(stream_, 0, "memory.size reserved"); + break; + case ExprType::TableCopy: { + auto* copy_expr = cast(expr); + Index dst = module_->GetTableIndex(copy_expr->dst_table); + Index src = module_->GetTableIndex(copy_expr->src_table); + WriteOpcode(stream_, Opcode::TableCopy); + WriteTableNumberWithReloc(dst, "table.copy dst_table"); + WriteTableNumberWithReloc(src, "table.copy src_table"); + break; + } + case ExprType::ElemDrop: { + Index index = + module_->GetElemSegmentIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::ElemDrop); + WriteU32Leb128(stream_, index, "elem.drop segment"); + break; + } + case ExprType::TableInit: { + auto* init_expr = cast(expr); + Index table_index = module_->GetTableIndex(init_expr->table_index); + Index segment_index = + module_->GetElemSegmentIndex(init_expr->segment_index); + WriteOpcode(stream_, Opcode::TableInit); + WriteU32Leb128(stream_, segment_index, "table.init segment"); + WriteTableNumberWithReloc(table_index, "table.init table"); + break; + } + case ExprType::TableGet: { + Index index = + module_->GetTableIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::TableGet); + WriteTableNumberWithReloc(index, "table.get table index"); + break; + } + case ExprType::TableSet: { + Index index = + module_->GetTableIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::TableSet); + WriteTableNumberWithReloc(index, "table.set table index"); + break; + } + case ExprType::TableGrow: { + Index index = + module_->GetTableIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::TableGrow); + WriteTableNumberWithReloc(index, "table.grow table index"); + break; + } + case ExprType::TableSize: { + Index index = + module_->GetTableIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::TableSize); + WriteTableNumberWithReloc(index, "table.size table index"); + break; + } + case ExprType::TableFill: { + Index index = + module_->GetTableIndex(cast(expr)->var); + WriteOpcode(stream_, Opcode::TableFill); + WriteTableNumberWithReloc(index, "table.fill table index"); + break; + } + case ExprType::RefFunc: { + WriteOpcode(stream_, Opcode::RefFunc); + Index index = module_->GetFuncIndex(cast(expr)->var); + WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB); + break; + } + case ExprType::RefNull: { + WriteOpcode(stream_, Opcode::RefNull); + WriteType(stream_, cast(expr)->type, "ref.null type"); + break; + } + case ExprType::RefIsNull: + WriteOpcode(stream_, Opcode::RefIsNull); + break; + case ExprType::Nop: + WriteOpcode(stream_, Opcode::Nop); + break; + case ExprType::Rethrow: + WriteOpcode(stream_, Opcode::Rethrow); + WriteU32Leb128(stream_, GetLabelVarDepth(&cast(expr)->var), + "rethrow depth"); + break; + case ExprType::Return: + WriteOpcode(stream_, Opcode::Return); + break; + case ExprType::Select: { + auto* select_expr = cast(expr); + if (select_expr->result_type.empty()) { + WriteOpcode(stream_, Opcode::Select); + } else { + WriteOpcode(stream_, Opcode::SelectT); + WriteU32Leb128(stream_, select_expr->result_type.size(), + "num result types"); + for (Type t : select_expr->result_type) { + WriteType(stream_, t, "result type"); + } + } + break; + } + case ExprType::Store: + WriteLoadStoreExpr(func, expr, "store offset"); + break; + case ExprType::Throw: + WriteOpcode(stream_, Opcode::Throw); + WriteU32Leb128(stream_, GetEventVarDepth(&cast(expr)->var), + "throw event"); + break; + case ExprType::Try: { + auto* try_expr = cast(expr); + WriteOpcode(stream_, Opcode::Try); + WriteBlockDecl(try_expr->block.decl); + WriteExprList(func, try_expr->block.exprs); + switch (try_expr->kind) { + case TryKind::Catch: + for (const Catch& catch_ : try_expr->catches) { + if (catch_.IsCatchAll()) { + WriteOpcode(stream_, Opcode::CatchAll); + } else { + WriteOpcode(stream_, Opcode::Catch); + WriteU32Leb128(stream_, GetEventVarDepth(&catch_.var), + "catch event"); + } + WriteExprList(func, catch_.exprs); + } + WriteOpcode(stream_, Opcode::End); + break; + case TryKind::Unwind: + WriteOpcode(stream_, Opcode::Unwind); + WriteExprList(func, try_expr->unwind); + WriteOpcode(stream_, Opcode::End); + break; + case TryKind::Delegate: + WriteOpcode(stream_, Opcode::Delegate); + WriteU32Leb128(stream_, + GetLabelVarDepth(&try_expr->delegate_target), + "delegate depth"); + break; + case TryKind::Invalid: + // Should not occur. + break; + } + break; + } + case ExprType::Unary: + WriteOpcode(stream_, cast(expr)->opcode); + break; + case ExprType::Ternary: + WriteOpcode(stream_, cast(expr)->opcode); + break; + case ExprType::SimdLaneOp: { + const Opcode opcode = cast(expr)->opcode; + WriteOpcode(stream_, opcode); + stream_->WriteU8(static_cast(cast(expr)->val), + "Simd Lane literal"); + break; + } + case ExprType::SimdShuffleOp: { + const Opcode opcode = cast(expr)->opcode; + WriteOpcode(stream_, opcode); + stream_->WriteU128(cast(expr)->val, + "Simd Lane[16] literal"); + break; + } + case ExprType::LoadSplat: + WriteLoadStoreExpr(func, expr, "load offset"); + break; + case ExprType::Unreachable: + WriteOpcode(stream_, Opcode::Unreachable); + break; + } +} + +void BinaryWriter::WriteExprList(const Func* func, const ExprList& exprs) { + for (const Expr& expr : exprs) { + WriteExpr(func, &expr); + } +} + +void BinaryWriter::WriteInitExpr(const ExprList& expr) { + WriteExprList(nullptr, expr); + WriteOpcode(stream_, Opcode::End); +} + +void BinaryWriter::WriteFuncLocals(const Func* func, + const LocalTypes& local_types) { + if (local_types.size() == 0) { + WriteU32Leb128(stream_, 0, "local decl count"); + return; + } + + Index local_decl_count = local_types.decls().size(); + WriteU32Leb128(stream_, local_decl_count, "local decl count"); + for (auto decl : local_types.decls()) { + WriteU32Leb128(stream_, decl.second, "local type count"); + WriteType(stream_, decl.first); + } +} + +void BinaryWriter::WriteFunc(const Func* func) { + WriteFuncLocals(func, func->local_types); + WriteExprList(func, func->exprs); + WriteOpcode(stream_, Opcode::End); +} + +void BinaryWriter::WriteTable(const Table* table) { + WriteType(stream_, table->elem_type); + WriteLimits(stream_, &table->elem_limits); +} + +void BinaryWriter::WriteMemory(const Memory* memory) { + WriteLimits(stream_, &memory->page_limits); +} + +void BinaryWriter::WriteGlobalHeader(const Global* global) { + WriteType(stream_, global->type); + stream_->WriteU8(global->mutable_, "global mutability"); +} + +void BinaryWriter::WriteEventType(const Event* event) { + WriteU32Leb128(stream_, 0, "event attribute"); + WriteU32Leb128(stream_, module_->GetFuncTypeIndex(event->decl), + "event signature index"); +} + +void BinaryWriter::WriteRelocSection(const RelocSection* reloc_section) { + char section_name[128]; + wabt_snprintf(section_name, sizeof(section_name), "%s.%s", + WABT_BINARY_SECTION_RELOC, reloc_section->name); + BeginCustomSection(section_name); + WriteU32Leb128(stream_, reloc_section->section_index, "reloc section index"); + const std::vector& relocs = reloc_section->relocations; + WriteU32Leb128(stream_, relocs.size(), "num relocs"); + + for (const Reloc& reloc : relocs) { + WriteU32Leb128(stream_, reloc.type, "reloc type"); + WriteU32Leb128(stream_, reloc.offset, "reloc offset"); + WriteU32Leb128(stream_, reloc.index, "reloc index"); + switch (reloc.type) { + case RelocType::MemoryAddressLEB: + case RelocType::MemoryAddressLEB64: + case RelocType::MemoryAddressSLEB: + case RelocType::MemoryAddressSLEB64: + case RelocType::MemoryAddressRelSLEB: + case RelocType::MemoryAddressRelSLEB64: + case RelocType::MemoryAddressI32: + case RelocType::MemoryAddressI64: + case RelocType::FunctionOffsetI32: + case RelocType::SectionOffsetI32: + case RelocType::MemoryAddressTLSSLEB: + case RelocType::MemoryAddressTLSI32: + WriteU32Leb128(stream_, reloc.addend, "reloc addend"); + break; + case RelocType::FuncIndexLEB: + case RelocType::TableIndexSLEB: + case RelocType::TableIndexSLEB64: + case RelocType::TableIndexI32: + case RelocType::TableIndexI64: + case RelocType::TypeIndexLEB: + case RelocType::GlobalIndexLEB: + case RelocType::EventIndexLEB: + case RelocType::TableIndexRelSLEB: + case RelocType::TableNumberLEB: + break; + default: + fprintf(stderr, "warning: unsupported relocation type: %s\n", + GetRelocTypeName(reloc.type)); + } + } + + EndSection(); +} + +void BinaryWriter::WriteLinkingSection() { + BeginCustomSection(WABT_BINARY_SECTION_LINKING); + WriteU32Leb128(stream_, 2, "metadata version"); + const std::vector& symbols = symtab_.symbols(); + if (symbols.size()) { + stream_->WriteU8Enum(LinkingEntryType::SymbolTable, "symbol table"); + BeginSubsection("symbol table"); + WriteU32Leb128(stream_, symbols.size(), "num symbols"); + + for (const Symbol& sym : symbols) { + stream_->WriteU8Enum(sym.type(), "symbol type"); + WriteU32Leb128(stream_, sym.flags(), "symbol flags"); + switch (sym.type()) { + case SymbolType::Function: + WriteU32Leb128(stream_, sym.AsFunction().index, "function index"); + if (sym.defined() || sym.explicit_name()) { + WriteStr(stream_, sym.name(), "function name", PrintChars::Yes); + } + break; + case SymbolType::Data: + WriteStr(stream_, sym.name(), "data name", PrintChars::Yes); + if (sym.defined()) { + WriteU32Leb128(stream_, sym.AsData().index, "data index"); + WriteU32Leb128(stream_, sym.AsData().offset, "data offset"); + WriteU32Leb128(stream_, sym.AsData().size, "data size"); + } + break; + case SymbolType::Global: + WriteU32Leb128(stream_, sym.AsGlobal().index, "global index"); + if (sym.defined() || sym.explicit_name()) { + WriteStr(stream_, sym.name(), "global name", PrintChars::Yes); + } + break; + case SymbolType::Section: + WriteU32Leb128(stream_, sym.AsSection().section, "section index"); + break; + case SymbolType::Event: + WriteU32Leb128(stream_, sym.AsEvent().index, "event index"); + if (sym.defined() || sym.explicit_name()) { + WriteStr(stream_, sym.name(), "event name", PrintChars::Yes); + } + break; + case SymbolType::Table: + WriteU32Leb128(stream_, sym.AsTable().index, "table index"); + if (sym.defined() || sym.explicit_name()) { + WriteStr(stream_, sym.name(), "table name", PrintChars::Yes); + } + break; + } + } + EndSubsection(); + } + EndSection(); +} + +template +void BinaryWriter::WriteNames(const std::vector& elems, + NameSectionSubsection type) { + size_t num_named_elems = 0; + for (const T* elem : elems) { + if (!elem->name.empty()) { + num_named_elems++; + } + } + + if (!num_named_elems) { + return; + } + + WriteU32Leb128(stream_, type, "name subsection type"); + BeginSubsection("name subsection"); + + char desc[100]; + WriteU32Leb128(stream_, num_named_elems, "num names"); + for (size_t i = 0; i < elems.size(); ++i) { + const T* elem = elems[i]; + if (elem->name.empty()) { + continue; + } + WriteU32Leb128(stream_, i, "elem index"); + wabt_snprintf(desc, sizeof(desc), "elem name %" PRIzd, i); + WriteDebugName(stream_, elem->name, desc); + } + EndSubsection(); +} + +Result BinaryWriter::WriteModule() { + stream_->WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC"); + stream_->WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION"); + + if (options_.relocatable) { + CHECK_RESULT(symtab_.Populate(module_)); + } + + if (module_->types.size()) { + BeginKnownSection(BinarySection::Type); + WriteU32Leb128(stream_, module_->types.size(), "num types"); + for (size_t i = 0; i < module_->types.size(); ++i) { + const TypeEntry* type = module_->types[i]; + switch (type->kind()) { + case TypeEntryKind::Func: { + const FuncType* func_type = cast(type); + const FuncSignature* sig = &func_type->sig; + WriteHeader("func type", i); + WriteType(stream_, Type::Func); + + Index num_params = sig->param_types.size(); + Index num_results = sig->result_types.size(); + WriteU32Leb128(stream_, num_params, "num params"); + for (size_t j = 0; j < num_params; ++j) { + WriteType(stream_, sig->param_types[j]); + } + + WriteU32Leb128(stream_, num_results, "num results"); + for (size_t j = 0; j < num_results; ++j) { + WriteType(stream_, sig->result_types[j]); + } + break; + } + + case TypeEntryKind::Struct: { + const StructType* struct_type = cast(type); + WriteHeader("struct type", i); + WriteType(stream_, Type::Struct); + Index num_fields = struct_type->fields.size(); + WriteU32Leb128(stream_, num_fields, "num fields"); + for (size_t j = 0; j < num_fields; ++j) { + const Field& field = struct_type->fields[j]; + WriteType(stream_, field.type); + stream_->WriteU8(field.mutable_, "field mutability"); + } + break; + } + + case TypeEntryKind::Array: { + const ArrayType* array_type = cast(type); + WriteHeader("array type", i); + WriteType(stream_, Type::Array); + WriteType(stream_, array_type->field.type); + stream_->WriteU8(array_type->field.mutable_, "field mutability"); + break; + } + } + } + EndSection(); + } + + if (module_->imports.size()) { + BeginKnownSection(BinarySection::Import); + WriteU32Leb128(stream_, module_->imports.size(), "num imports"); + + for (size_t i = 0; i < module_->imports.size(); ++i) { + const Import* import = module_->imports[i]; + WriteHeader("import header", i); + WriteStr(stream_, import->module_name, "import module name", + PrintChars::Yes); + WriteStr(stream_, import->field_name, "import field name", + PrintChars::Yes); + stream_->WriteU8Enum(import->kind(), "import kind"); + switch (import->kind()) { + case ExternalKind::Func: + WriteU32Leb128( + stream_, + module_->GetFuncTypeIndex(cast(import)->func.decl), + "import signature index"); + break; + + case ExternalKind::Table: + WriteTable(&cast(import)->table); + break; + + case ExternalKind::Memory: + WriteMemory(&cast(import)->memory); + break; + + case ExternalKind::Global: + WriteGlobalHeader(&cast(import)->global); + break; + + case ExternalKind::Event: + WriteEventType(&cast(import)->event); + break; + } + } + EndSection(); + } + + assert(module_->funcs.size() >= module_->num_func_imports); + Index num_funcs = module_->funcs.size() - module_->num_func_imports; + if (num_funcs) { + BeginKnownSection(BinarySection::Function); + WriteU32Leb128(stream_, num_funcs, "num functions"); + + for (size_t i = 0; i < num_funcs; ++i) { + const Func* func = module_->funcs[i + module_->num_func_imports]; + char desc[100]; + wabt_snprintf(desc, sizeof(desc), "function %" PRIzd " signature index", + i); + WriteU32Leb128(stream_, module_->GetFuncTypeIndex(func->decl), desc); + } + EndSection(); + } + + assert(module_->tables.size() >= module_->num_table_imports); + Index num_tables = module_->tables.size() - module_->num_table_imports; + if (num_tables) { + BeginKnownSection(BinarySection::Table); + WriteU32Leb128(stream_, num_tables, "num tables"); + for (size_t i = 0; i < num_tables; ++i) { + const Table* table = module_->tables[i + module_->num_table_imports]; + WriteHeader("table", i); + WriteTable(table); + } + EndSection(); + } + + assert(module_->memories.size() >= module_->num_memory_imports); + Index num_memories = module_->memories.size() - module_->num_memory_imports; + if (num_memories) { + BeginKnownSection(BinarySection::Memory); + WriteU32Leb128(stream_, num_memories, "num memories"); + for (size_t i = 0; i < num_memories; ++i) { + const Memory* memory = module_->memories[i + module_->num_memory_imports]; + WriteHeader("memory", i); + WriteMemory(memory); + } + EndSection(); + } + + assert(module_->events.size() >= module_->num_event_imports); + Index num_events = module_->events.size() - module_->num_event_imports; + if (num_events) { + BeginKnownSection(BinarySection::Event); + WriteU32Leb128(stream_, num_events, "event count"); + for (size_t i = 0; i < num_events; ++i) { + WriteHeader("event", i); + const Event* event = module_->events[i + module_->num_event_imports]; + WriteEventType(event); + } + EndSection(); + } + + assert(module_->globals.size() >= module_->num_global_imports); + Index num_globals = module_->globals.size() - module_->num_global_imports; + if (num_globals) { + BeginKnownSection(BinarySection::Global); + WriteU32Leb128(stream_, num_globals, "num globals"); + + for (size_t i = 0; i < num_globals; ++i) { + const Global* global = module_->globals[i + module_->num_global_imports]; + WriteGlobalHeader(global); + WriteInitExpr(global->init_expr); + } + EndSection(); + } + + if (module_->exports.size()) { + BeginKnownSection(BinarySection::Export); + WriteU32Leb128(stream_, module_->exports.size(), "num exports"); + + for (const Export* export_ : module_->exports) { + WriteStr(stream_, export_->name, "export name", PrintChars::Yes); + stream_->WriteU8Enum(export_->kind, "export kind"); + switch (export_->kind) { + case ExternalKind::Func: { + Index index = module_->GetFuncIndex(export_->var); + WriteU32Leb128(stream_, index, "export func index"); + break; + } + case ExternalKind::Table: { + Index index = module_->GetTableIndex(export_->var); + WriteU32Leb128(stream_, index, "export table index"); + break; + } + case ExternalKind::Memory: { + Index index = module_->GetMemoryIndex(export_->var); + WriteU32Leb128(stream_, index, "export memory index"); + break; + } + case ExternalKind::Global: { + Index index = module_->GetGlobalIndex(export_->var); + WriteU32Leb128(stream_, index, "export global index"); + break; + } + case ExternalKind::Event: { + Index index = module_->GetEventIndex(export_->var); + WriteU32Leb128(stream_, index, "export event index"); + break; + } + } + } + EndSection(); + } + + if (module_->starts.size()) { + Index start_func_index = module_->GetFuncIndex(*module_->starts[0]); + if (start_func_index != kInvalidIndex) { + BeginKnownSection(BinarySection::Start); + WriteU32Leb128(stream_, start_func_index, "start func index"); + EndSection(); + } + } + + if (module_->elem_segments.size()) { + BeginKnownSection(BinarySection::Elem); + WriteU32Leb128(stream_, module_->elem_segments.size(), "num elem segments"); + for (size_t i = 0; i < module_->elem_segments.size(); ++i) { + ElemSegment* segment = module_->elem_segments[i]; + WriteHeader("elem segment header", i); + // 1. flags + uint8_t flags = segment->GetFlags(module_); + stream_->WriteU8(flags, "segment flags"); + // 2. optional target table + if (flags & SegExplicitIndex && segment->kind != SegmentKind::Declared) { + WriteU32Leb128(stream_, module_->GetTableIndex(segment->table_var), + "table index"); + } + // 3. optional target location within the table (active segments only) + if (!(flags & SegPassive)) { + WriteInitExpr(segment->offset); + } + // 4. type of item in the following list (omitted for "legacy" segments) + if (flags & (SegPassive | SegExplicitIndex)) { + if (flags & SegUseElemExprs) { + WriteType(stream_, segment->elem_type, "elem expr list type"); + } else { + stream_->WriteU8Enum(ExternalKind::Func, "elem list type"); + } + } + // 5. actual list of elements (with extern indexes or elem expr's) + // preceeded by length + WriteU32Leb128(stream_, segment->elem_exprs.size(), "num elems"); + if (flags & SegUseElemExprs) { + for (const ElemExpr& elem_expr : segment->elem_exprs) { + switch (elem_expr.kind) { + case ElemExprKind::RefNull: + WriteOpcode(stream_, Opcode::RefNull); + WriteType(stream_, elem_expr.type, "elem expr ref.null type"); + break; + + case ElemExprKind::RefFunc: + WriteOpcode(stream_, Opcode::RefFunc); + WriteU32Leb128(stream_, module_->GetFuncIndex(elem_expr.var), "elem expr function index"); + break; + } + WriteOpcode(stream_, Opcode::End); + } + } else { + for (const ElemExpr& elem_expr : segment->elem_exprs) { + assert(elem_expr.kind == ElemExprKind::RefFunc); + WriteU32Leb128(stream_, module_->GetFuncIndex(elem_expr.var), "elem function index"); + } + } + } + EndSection(); + } + + if (options_.features.bulk_memory_enabled()) { + // Keep track of the data count section offset so it can be removed if + // it isn't needed. + data_count_start_ = stream_->offset(); + BeginKnownSection(BinarySection::DataCount); + WriteU32Leb128(stream_, module_->data_segments.size(), "data count"); + EndSection(); + data_count_end_ = stream_->offset(); + } + + if (num_funcs) { + code_start_ = stream_->offset(); + BeginKnownSection(BinarySection::Code); + WriteU32Leb128(stream_, num_funcs, "num functions"); + + for (size_t i = 0; i < num_funcs; ++i) { + WriteHeader("function body", i); + const Func* func = module_->funcs[i + module_->num_func_imports]; + + /* TODO(binji): better guess of the size of the function body section */ + const Offset leb_size_guess = 1; + Offset body_size_offset = + WriteU32Leb128Space(leb_size_guess, "func body size (guess)"); + WriteFunc(func); + auto func_start_offset = body_size_offset - last_section_payload_offset_; + auto func_end_offset = stream_->offset() - last_section_payload_offset_; + auto delta = WriteFixupU32Leb128Size(body_size_offset, leb_size_guess, + "FIXUP func body size"); + if (current_reloc_section_ && delta != 0) { + for (Reloc& reloc : current_reloc_section_->relocations) { + if (reloc.offset >= func_start_offset && reloc.offset <= func_end_offset) { + reloc.offset += delta; + } + } + } + } + EndSection(); + } + + // Remove the DataCount section if there are no instructions that require it. + if (options_.features.bulk_memory_enabled() && + !has_data_segment_instruction_) { + Offset size = stream_->offset() - data_count_end_; + if (size) { + // If the DataCount section was followed by anything, assert that it's + // only the Code section. This limits the amount of fixing-up that we + // need to do. + assert(data_count_end_ == code_start_); + assert(last_section_type_ == BinarySection::Code); + stream_->MoveData(data_count_start_, data_count_end_, size); + } + stream_->Truncate(data_count_start_ + size); + + --section_count_; + + // We just effectively decremented the code section's index; adjust anything + // that might have captured it. + for (RelocSection& section : reloc_sections_) { + if (section.section_index == section_count_) { + assert(last_section_type_ == BinarySection::Code); + --section.section_index; + } + } + } + + if (module_->data_segments.size()) { + BeginKnownSection(BinarySection::Data); + WriteU32Leb128(stream_, module_->data_segments.size(), "num data segments"); + for (size_t i = 0; i < module_->data_segments.size(); ++i) { + const DataSegment* segment = module_->data_segments[i]; + WriteHeader("data segment header", i); + uint8_t flags = segment->GetFlags(module_); + stream_->WriteU8(flags, "segment flags"); + if (!(flags & SegPassive)) { + assert(module_->GetMemoryIndex(segment->memory_var) == 0); + WriteInitExpr(segment->offset); + } + WriteU32Leb128(stream_, segment->data.size(), "data segment size"); + WriteHeader("data segment data", i); + stream_->WriteData(segment->data, "data segment data"); + } + EndSection(); + } + + if (options_.write_debug_names) { + std::vector index_to_name; + + char desc[100]; + BeginCustomSection(WABT_BINARY_SECTION_NAME); + + if (!module_->name.empty()) { + WriteU32Leb128(stream_, NameSectionSubsection::Module, + "module name type"); + BeginSubsection("module name subsection"); + WriteDebugName(stream_, module_->name, "module name"); + EndSubsection(); + } + + WriteNames(module_->funcs, NameSectionSubsection::Function); + + WriteU32Leb128(stream_, 2, "local name type"); + + BeginSubsection("local name subsection"); + WriteU32Leb128(stream_, module_->funcs.size(), "num functions"); + for (size_t i = 0; i < module_->funcs.size(); ++i) { + const Func* func = module_->funcs[i]; + Index num_params_and_locals = func->GetNumParamsAndLocals(); + + WriteU32Leb128(stream_, i, "function index"); + WriteU32Leb128(stream_, num_params_and_locals, "num locals"); + + MakeTypeBindingReverseMapping(num_params_and_locals, func->bindings, + &index_to_name); + for (size_t j = 0; j < num_params_and_locals; ++j) { + const std::string& name = index_to_name[j]; + wabt_snprintf(desc, sizeof(desc), "local name %" PRIzd, j); + WriteU32Leb128(stream_, j, "local index"); + WriteDebugName(stream_, name, desc); + } + } + EndSubsection(); + + WriteNames(module_->types, NameSectionSubsection::Type); + WriteNames(module_->tables, NameSectionSubsection::Table); + WriteNames(module_->memories, NameSectionSubsection::Memory); + WriteNames(module_->globals, NameSectionSubsection::Global); + WriteNames(module_->elem_segments, + NameSectionSubsection::ElemSegment); + WriteNames(module_->data_segments, + NameSectionSubsection::DataSegment); + + EndSection(); + } + + if (options_.relocatable) { + WriteLinkingSection(); + for (RelocSection& section : reloc_sections_) { + WriteRelocSection(§ion); + } + } + + return stream_->result(); +} + +} // end anonymous namespace + +Result WriteBinaryModule(Stream* stream, + const Module* module, + const WriteBinaryOptions& options) { + BinaryWriter binary_writer(stream, options, module); + return binary_writer.WriteModule(); +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.h new file mode 100644 index 0000000..4304a0a --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.h @@ -0,0 +1,62 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_WRITER_H_ +#define WABT_BINARY_WRITER_H_ + +#include "src/common.h" +#include "src/feature.h" +#include "src/opcode.h" +#include "src/stream.h" + +namespace wabt { + +struct Module; +struct Script; + +struct WriteBinaryOptions { + WriteBinaryOptions() = default; + WriteBinaryOptions(const Features& features, + bool canonicalize_lebs, + bool relocatable, + bool write_debug_names) + : features(features), + canonicalize_lebs(canonicalize_lebs), + relocatable(relocatable), + write_debug_names(write_debug_names) {} + + Features features; + bool canonicalize_lebs = true; + bool relocatable = false; + bool write_debug_names = false; +}; + +Result WriteBinaryModule(Stream*, const Module*, const WriteBinaryOptions&); + +void WriteType(Stream* stream, Type type, const char* desc = nullptr); + +void WriteStr(Stream* stream, + string_view s, + const char* desc, + PrintChars print_chars = PrintChars::No); + +void WriteOpcode(Stream* stream, Opcode opcode); + +void WriteLimits(Stream* stream, const Limits* limits); + +} // namespace wabt + +#endif /* WABT_BINARY_WRITER_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.cc new file mode 100644 index 0000000..60b20cb --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.cc @@ -0,0 +1,62 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binary.h" + +namespace wabt { + +BinarySectionOrder GetSectionOrder(BinarySection sec) { + switch (sec) { +#define V(Name, name, code) \ + case BinarySection::Name: \ + return BinarySectionOrder::Name; + WABT_FOREACH_BINARY_SECTION(V) +#undef V + default: + WABT_UNREACHABLE; + } +} + +const char* GetSectionName(BinarySection sec) { + switch (sec) { +#define V(Name, name, code) \ + case BinarySection::Name: \ + return #Name; + WABT_FOREACH_BINARY_SECTION(V) +#undef V + default: + WABT_UNREACHABLE; + } +} + +const char* NameSubsectionName[] = { + "module", + "function", + "local", + "label", + "type", + "table", + "memory", + "global", + "elemseg", + "dataseg", +}; + +const char* GetNameSectionSubsectionName(NameSectionSubsection subsec) { + return NameSubsectionName[size_t(subsec)]; +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.h new file mode 100644 index 0000000..d9877f9 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.h @@ -0,0 +1,93 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINARY_H_ +#define WABT_BINARY_H_ + +#include "src/common.h" + +#define WABT_BINARY_MAGIC 0x6d736100 +#define WABT_BINARY_VERSION 1 +#define WABT_BINARY_LIMITS_HAS_MAX_FLAG 0x1 +#define WABT_BINARY_LIMITS_IS_SHARED_FLAG 0x2 +#define WABT_BINARY_LIMITS_IS_64_FLAG 0x4 +#define WABT_BINARY_LIMITS_ALL_FLAGS \ + (WABT_BINARY_LIMITS_HAS_MAX_FLAG | WABT_BINARY_LIMITS_IS_SHARED_FLAG | \ + WABT_BINARY_LIMITS_IS_64_FLAG) + +#define WABT_BINARY_SECTION_NAME "name" +#define WABT_BINARY_SECTION_RELOC "reloc" +#define WABT_BINARY_SECTION_LINKING "linking" +#define WABT_BINARY_SECTION_DYLINK "dylink" + +#define WABT_FOREACH_BINARY_SECTION(V) \ + V(Custom, custom, 0) \ + V(Type, type, 1) \ + V(Import, import, 2) \ + V(Function, function, 3) \ + V(Table, table, 4) \ + V(Memory, memory, 5) \ + V(Event, event, 13) \ + V(Global, global, 6) \ + V(Export, export, 7) \ + V(Start, start, 8) \ + V(Elem, elem, 9) \ + V(DataCount, data_count, 12) \ + V(Code, code, 10) \ + V(Data, data, 11) + +namespace wabt { + +/* clang-format off */ +enum class BinarySection { +#define V(Name, name, code) Name = code, + WABT_FOREACH_BINARY_SECTION(V) +#undef V + Invalid = ~0, + + First = Custom, + Last = Event, +}; +/* clang-format on */ +static const int kBinarySectionCount = WABT_ENUM_COUNT(BinarySection); + +enum class BinarySectionOrder { +#define V(Name, name, code) Name, + WABT_FOREACH_BINARY_SECTION(V) +#undef V +}; + +BinarySectionOrder GetSectionOrder(BinarySection); +const char* GetSectionName(BinarySection); + +enum class NameSectionSubsection { + Module = 0, + Function = 1, + Local = 2, + Label = 3, + Type = 4, + Table = 5, + Memory = 6, + Global = 7, + ElemSegment = 8, + DataSegment = 9, + Last = DataSegment, +}; +const char* GetNameSectionSubsectionName(NameSectionSubsection subsec); + +} // namespace wabt + +#endif /* WABT_BINARY_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.cc new file mode 100644 index 0000000..f52682d --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.cc @@ -0,0 +1,91 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/binding-hash.h" + +#include +#include + +#include "src/ir.h" + +namespace wabt { + +void BindingHash::FindDuplicates(DuplicateCallback callback) const { + if (size() > 0) { + ValueTypeVector duplicates; + CreateDuplicatesVector(&duplicates); + SortDuplicatesVectorByLocation(&duplicates); + CallCallbacks(duplicates, callback); + } +} + +Index BindingHash::FindIndex(const Var& var) const { + if (var.is_name()) { + return FindIndex(var.name()); + } + return var.index(); +} + +void BindingHash::CreateDuplicatesVector( + ValueTypeVector* out_duplicates) const { + // This relies on the fact that in an unordered_multimap, all values with the + // same key are adjacent in iteration order. + auto first = begin(); + bool is_first = true; + for (auto iter = std::next(first); iter != end(); ++iter) { + if (first->first == iter->first) { + if (is_first) { + out_duplicates->push_back(&*first); + } + out_duplicates->push_back(&*iter); + is_first = false; + } else { + is_first = true; + first = iter; + } + } +} + +void BindingHash::SortDuplicatesVectorByLocation( + ValueTypeVector* duplicates) const { + std::sort( + duplicates->begin(), duplicates->end(), + [](const value_type* lhs, const value_type* rhs) -> bool { + return lhs->second.loc.line < rhs->second.loc.line || + (lhs->second.loc.line == rhs->second.loc.line && + lhs->second.loc.first_column < rhs->second.loc.first_column); + }); +} + +void BindingHash::CallCallbacks(const ValueTypeVector& duplicates, + DuplicateCallback callback) const { + // Loop through all duplicates in order, and call callback with first + // occurrence. + for (auto iter = duplicates.begin(), end = duplicates.end(); iter != end; + ++iter) { + auto first = std::find_if(duplicates.begin(), duplicates.end(), + [iter](const value_type* x) -> bool { + return x->first == (*iter)->first; + }); + if (first == iter) { + continue; + } + assert(first != duplicates.end()); + callback(**first, **iter); + } +} + +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.h new file mode 100644 index 0000000..0779527 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.h @@ -0,0 +1,72 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_BINDING_HASH_H_ +#define WABT_BINDING_HASH_H_ + +#include +#include +#include +#include + +#include "src/common.h" +#include "src/string-view.h" + +namespace wabt { + +struct Var; + +struct Binding { + explicit Binding(Index index) : index(index) {} + Binding(const Location& loc, Index index) : loc(loc), index(index) {} + + Location loc; + Index index; +}; + +// This class derives from a C++ container, which is usually not advisable +// because they don't have virtual destructors. So don't delete a BindingHash +// object through a pointer to std::unordered_multimap. +class BindingHash : public std::unordered_multimap { + public: + typedef std::function + DuplicateCallback; + + void FindDuplicates(DuplicateCallback callback) const; + + Index FindIndex(const Var&) const; + + Index FindIndex(const std::string& name) const { + auto iter = find(name); + return iter != end() ? iter->second.index : kInvalidIndex; + } + + Index FindIndex(string_view name) const { + return FindIndex(name.to_string()); + } + + private: + typedef std::vector ValueTypeVector; + + void CreateDuplicatesVector(ValueTypeVector* out_duplicates) const; + void SortDuplicatesVectorByLocation(ValueTypeVector* duplicates) const; + void CallCallbacks(const ValueTypeVector& duplicates, + DuplicateCallback callback) const; +}; + +} // namespace wabt + +#endif /* WABT_BINDING_HASH_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.cc new file mode 100644 index 0000000..d1129b2 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.cc @@ -0,0 +1,2245 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/c-writer.h" + +#include +#include +#include +#include + +#include "src/cast.h" +#include "src/common.h" +#include "src/ir.h" +#include "src/literal.h" +#include "src/stream.h" +#include "src/string-view.h" + +#define INDENT_SIZE 2 + +#define UNIMPLEMENTED(x) printf("unimplemented: %s\n", (x)), abort() + +namespace wabt { + +namespace { + +struct Label { + Label(LabelType label_type, + const std::string& name, + const TypeVector& sig, + size_t type_stack_size, + bool used = false) + : label_type(label_type), + name(name), + sig(sig), + type_stack_size(type_stack_size), + used(used) {} + + bool HasValue() const { + return label_type != LabelType::Loop && !sig.empty(); + } + + LabelType label_type; + const std::string& name; + const TypeVector& sig; + size_t type_stack_size; + bool used = false; +}; + +template +struct Name { + explicit Name(const std::string& name) : name(name) {} + const std::string& name; +}; + +typedef Name<0> LocalName; +typedef Name<1> GlobalName; +typedef Name<2> ExternalPtr; +typedef Name<3> ExternalRef; + +struct GotoLabel { + explicit GotoLabel(const Var& var) : var(var) {} + const Var& var; +}; + +struct LabelDecl { + explicit LabelDecl(const std::string& name) : name(name) {} + std::string name; +}; + +struct GlobalVar { + explicit GlobalVar(const Var& var) : var(var) {} + const Var& var; +}; + +struct StackVar { + explicit StackVar(Index index, Type type = Type::Any) + : index(index), type(type) {} + Index index; + Type type; +}; + +struct TypeEnum { + explicit TypeEnum(Type type) : type(type) {} + Type type; +}; + +struct SignedType { + explicit SignedType(Type type) : type(type) {} + Type type; +}; + +struct ResultType { + explicit ResultType(const TypeVector& types) : types(types) {} + const TypeVector& types; +}; + +struct Newline {}; +struct OpenBrace {}; +struct CloseBrace {}; + +int GetShiftMask(Type type) { + switch (type) { + case Type::I32: return 31; + case Type::I64: return 63; + default: WABT_UNREACHABLE; return 0; + } +} + +class CWriter { + public: + CWriter(Stream* c_stream, + Stream* h_stream, + const char* header_name, + const WriteCOptions& options) + : options_(options), + c_stream_(c_stream), + h_stream_(h_stream), + header_name_(header_name) {} + + Result WriteModule(const Module&); + + private: + typedef std::set SymbolSet; + typedef std::map SymbolMap; + typedef std::pair StackTypePair; + typedef std::map StackVarSymbolMap; + + void UseStream(Stream*); + + void WriteCHeader(); + void WriteCSource(); + + size_t MarkTypeStack() const; + void ResetTypeStack(size_t mark); + Type StackType(Index) const; + void PushType(Type); + void PushTypes(const TypeVector&); + void DropTypes(size_t count); + + void PushLabel(LabelType, + const std::string& name, + const FuncSignature&, + bool used = false); + const Label* FindLabel(const Var& var); + bool IsTopLabelUsed() const; + void PopLabel(); + + static std::string AddressOf(const std::string&); + static std::string Deref(const std::string&); + + static char MangleType(Type); + static std::string MangleTypes(const TypeVector&); + static std::string MangleName(string_view); + static std::string MangleFuncName(string_view, + const TypeVector& param_types, + const TypeVector& result_types); + static std::string MangleGlobalName(string_view, Type); + static std::string LegalizeName(string_view); + static std::string ExportName(string_view mangled_name); + std::string DefineName(SymbolSet*, string_view); + std::string DefineImportName(const std::string& name, + string_view module_name, + string_view mangled_field_name); + std::string DefineGlobalScopeName(const std::string&); + std::string DefineLocalScopeName(const std::string&); + std::string DefineStackVarName(Index, Type, string_view); + + void Indent(int size = INDENT_SIZE); + void Dedent(int size = INDENT_SIZE); + void WriteIndent(); + void WriteData(const void* src, size_t size); + void Writef(const char* format, ...); + + template + void Write(T&& t, U&& u, Args&&... args) { + Write(std::forward(t)); + Write(std::forward(u)); + Write(std::forward(args)...); + } + + std::string GetGlobalName(const std::string&) const; + + enum class WriteExportsKind { + Declarations, + Definitions, + Initializers, + }; + + void Write() {} + void Write(Newline); + void Write(OpenBrace); + void Write(CloseBrace); + void Write(Index); + void Write(string_view); + void Write(const LocalName&); + void Write(const GlobalName&); + void Write(const ExternalPtr&); + void Write(const ExternalRef&); + void Write(Type); + void Write(SignedType); + void Write(TypeEnum); + void Write(const Var&); + void Write(const GotoLabel&); + void Write(const LabelDecl&); + void Write(const GlobalVar&); + void Write(const StackVar&); + void Write(const ResultType&); + void Write(const Const&); + void WriteInitExpr(const ExprList&); + std::string GenerateHeaderGuard() const; + void WriteSourceTop(); + void WriteFuncTypes(); + void WriteImports(); + void WriteFuncDeclarations(); + void WriteFuncDeclaration(const FuncDeclaration&, const std::string&); + void WriteGlobals(); + void WriteGlobal(const Global&, const std::string&); + void WriteMemories(); + void WriteMemory(const std::string&); + void WriteTables(); + void WriteTable(const std::string&); + void WriteDataInitializers(); + void WriteElemInitializers(); + void WriteInitExports(); + void WriteExports(WriteExportsKind); + void WriteInit(); + void WriteFuncs(); + void Write(const Func&); + void WriteParamsAndLocals(); + void WriteParams(const std::vector& index_to_name); + void WriteLocals(const std::vector& index_to_name); + void WriteStackVarDeclarations(); + void Write(const ExprList&); + + enum class AssignOp { + Disallowed, + Allowed, + }; + + void WriteSimpleUnaryExpr(Opcode, const char* op); + void WriteInfixBinaryExpr(Opcode, + const char* op, + AssignOp = AssignOp::Allowed); + void WritePrefixBinaryExpr(Opcode, const char* op); + void WriteSignedBinaryExpr(Opcode, const char* op); + void Write(const BinaryExpr&); + void Write(const CompareExpr&); + void Write(const ConvertExpr&); + void Write(const LoadExpr&); + void Write(const StoreExpr&); + void Write(const UnaryExpr&); + void Write(const TernaryExpr&); + void Write(const SimdLaneOpExpr&); + void Write(const SimdShuffleOpExpr&); + void Write(const LoadSplatExpr&); + + const WriteCOptions& options_; + const Module* module_ = nullptr; + const Func* func_ = nullptr; + Stream* stream_ = nullptr; + MemoryStream func_stream_; + Stream* c_stream_ = nullptr; + Stream* h_stream_ = nullptr; + std::string header_name_; + Result result_ = Result::Ok; + int indent_ = 0; + bool should_write_indent_next_ = false; + + SymbolMap global_sym_map_; + SymbolMap local_sym_map_; + StackVarSymbolMap stack_var_sym_map_; + SymbolSet global_syms_; + SymbolSet local_syms_; + SymbolSet import_syms_; + TypeVector type_stack_; + std::vector
(store, type); +} + +inline const ExternType& Table::extern_type() { + return type_; +} + +inline const TableType& Table::type() const { + return type_; +} + +inline const RefVec& Table::elements() const { + return elements_; +} + +inline u32 Table::size() const { + return static_cast(elements_.size()); +} + +//// Memory //// +// static +inline bool Memory::classof(const Object* obj) { + return obj->kind() == skind; +} + +// static +inline Memory::Ptr Memory::New(interp::Store& store, MemoryType type) { + return store.Alloc(store, type); +} + +inline bool Memory::IsValidAccess(u64 offset, u64 addend, u64 size) const { + // FIXME: make this faster. + return offset <= data_.size() && + addend <= data_.size() && + size <= data_.size() && + offset + addend + size <= data_.size(); +} + +inline bool Memory::IsValidAtomicAccess(u64 offset, + u64 addend, + u64 size) const { + return IsValidAccess(offset, addend, size) && + ((offset + addend) & (size - 1)) == 0; +} + +template +Result Memory::Load(u64 offset, u64 addend, T* out) const { + if (!IsValidAccess(offset, addend, sizeof(T))) { + return Result::Error; + } + wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T)); + return Result::Ok; +} + +template +T WABT_VECTORCALL Memory::UnsafeLoad(u64 offset, u64 addend) const { + assert(IsValidAccess(offset, addend, sizeof(T))); + T val; + wabt::MemcpyEndianAware(&val, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T)); + return val; +} + +template +Result WABT_VECTORCALL Memory::Store(u64 offset, u64 addend, T val) { + if (!IsValidAccess(offset, addend, sizeof(T))) { + return Result::Error; + } + wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T), offset + addend, 0, sizeof(T)); + return Result::Ok; +} + +template +Result Memory::AtomicLoad(u64 offset, u64 addend, T* out) const { + if (!IsValidAtomicAccess(offset, addend, sizeof(T))) { + return Result::Error; + } + wabt::MemcpyEndianAware(out, data_.data(), sizeof(T), data_.size(), 0, offset + addend, sizeof(T)); + return Result::Ok; +} + +template +Result Memory::AtomicStore(u64 offset, u64 addend, T val) { + if (!IsValidAtomicAccess(offset, addend, sizeof(T))) { + return Result::Error; + } + wabt::MemcpyEndianAware(data_.data(), &val, data_.size(), sizeof(T), offset + addend, 0, sizeof(T)); + return Result::Ok; +} + +template +Result Memory::AtomicRmw(u64 offset, u64 addend, T rhs, F&& func, T* out) { + T lhs; + CHECK_RESULT(AtomicLoad(offset, addend, &lhs)); + CHECK_RESULT(AtomicStore(offset, addend, func(lhs, rhs))); + *out = lhs; + return Result::Ok; +} + +template +Result Memory::AtomicRmwCmpxchg(u64 offset, + u64 addend, + T expect, + T replace, + T* out) { + T read; + CHECK_RESULT(AtomicLoad(offset, addend, &read)); + if (read == expect) { + CHECK_RESULT(AtomicStore(offset, addend, replace)); + } + *out = read; + return Result::Ok; +} + +inline u8* Memory::UnsafeData() { + return data_.data(); +} + +inline u64 Memory::ByteSize() const { + return data_.size(); +} + +inline u64 Memory::PageSize() const { + return pages_; +} + +inline const ExternType& Memory::extern_type() { + return type_; +} + +inline const MemoryType& Memory::type() const { + return type_; +} + +//// Global //// +// static +inline bool Global::classof(const Object* obj) { + return obj->kind() == skind; +} + +// static +inline Global::Ptr Global::New(Store& store, GlobalType type, Value value) { + return store.Alloc(store, type, value); +} + +inline Value Global::Get() const { + return value_; +} + +template +Result Global::Get(T* out) const { + if (HasType(type_.type)) { + *out = value_.Get(); + return Result::Ok; + } + return Result::Error; +} + +template +T WABT_VECTORCALL Global::UnsafeGet() const { + RequireType(type_.type); + return value_.Get(); +} + +template +Result WABT_VECTORCALL Global::Set(T val) { + if (type_.mut == Mutability::Var && HasType(type_.type)) { + value_.Set(val); + return Result::Ok; + } + return Result::Error; +} + +inline const ExternType& Global::extern_type() { + return type_; +} + +inline const GlobalType& Global::type() const { + return type_; +} + +//// Event //// +// static +inline bool Event::classof(const Object* obj) { + return obj->kind() == skind; +} + +// static +inline Event::Ptr Event::New(Store& store, EventType type) { + return store.Alloc(store, type); +} + +inline const ExternType& Event::extern_type() { + return type_; +} + +inline const EventType& Event::type() const { + return type_; +} + +//// ElemSegment //// +inline void ElemSegment::Drop() { + elements_.clear(); +} + +inline const ElemDesc& ElemSegment::desc() const { + return *desc_; +} + +inline const RefVec& ElemSegment::elements() const { + return elements_; +} + +inline u32 ElemSegment::size() const { + return elements_.size(); +} + +//// DataSegment //// +inline void DataSegment::Drop() { + size_ = 0; +} + +inline const DataDesc& DataSegment::desc() const { + return *desc_; +} + +inline u64 DataSegment::size() const { + return size_; +} + +//// Module //// +// static +inline bool Module::classof(const Object* obj) { + return obj->kind() == skind; +} + +// static +inline Module::Ptr Module::New(Store& store, ModuleDesc desc) { + return store.Alloc(store, std::move(desc)); +} + +inline const ModuleDesc& Module::desc() const { + return desc_; +} + +inline const std::vector& Module::import_types() const { + return import_types_; +} + +inline const std::vector& Module::export_types() const { + return export_types_; +} + +//// Instance //// +// static +inline bool Instance::classof(const Object* obj) { + return obj->kind() == skind; +} + +inline Ref Instance::module() const { + return module_; +} + +inline const RefVec& Instance::imports() const { + return imports_; +} + +inline const RefVec& Instance::funcs() const { + return funcs_; +} + +inline const RefVec& Instance::tables() const { + return tables_; +} + +inline const RefVec& Instance::memories() const { + return memories_; +} + +inline const RefVec& Instance::globals() const { + return globals_; +} + +inline const RefVec& Instance::events() const { + return events_; +} + +inline const RefVec& Instance::exports() const { + return exports_; +} + +inline const std::vector& Instance::elems() const { + return elems_; +} + +inline std::vector& Instance::elems() { + return elems_; +} + +inline const std::vector& Instance::datas() const { + return datas_; +} + +inline std::vector& Instance::datas() { + return datas_; +} + +//// Thread //// +// static +inline bool Thread::classof(const Object* obj) { + return obj->kind() == skind; +} + +// static +inline Thread::Ptr Thread::New(Store& store, const Options& options) { + return store.Alloc(store, options); +} + +inline Store& Thread::store() { + return store_; +} + +} // namespace interp +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-math.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-math.h new file mode 100644 index 0000000..d5643d5 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-math.h @@ -0,0 +1,400 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_INTERP_MATH_H_ +#define WABT_INTERP_MATH_H_ + +#include +#include +#include +#include + +#if COMPILER_IS_MSVC +#include +#include +#endif + +#include "src/common.h" +#include "src/interp/interp.h" + +namespace wabt { +namespace interp { + +template < + typename T, + typename std::enable_if::value, int>::type = 0> +bool WABT_VECTORCALL IsNaN(T val) { + return false; +} + +template < + typename T, + typename std::enable_if::value, int>::type = 0> +bool WABT_VECTORCALL IsNaN(T val) { + return std::isnan(val); +} + +template < + typename T, + typename std::enable_if::value, int>::type = 0> +T WABT_VECTORCALL CanonNaN(T val) { + return val; +} + +template < + typename T, + typename std::enable_if::value, int>::type = 0> +T WABT_VECTORCALL CanonNaN(T val) { + if (WABT_UNLIKELY(std::isnan(val))) { + return std::numeric_limits::quiet_NaN(); + } + return val; +} + +template T ShiftMask(T val) { return val & (sizeof(T)*8-1); } + +template bool WABT_VECTORCALL IntEqz(T val) { return val == 0; } +template bool WABT_VECTORCALL Eq(T lhs, T rhs) { return lhs == rhs; } +template bool WABT_VECTORCALL Ne(T lhs, T rhs) { return lhs != rhs; } +template bool WABT_VECTORCALL Lt(T lhs, T rhs) { return lhs < rhs; } +template bool WABT_VECTORCALL Le(T lhs, T rhs) { return lhs <= rhs; } +template bool WABT_VECTORCALL Gt(T lhs, T rhs) { return lhs > rhs; } +template bool WABT_VECTORCALL Ge(T lhs, T rhs) { return lhs >= rhs; } +template T WABT_VECTORCALL IntClz(T val) { return Clz(val); } +template T WABT_VECTORCALL IntCtz(T val) { return Ctz(val); } +template T WABT_VECTORCALL IntPopcnt(T val) { return Popcount(val); } +template T WABT_VECTORCALL IntNot(T val) { return ~val; } +template T WABT_VECTORCALL IntNeg(T val) { return ~val + 1; } +template T WABT_VECTORCALL Add(T lhs, T rhs) { return CanonNaN(lhs + rhs); } +template T WABT_VECTORCALL Sub(T lhs, T rhs) { return CanonNaN(lhs - rhs); } +template T WABT_VECTORCALL IntAnd(T lhs, T rhs) { return lhs & rhs; } +template T WABT_VECTORCALL IntOr(T lhs, T rhs) { return lhs | rhs; } +template T WABT_VECTORCALL IntXor(T lhs, T rhs) { return lhs ^ rhs; } +template T WABT_VECTORCALL IntShl(T lhs, T rhs) { return lhs << ShiftMask(rhs); } +template T WABT_VECTORCALL IntShr(T lhs, T rhs) { return lhs >> ShiftMask(rhs); } +template T WABT_VECTORCALL IntMin(T lhs, T rhs) { return std::min(lhs, rhs); } +template T WABT_VECTORCALL IntMax(T lhs, T rhs) { return std::max(lhs, rhs); } +template T WABT_VECTORCALL IntAndNot(T lhs, T rhs) { return lhs & ~rhs; } +template T WABT_VECTORCALL IntAvgr(T lhs, T rhs) { return (lhs + rhs + 1) / 2; } +template T WABT_VECTORCALL Xchg(T lhs, T rhs) { return rhs; } + +// This is a wrapping absolute value function, so a negative number that is not +// representable as a positive number will be unchanged (e.g. abs(-128) = 128). +// +// Note that std::abs() does not have this behavior (e.g. abs(-128) is UB). +// Similarly, using unary minus is also UB. +template +T WABT_VECTORCALL IntAbs(T val) { + static_assert(std::is_unsigned::value, "T must be unsigned."); + const auto signbit = T(-1) << (sizeof(T) * 8 - 1); + return (val & signbit) ? ~val + 1 : val; +} + +// Because of the integer promotion rules [1], any value of a type T which is +// smaller than `int` will be converted to an `int`, as long as `int` can hold +// any value of type T. +// +// So type `u16` will be promoted to `int`, since all values can be stored in +// an int. Unfortunately, the product of two `u16` values cannot always be +// stored in an `int` (e.g. 65535 * 65535). This triggers an error in UBSan. +// +// As a result, we make sure to promote the type ahead of time for `u16`. Note +// that this isn't a problem for any other unsigned types. +// +// [1]; https://en.cppreference.com/w/cpp/language/implicit_conversion#Integral_promotion +template struct PromoteMul { using type = T; }; +template <> struct PromoteMul { using type = u32; }; + +template +T WABT_VECTORCALL Mul(T lhs, T rhs) { + using U = typename PromoteMul::type; + return CanonNaN(U(lhs) * U(rhs)); +} + +template struct Mask { using Type = T; }; +template <> struct Mask { using Type = u32; }; +template <> struct Mask { using Type = u64; }; + +template typename Mask::Type WABT_VECTORCALL EqMask(T lhs, T rhs) { return lhs == rhs ? -1 : 0; } +template typename Mask::Type WABT_VECTORCALL NeMask(T lhs, T rhs) { return lhs != rhs ? -1 : 0; } +template typename Mask::Type WABT_VECTORCALL LtMask(T lhs, T rhs) { return lhs < rhs ? -1 : 0; } +template typename Mask::Type WABT_VECTORCALL LeMask(T lhs, T rhs) { return lhs <= rhs ? -1 : 0; } +template typename Mask::Type WABT_VECTORCALL GtMask(T lhs, T rhs) { return lhs > rhs ? -1 : 0; } +template typename Mask::Type WABT_VECTORCALL GeMask(T lhs, T rhs) { return lhs >= rhs ? -1 : 0; } + +template +T WABT_VECTORCALL IntRotl(T lhs, T rhs) { + return (lhs << ShiftMask(rhs)) | (lhs >> ShiftMask(0 - rhs)); +} + +template +T WABT_VECTORCALL IntRotr(T lhs, T rhs) { + return (lhs >> ShiftMask(rhs)) | (lhs << ShiftMask(0 - rhs)); +} + +// i{32,64}.{div,rem}_s are special-cased because they trap when dividing the +// max signed value by -1. The modulo operation on x86 uses the same +// instruction to generate the quotient and the remainder. +template ::value, int>::type = 0> +bool IsNormalDivRem(T lhs, T rhs) { + return !(lhs == std::numeric_limits::min() && rhs == -1); +} + +template ::value, int>::type = 0> +bool IsNormalDivRem(T lhs, T rhs) { + return true; +} + +template +RunResult WABT_VECTORCALL IntDiv(T lhs, T rhs, T* out, std::string* out_msg) { + if (WABT_UNLIKELY(rhs == 0)) { + *out_msg = "integer divide by zero"; + return RunResult::Trap; + } + if (WABT_LIKELY(IsNormalDivRem(lhs, rhs))) { + *out = lhs / rhs; + return RunResult::Ok; + } else { + *out_msg = "integer overflow"; + return RunResult::Trap; + } +} + +template +RunResult WABT_VECTORCALL IntRem(T lhs, T rhs, T* out, std::string* out_msg) { + if (WABT_UNLIKELY(rhs == 0)) { + *out_msg = "integer divide by zero"; + return RunResult::Trap; + } + if (WABT_LIKELY(IsNormalDivRem(lhs, rhs))) { + *out = lhs % rhs; + } else { + *out = 0; + } + return RunResult::Ok; +} + +#if COMPILER_IS_MSVC +template T WABT_VECTORCALL FloatAbs(T val); +template T WABT_VECTORCALL FloatCopysign(T lhs, T rhs); + +// Don't use std::{abs,copysign} directly on MSVC, since that seems to lose +// the NaN tag. +template <> +inline f32 WABT_VECTORCALL FloatAbs(f32 val) { + return _mm_cvtss_f32(_mm_and_ps( + _mm_set1_ps(val), _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)))); +} + +template <> +inline f64 WABT_VECTORCALL FloatAbs(f64 val) { + return _mm_cvtsd_f64( + _mm_and_pd(_mm_set1_pd(val), + _mm_castsi128_pd(_mm_set1_epi64x(0x7fffffffffffffffull)))); +} + +template <> +inline f32 WABT_VECTORCALL FloatCopysign(f32 lhs, f32 rhs) { + return _mm_cvtss_f32( + _mm_or_ps( + _mm_and_ps(_mm_set1_ps(lhs), _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff))), + _mm_and_ps(_mm_set1_ps(rhs), _mm_castsi128_ps(_mm_set1_epi32(0x80000000))))); +} + +template <> +inline f64 WABT_VECTORCALL FloatCopysign(f64 lhs, f64 rhs) { + return _mm_cvtsd_f64( + _mm_or_pd( + _mm_and_pd(_mm_set1_pd(lhs), _mm_castsi128_pd(_mm_set1_epi64x(0x7fffffffffffffffull))), + _mm_and_pd(_mm_set1_pd(rhs), _mm_castsi128_pd(_mm_set1_epi64x(0x8000000000000000ull))))); +} + +#else +template +T WABT_VECTORCALL FloatAbs(T val) { + return std::abs(val); +} + +template +T WABT_VECTORCALL FloatCopysign(T lhs, T rhs) { + return std::copysign(lhs, rhs); +} +#endif + +#if COMPILER_IS_MSVC +#else +#endif + +template T WABT_VECTORCALL FloatNeg(T val) { return -val; } +template T WABT_VECTORCALL FloatCeil(T val) { return CanonNaN(std::ceil(val)); } +template T WABT_VECTORCALL FloatFloor(T val) { return CanonNaN(std::floor(val)); } +template T WABT_VECTORCALL FloatTrunc(T val) { return CanonNaN(std::trunc(val)); } +template T WABT_VECTORCALL FloatNearest(T val) { return CanonNaN(std::nearbyint(val)); } +template T WABT_VECTORCALL FloatSqrt(T val) { return CanonNaN(std::sqrt(val)); } + +template +T WABT_VECTORCALL FloatDiv(T lhs, T rhs) { + // IEE754 specifies what should happen when dividing a float by zero, but + // C/C++ says it is undefined behavior. + if (WABT_UNLIKELY(rhs == 0)) { + return std::isnan(lhs) || lhs == 0 + ? std::numeric_limits::quiet_NaN() + : ((std::signbit(lhs) ^ std::signbit(rhs)) + ? -std::numeric_limits::infinity() + : std::numeric_limits::infinity()); + } + return CanonNaN(lhs / rhs); +} + +template +T WABT_VECTORCALL FloatMin(T lhs, T rhs) { + if (WABT_UNLIKELY(std::isnan(lhs) || std::isnan(rhs))) { + return std::numeric_limits::quiet_NaN(); + } else if (WABT_UNLIKELY(lhs == 0 && rhs == 0)) { + return std::signbit(lhs) ? lhs : rhs; + } else { + return std::min(lhs, rhs); + } +} + +template +T WABT_VECTORCALL FloatPMin(T lhs, T rhs) { + return std::min(lhs, rhs); +} + +template +T WABT_VECTORCALL FloatMax(T lhs, T rhs) { + if (WABT_UNLIKELY(std::isnan(lhs) || std::isnan(rhs))) { + return std::numeric_limits::quiet_NaN(); + } else if (WABT_UNLIKELY(lhs == 0 && rhs == 0)) { + return std::signbit(lhs) ? rhs : lhs; + } else { + return std::max(lhs, rhs); + } +} + +template +T WABT_VECTORCALL FloatPMax(T lhs, T rhs) { + return std::max(lhs, rhs); +} + +template bool WABT_VECTORCALL CanConvert(T val) { return true; } +template <> inline bool WABT_VECTORCALL CanConvert(f32 val) { return val >= -2147483648.f && val < 2147483648.f; } +template <> inline bool WABT_VECTORCALL CanConvert(f64 val) { return val > -2147483649. && val < 2147483648.; } +template <> inline bool WABT_VECTORCALL CanConvert(f32 val) { return val > -1.f && val < 4294967296.f; } +template <> inline bool WABT_VECTORCALL CanConvert(f64 val) { return val > -1. && val < 4294967296.; } +template <> inline bool WABT_VECTORCALL CanConvert(f32 val) { return val >= -9223372036854775808.f && val < 9223372036854775808.f; } +template <> inline bool WABT_VECTORCALL CanConvert(f64 val) { return val >= -9223372036854775808. && val < 9223372036854775808.; } +template <> inline bool WABT_VECTORCALL CanConvert(f32 val) { return val > -1.f && val < 18446744073709551616.f; } +template <> inline bool WABT_VECTORCALL CanConvert(f64 val) { return val > -1. && val < 18446744073709551616.; } + +template +R WABT_VECTORCALL Convert(T val) { + assert((CanConvert(val))); + return static_cast(val); +} + +template <> +inline f32 WABT_VECTORCALL Convert(f64 val) { + // The WebAssembly rounding mode means that these values (which are > F32_MAX) + // should be rounded to F32_MAX and not set to infinity. Unfortunately, UBSAN + // complains that the value is not representable as a float, so we'll special + // case them. + const f64 kMin = 3.4028234663852886e38; + const f64 kMax = 3.4028235677973366e38; + if (WABT_LIKELY(val >= -kMin && val <= kMin)) { + return val; + } else if (WABT_UNLIKELY(val > kMin && val < kMax)) { + return std::numeric_limits::max(); + } else if (WABT_UNLIKELY(val > -kMax && val < -kMin)) { + return -std::numeric_limits::max(); + } else if (WABT_UNLIKELY(std::isnan(val))) { + return std::numeric_limits::quiet_NaN(); + } else { + return std::copysign(std::numeric_limits::infinity(), val); + } +} + +template <> +inline f32 WABT_VECTORCALL Convert(u64 val) { + return wabt_convert_uint64_to_float(val); +} + +template <> +inline f64 WABT_VECTORCALL Convert(u64 val) { + return wabt_convert_uint64_to_double(val); +} + +template <> +inline f32 WABT_VECTORCALL Convert(s64 val) { + return wabt_convert_int64_to_float(val); +} + +template <> +inline f64 WABT_VECTORCALL Convert(s64 val) { + return wabt_convert_int64_to_double(val); +} + +template +T WABT_VECTORCALL IntExtend(T val) { + // Hacker's delight 2.6 - sign extension + auto bit = T{1} << N; + auto mask = (bit << 1) - 1; + return ((val & mask) ^ bit) - bit; +} + +template +R WABT_VECTORCALL IntTruncSat(T val) { + if (WABT_UNLIKELY(std::isnan(val))) { + return 0; + } else if (WABT_UNLIKELY(!CanConvert(val))) { + return std::signbit(val) ? std::numeric_limits::min() + : std::numeric_limits::max(); + } else { + return static_cast(val); + } +} + +template struct SatPromote; +template <> struct SatPromote { using type = s32; }; +template <> struct SatPromote { using type = s32; }; +template <> struct SatPromote { using type = s32; }; +template <> struct SatPromote { using type = s32; }; + +template +R WABT_VECTORCALL Saturate(T val) { + static_assert(sizeof(R) < sizeof(T), "Incorrect types for Saturate"); + const T min = std::numeric_limits::min(); + const T max = std::numeric_limits::max(); + return val > max ? max : val < min ? min : val; +} + +template ::type> +T WABT_VECTORCALL IntAddSat(T lhs, T rhs) { + return Saturate(lhs + rhs); +} + +template ::type> +T WABT_VECTORCALL IntSubSat(T lhs, T rhs) { + return Saturate(lhs - rhs); +} + +} // namespace interp +} // namespace wabt + +#endif // WABT_INTERP_MATH_H_ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.cc new file mode 100644 index 0000000..001b2d9 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.cc @@ -0,0 +1,114 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/interp/interp-util.h" + +#include + +#include "src/stream.h" + +namespace wabt { +namespace interp { + +std::string TypedValueToString(const TypedValue& tv) { + switch (tv.type) { + case Type::I32: + return StringPrintf("i32:%u", tv.value.Get()); + + case Type::I64: + return StringPrintf("i64:%" PRIu64, tv.value.Get()); + + case Type::F32: + return StringPrintf("f32:%f", tv.value.Get()); + + case Type::F64: + return StringPrintf("f64:%f", tv.value.Get()); + + case Type::V128: { + v128 simd = tv.value.Get(); + return StringPrintf("v128 i32x4:0x%08x 0x%08x 0x%08x 0x%08x", simd.u32(0), + simd.u32(1), simd.u32(2), simd.u32(3)); + } + + case Type::I8: // For SIMD lane. + return StringPrintf("i8:%u", tv.value.Get() & 0xff); + + case Type::I16: // For SIMD lane. + return StringPrintf("i16:%u", tv.value.Get() & 0xffff); + + case Type::FuncRef: + return StringPrintf("funcref:%" PRIzd, tv.value.Get().index); + + case Type::ExternRef: + return StringPrintf("externref:%" PRIzd, tv.value.Get().index); + + case Type::Func: + case Type::Struct: + case Type::Array: + case Type::Void: + case Type::Any: + case Type::I8U: + case Type::I16U: + case Type::I32U: + // These types are not concrete types and should never exist as a value + WABT_UNREACHABLE; + } + WABT_UNREACHABLE; +} + +void WriteValue(Stream* stream, const TypedValue& tv) { + std::string s = TypedValueToString(tv); + stream->WriteData(s.data(), s.size()); +} + +void WriteValues(Stream* stream, + const ValueTypes& types, + const Values& values) { + assert(types.size() == values.size()); + for (size_t i = 0; i < values.size(); ++i) { + WriteValue(stream, TypedValue{types[i], values[i]}); + if (i != values.size() - 1) { + stream->Writef(", "); + } + } +} + +void WriteTrap(Stream* stream, const char* desc, const Trap::Ptr& trap) { + stream->Writef("%s: %s\n", desc, trap->message().c_str()); +} + +void WriteCall(Stream* stream, + string_view name, + const FuncType& func_type, + const Values& params, + const Values& results, + const Trap::Ptr& trap) { + stream->Writef(PRIstringview "(", WABT_PRINTF_STRING_VIEW_ARG(name)); + WriteValues(stream, func_type.params, params); + stream->Writef(") =>"); + if (!trap) { + if (!results.empty()) { + stream->Writef(" "); + WriteValues(stream, func_type.results, results); + } + stream->Writef("\n"); + } else { + WriteTrap(stream, " error", trap); + } +} + +} // namespace interp +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.h new file mode 100644 index 0000000..d05b34d --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.h @@ -0,0 +1,50 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_INTERP_UTIL_H_ +#define WABT_INTERP_UTIL_H_ + +#include +#include + +#include "src/interp/interp.h" +#include "src/string-view.h" + +namespace wabt { + +class Stream; + +namespace interp { + +std::string TypedValueToString(const TypedValue&); + +void WriteValue(Stream* stream, const TypedValue&); + +void WriteValues(Stream* stream, const ValueTypes&, const Values&); + +void WriteTrap(Stream* stream, const char* desc, const Trap::Ptr&); + +void WriteCall(Stream* stream, + string_view name, + const FuncType& func_type, + const Values& params, + const Values& results, + const Trap::Ptr& trap); + +} // namespace interp +} // namespace wabt + +#endif // WABT_INTERP_UTIL_H_ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.cc new file mode 100644 index 0000000..80deec2 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.cc @@ -0,0 +1,760 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +/* + * This is an experiment and currently extremely limited implementation + * of the WASI syscall API. The implementation of the API itself is coming from + * uvwasi: https://github.com/cjihrig/uvwasi. + * + * Most of the code in the file is mostly marshelling data between the wabt + * interpreter and uvwasi. + * + * For details of the WASI api see: + * https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md + * and the C headers version: + * https://github.com/WebAssembly/wasi-libc/blob/master/libc-bottom-half/headers/public/wasi/api.h + */ + +#include "src/interp/interp-wasi.h" +#include "src/interp/interp-util.h" + +#ifdef WITH_WASI + +#include "uvwasi.h" + +#include +#include + +using namespace wabt; +using namespace wabt::interp; + +namespace { + +// Types that align with WASI spec on size and alignment. These are +// copied directly from wasi-lib's auto-generated api.h +// TODO(sbc): Auto-generate this from witx. + +// BEGIN: wasi.h types from wasi-libc + +typedef uint32_t __wasi_size_t; +typedef uint32_t __wasi_ptr_t; + +static_assert(sizeof(__wasi_size_t) == 4, "witx calculated size"); +static_assert(alignof(__wasi_size_t) == 4, "witx calculated align"); +static_assert(sizeof(__wasi_ptr_t) == 4, "witx calculated size"); +static_assert(alignof(__wasi_ptr_t) == 4, "witx calculated align"); + +typedef struct __wasi_prestat_dir_t { + __wasi_size_t pr_name_len; +} __wasi_prestat_dir_t; + +typedef uint8_t __wasi_preopentype_t; +typedef uint64_t __wasi_rights_t; +typedef uint16_t __wasi_fdflags_t; +typedef uint8_t __wasi_filetype_t; +typedef uint16_t __wasi_oflags_t; +typedef uint32_t __wasi_lookupflags_t; +typedef uint32_t __wasi_fd_t; +typedef uint64_t __wasi_timestamp_t; +typedef uint8_t __wasi_whence_t; +typedef int64_t __wasi_filedelta_t; +typedef uint64_t __wasi_filesize_t; + +typedef union __wasi_prestat_u_t { + __wasi_prestat_dir_t dir; +} __wasi_prestat_u_t; + +struct __wasi_prestat_t { + __wasi_preopentype_t tag; + __wasi_prestat_u_t u; +}; + +typedef struct __wasi_fdstat_t { + __wasi_filetype_t fs_filetype; + __wasi_fdflags_t fs_flags; + __wasi_rights_t fs_rights_base; + __wasi_rights_t fs_rights_inheriting; +} __wasi_fdstat_t; + +static_assert(sizeof(__wasi_fdstat_t) == 24, "witx calculated size"); +static_assert(alignof(__wasi_fdstat_t) == 8, "witx calculated align"); +static_assert(offsetof(__wasi_fdstat_t, fs_filetype) == 0, + "witx calculated offset"); +static_assert(offsetof(__wasi_fdstat_t, fs_flags) == 2, + "witx calculated offset"); +static_assert(offsetof(__wasi_fdstat_t, fs_rights_base) == 8, + "witx calculated offset"); +static_assert(offsetof(__wasi_fdstat_t, fs_rights_inheriting) == 16, + "witx calculated offset"); + +struct __wasi_iovec_t { + __wasi_ptr_t buf; + __wasi_size_t buf_len; +}; + +static_assert(sizeof(__wasi_iovec_t) == 8, "witx calculated size"); +static_assert(alignof(__wasi_iovec_t) == 4, "witx calculated align"); +static_assert(offsetof(__wasi_iovec_t, buf) == 0, "witx calculated offset"); +static_assert(offsetof(__wasi_iovec_t, buf_len) == 4, "witx calculated offset"); + +typedef uint64_t __wasi_device_t; + +static_assert(sizeof(__wasi_device_t) == 8, "witx calculated size"); +static_assert(alignof(__wasi_device_t) == 8, "witx calculated align"); + +typedef uint64_t __wasi_inode_t; + +static_assert(sizeof(__wasi_inode_t) == 8, "witx calculated size"); +static_assert(alignof(__wasi_inode_t) == 8, "witx calculated align"); + +typedef uint64_t __wasi_linkcount_t; + +static_assert(sizeof(__wasi_linkcount_t) == 8, "witx calculated size"); +static_assert(alignof(__wasi_linkcount_t) == 8, "witx calculated align"); + +typedef struct __wasi_filestat_t { + __wasi_device_t dev; + __wasi_inode_t ino; + __wasi_filetype_t filetype; + __wasi_linkcount_t nlink; + __wasi_filesize_t size; + __wasi_timestamp_t atim; + __wasi_timestamp_t mtim; + __wasi_timestamp_t ctim; +} __wasi_filestat_t; + +static_assert(sizeof(__wasi_filestat_t) == 64, "witx calculated size"); +static_assert(alignof(__wasi_filestat_t) == 8, "witx calculated align"); +static_assert(offsetof(__wasi_filestat_t, dev) == 0, "witx calculated offset"); +static_assert(offsetof(__wasi_filestat_t, ino) == 8, "witx calculated offset"); +static_assert(offsetof(__wasi_filestat_t, filetype) == 16, + "witx calculated offset"); +static_assert(offsetof(__wasi_filestat_t, nlink) == 24, + "witx calculated offset"); +static_assert(offsetof(__wasi_filestat_t, size) == 32, + "witx calculated offset"); +static_assert(offsetof(__wasi_filestat_t, atim) == 40, + "witx calculated offset"); +static_assert(offsetof(__wasi_filestat_t, mtim) == 48, + "witx calculated offset"); +static_assert(offsetof(__wasi_filestat_t, ctim) == 56, + "witx calculated offset"); + +#define __WASI_ERRNO_SUCCESS (UINT16_C(0)) +#define __WASI_ERRNO_NOENT (UINT16_C(44)) + +// END wasi.h types from wasi-lib + +class WasiInstance { + public: + WasiInstance(Instance::Ptr instance, + uvwasi_s* uvwasi, + Memory* memory, + Stream* trace_stream) + : trace_stream(trace_stream), + instance(instance), + uvwasi(uvwasi), + memory(memory) {} + + Result random_get(const Values& params, Values& results, Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_random_get(uint8_t * buf, __wasi_size_t buf_len) */ + assert(false); + return Result::Ok; + } + + Result proc_exit(const Values& params, Values& results, Trap::Ptr* trap) { + const Value arg0 = params[0]; + uvwasi_proc_exit(uvwasi, arg0.i32_); + return Result::Ok; + } + + Result poll_oneoff(const Values& params, Values& results, Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result clock_time_get(const Values& params, + Values& results, + Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_clock_time_get(__wasi_clockid_t id, + * __wasi_timestamp_t precision, + * __wasi_timestamp_t *time) + */ + __wasi_timestamp_t t; + results[0].i32_ = + uvwasi_clock_time_get(uvwasi, params[0].i32_, params[1].i64_, &t); + uint32_t time_ptr = params[2].i32_; + CHECK_RESULT(writeValue<__wasi_timestamp_t>(t, time_ptr, trap)); + return Result::Ok; + } + + Result path_rename(const Values& params, Values& results, Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result path_open(const Values& params, Values& results, Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_path_open(__wasi_fd_t fd, + __wasi_lookupflags_t dirflags, + const char *path, + size_t path_len, + __wasi_oflags_t oflags, + __wasi_rights_t fs_rights_base, + __wasi_rights_t fs_rights_inherting, + __wasi_fdflags_t fdflags, + __wasi_fd_t *opened_fd) */ + uvwasi_fd_t dirfd = params[0].i32_; + __wasi_lookupflags_t dirflags = params[1].i32_; + uint32_t path_ptr = params[2].i32_; + __wasi_size_t path_len = params[3].i32_; + __wasi_oflags_t oflags = params[4].i32_; + __wasi_rights_t fs_rights_base = params[5].i32_; + __wasi_rights_t fs_rights_inherting = params[6].i32_; + __wasi_fdflags_t fs_flags = params[7].i32_; + uint32_t out_ptr = params[8].i32_; + char* path; + CHECK_RESULT(getMemPtr(path_ptr, path_len, &path, trap)); + if (trace_stream) { + trace_stream->Writef("path_open : %s\n", path); + } + uvwasi_fd_t outfd; + results[0].i32_ = + uvwasi_path_open(uvwasi, dirfd, dirflags, path, path_len, oflags, + fs_rights_base, fs_rights_inherting, fs_flags, &outfd); + if (trace_stream) { + trace_stream->Writef("path_open -> %d\n", results[0].i32_); + } + CHECK_RESULT(writeValue<__wasi_fd_t>(outfd, out_ptr, trap)); + return Result::Ok; + } + + Result path_filestat_get(const Values& params, + Values& results, + Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_path_filestat_get(__wasi_fd_t fd, + * __wasi_lookupflags_t flags, + * const char *path, + * size_t path_len, + * __wasi_filestat_t *buf + */ + uvwasi_fd_t fd = params[0].i32_; + __wasi_lookupflags_t flags = params[1].i32_; + uint32_t path_ptr = params[2].i32_; + uvwasi_size_t path_len = params[3].i32_; + uint32_t filestat_ptr = params[4].i32_; + char* path; + CHECK_RESULT(getMemPtr(path_ptr, path_len, &path, trap)); + if (trace_stream) { + trace_stream->Writef("path_filestat_get : %d %s\n", fd, path); + } + uvwasi_filestat_t buf; + results[0].i32_ = + uvwasi_path_filestat_get(uvwasi, fd, flags, path, path_len, &buf); + __wasi_filestat_t* filestat; + CHECK_RESULT(getMemPtr<__wasi_filestat_t>( + filestat_ptr, sizeof(__wasi_filestat_t), &filestat, trap)); + uvwasi_serdes_write_filestat_t(filestat, 0, &buf); + if (trace_stream) { + trace_stream->Writef("path_filestat_get -> size=%" PRIu64 " %d\n", buf.st_size, + results[0].i32_); + } + return Result::Ok; + } + + Result path_symlink(const Values& params, Values& results, Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_path_symlink(const char *old_path, + * size_t old_path_len, + * __wasi_fd_t fd, + * const char *new_path, + * size_t new_path_len); + */ + + uint32_t old_path_ptr = params[0].i32_; + __wasi_size_t old_path_len = params[1].i32_; + uvwasi_fd_t fd = params[2].i32_; + uint32_t new_path_ptr = params[3].i32_; + __wasi_size_t new_path_len = params[4].i32_; + char* old_path; + char* new_path; + CHECK_RESULT(getMemPtr(old_path_ptr, old_path_len, &old_path, trap)); + CHECK_RESULT(getMemPtr(new_path_ptr, new_path_len, &new_path, trap)); + if (trace_stream) { + trace_stream->Writef("path_symlink %d %s : %s\n", fd, old_path, new_path); + } + results[0].i32_ = uvwasi_path_symlink(uvwasi, old_path, old_path_len, fd, + new_path, new_path_len); + if (trace_stream) { + trace_stream->Writef("path_symlink -> %d\n", results[0].i32_); + } + return Result::Ok; + } + + Result path_readlink(const Values& params, Values& results, Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result path_create_directory(const Values& params, + Values& results, + Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result path_remove_directory(const Values& params, + Values& results, + Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result path_unlink_file(const Values& params, + Values& results, + Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_path_unlink_file(__wasi_fd_t fd, + * const char *path, + * size_t path_len) + */ + uvwasi_fd_t fd = params[0].i32_; + uint32_t path_ptr = params[1].i32_; + __wasi_size_t path_len = params[2].i32_; + char* path; + CHECK_RESULT(getMemPtr(path_ptr, path_len, &path, trap)); + if (trace_stream) { + trace_stream->Writef("path_unlink_file %d %s\n", fd, path); + } + results[0].i32_ = uvwasi_path_unlink_file(uvwasi, fd, path, path_len); + return Result::Ok; + } + + Result fd_prestat_get(const Values& params, + Values& results, + Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_fd_prestat_get(__wasi_fd_t fd, + * __wasi_prestat_t *buf)) + */ + uvwasi_fd_t fd = params[0].i32_; + uint32_t prestat_ptr = params[1].i32_; + if (trace_stream) { + trace_stream->Writef("fd_prestat_get %d\n", fd); + } + uvwasi_prestat_t buf; + results[0].i32_ = uvwasi_fd_prestat_get(uvwasi, fd, &buf); + __wasi_prestat_t* prestat; + CHECK_RESULT(getMemPtr<__wasi_prestat_t>(prestat_ptr, 1, &prestat, trap)); + uvwasi_serdes_write_prestat_t(prestat, 0, &buf); + if (trace_stream) { + trace_stream->Writef("fd_prestat_get -> %d\n", results[0].i32_); + } + return Result::Ok; + } + + Result fd_prestat_dir_name(const Values& params, + Values& results, + Trap::Ptr* trap) { + uvwasi_fd_t fd = params[0].i32_; + uint32_t path_ptr = params[1].i32_; + uvwasi_size_t path_len = params[2].i32_; + if (trace_stream) { + trace_stream->Writef("fd_prestat_dir_name %d %d %d\n", fd, path_ptr, + path_len); + } + char* path; + CHECK_RESULT(getMemPtr(path_ptr, path_len, &path, trap)); + results[0].i32_ = uvwasi_fd_prestat_dir_name(uvwasi, fd, path, path_len); + if (trace_stream) { + trace_stream->Writef("fd_prestat_dir_name %d -> %d %s %d\n", fd, + results[0].i32_, path, path_len); + } + return Result::Ok; + } + + Result fd_filestat_get(const Values& params, + Values& results, + Trap::Ptr* trap) { + /* __wasi_fd_filestat_get(__wasi_fd_t f, __wasi_filestat_t *buf) */ + uvwasi_fd_t fd = params[0].i32_; + uint32_t filestat_ptr = params[1].i32_; + uvwasi_filestat_t buf; + results[0].i32_ = uvwasi_fd_filestat_get(uvwasi, fd, &buf); + __wasi_filestat_t* filestat; + CHECK_RESULT(getMemPtr<__wasi_filestat_t>( + filestat_ptr, sizeof(__wasi_filestat_t), &filestat, trap)); + uvwasi_serdes_write_filestat_t(filestat, 0, &buf); + if (trace_stream) { + trace_stream->Writef("fd_filestat_get -> size=%" PRIu64 " %d\n", buf.st_size, + results[0].i32_); + } + return Result::Ok; + } + + Result fd_fdstat_set_flags(const Values& params, + Values& results, + Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result fd_fdstat_get(const Values& params, Values& results, Trap::Ptr* trap) { + int32_t fd = params[0].i32_; + uint32_t stat_ptr = params[1].i32_; + if (trace_stream) { + trace_stream->Writef("fd_fdstat_get %d\n", fd); + } + CHECK_RESULT(getMemPtr<__wasi_fdstat_t>(stat_ptr, 1, nullptr, trap)); + uvwasi_fdstat_t host_statbuf; + results[0].i32_ = uvwasi_fd_fdstat_get(uvwasi, fd, &host_statbuf); + + // Write the host statbuf into the target wasm memory + __wasi_fdstat_t* statbuf; + CHECK_RESULT(getMemPtr<__wasi_fdstat_t>(stat_ptr, 1, &statbuf, trap)); + uvwasi_serdes_write_fdstat_t(statbuf, 0, &host_statbuf); + return Result::Ok; + } + + Result fd_read(const Values& params, Values& results, Trap::Ptr* trap) { + int32_t fd = params[0].i32_; + int32_t iovptr = params[1].i32_; + int32_t iovcnt = params[2].i32_; + int32_t out_ptr = params[2].i32_; + if (trace_stream) { + trace_stream->Writef("fd_read %d [%d]\n", fd, iovcnt); + } + __wasi_iovec_t* wasm_iovs; + CHECK_RESULT(getMemPtr<__wasi_iovec_t>(iovptr, iovcnt, &wasm_iovs, trap)); + std::vector iovs(iovcnt); + for (int i = 0; i < iovcnt; i++) { + iovs[i].buf_len = wasm_iovs[i].buf_len; + + CHECK_RESULT(getMemPtr(wasm_iovs[i].buf, wasm_iovs[i].buf_len, + reinterpret_cast(&iovs[i].buf), + trap)); + } + __wasi_ptr_t* out_addr; + CHECK_RESULT(getMemPtr<__wasi_ptr_t>(out_ptr, 1, &out_addr, trap)); + results[0].i32_ = + uvwasi_fd_read(uvwasi, fd, iovs.data(), iovs.size(), out_addr); + if (trace_stream) { + trace_stream->Writef("fd_read -> %d\n", results[0].i32_); + } + return Result::Ok; + } + + Result fd_pread(const Values& params, Values& results, Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result fd_readdir(const Values& params, Values& results, Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result fd_write(const Values& params, Values& results, Trap::Ptr* trap) { + int32_t fd = params[0].i32_; + int32_t iovptr = params[1].i32_; + int32_t iovcnt = params[2].i32_; + __wasi_iovec_t* wasm_iovs; + CHECK_RESULT(getMemPtr<__wasi_iovec_t>(iovptr, iovcnt, &wasm_iovs, trap)); + std::vector iovs(iovcnt); + for (int i = 0; i < iovcnt; i++) { + iovs[i].buf_len = wasm_iovs[i].buf_len; + CHECK_RESULT(getMemPtr( + wasm_iovs[i].buf, wasm_iovs[i].buf_len, + reinterpret_cast(&iovs[i].buf), trap)); + } + __wasi_ptr_t* out_addr; + CHECK_RESULT(getMemPtr<__wasi_ptr_t>(params[3].i32_, 1, &out_addr, trap)); + results[0].i32_ = + uvwasi_fd_write(uvwasi, fd, iovs.data(), iovs.size(), out_addr); + return Result::Ok; + } + + Result fd_pwrite(const Values& params, Values& results, Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result fd_close(const Values& params, Values& results, Trap::Ptr* trap) { + assert(false); + return Result::Ok; + } + + Result fd_seek(const Values& params, Values& results, Trap::Ptr* trap) { + /* __wasi_errno_t __wasi_fd_seek(__wasi_fd_t fd, + * __wasi_filedelta_t offset, + * __wasi_whence_t whence, + * __wasi_filesize_t *newoffset) + */ + int32_t fd = params[0].i32_; + __wasi_filedelta_t offset = params[1].i32_; + __wasi_whence_t whence = params[2].i32_; + uint32_t newoffset_ptr = params[3].i32_; + uvwasi_filesize_t newoffset; + results[0].i32_ = uvwasi_fd_seek(uvwasi, fd, offset, whence, &newoffset); + CHECK_RESULT(writeValue<__wasi_filesize_t>(newoffset, newoffset_ptr, trap)); + return Result::Ok; + } + + Result environ_get(const Values& params, Values& results, Trap::Ptr* trap) { + uvwasi_size_t environc; + uvwasi_size_t environ_buf_size; + uvwasi_environ_sizes_get(uvwasi, &environc, &environ_buf_size); + uint32_t wasm_buf = params[1].i32_; + char* buf; + CHECK_RESULT(getMemPtr(wasm_buf, environ_buf_size, &buf, trap)); + std::vector host_env(environc); + uvwasi_environ_get(uvwasi, host_env.data(), buf); + + // Copy host_env pointer array wasm_env) + for (uvwasi_size_t i = 0; i < environc; i++) { + uint32_t rel_address = host_env[i] - buf; + uint32_t dest = params[0].i32_ + (i * sizeof(uint32_t)); + CHECK_RESULT(writeValue(wasm_buf + rel_address, dest, trap)); + } + + results[0].i32_ = __WASI_ERRNO_SUCCESS; + return Result::Ok; + } + + Result environ_sizes_get(const Values& params, + Values& results, + Trap::Ptr* trap) { + uvwasi_size_t environc; + uvwasi_size_t environ_buf_size; + uvwasi_environ_sizes_get(uvwasi, &environc, &environ_buf_size); + CHECK_RESULT(writeValue(environc, params[0].i32_, trap)); + CHECK_RESULT(writeValue(environ_buf_size, params[1].i32_, trap)); + if (trace_stream) { + trace_stream->Writef("environ_sizes_get -> %d %d\n", environc, + environ_buf_size); + } + results[0].i32_ = __WASI_ERRNO_SUCCESS; + return Result::Ok; + } + + Result args_get(const Values& params, Values& results, Trap::Ptr* trap) { + uvwasi_size_t argc; + uvwasi_size_t arg_buf_size; + uvwasi_args_sizes_get(uvwasi, &argc, &arg_buf_size); + uint32_t wasm_buf = params[1].i32_; + char* buf; + CHECK_RESULT(getMemPtr(wasm_buf, arg_buf_size, &buf, trap)); + std::vector host_args(argc); + uvwasi_args_get(uvwasi, host_args.data(), buf); + + // Copy host_args pointer array wasm_args) + for (uvwasi_size_t i = 0; i < argc; i++) { + uint32_t rel_address = host_args[i] - buf; + uint32_t dest = params[0].i32_ + (i * sizeof(uint32_t)); + CHECK_RESULT(writeValue(wasm_buf + rel_address, dest, trap)); + } + results[0].i32_ = __WASI_ERRNO_SUCCESS; + return Result::Ok; + } + + Result args_sizes_get(const Values& params, + Values& results, + Trap::Ptr* trap) { + uvwasi_size_t argc; + uvwasi_size_t arg_buf_size; + uvwasi_args_sizes_get(uvwasi, &argc, &arg_buf_size); + CHECK_RESULT(writeValue(argc, params[0].i32_, trap)); + CHECK_RESULT(writeValue(arg_buf_size, params[1].i32_, trap)); + if (trace_stream) { + trace_stream->Writef("args_sizes_get -> %d %d\n", argc, arg_buf_size); + } + results[0].i32_ = __WASI_ERRNO_SUCCESS; + return Result::Ok; + } + + // The trace stream accosiated with the instance. + Stream* trace_stream; + + Instance::Ptr instance; + + private: + // Write a value into wasm-memory and the given memory offset. + template + Result writeValue(T value, uint32_t target_address, Trap::Ptr* trap) { + T* abs_address; + CHECK_RESULT(getMemPtr(target_address, sizeof(T), &abs_address, trap)); + *abs_address = value; + return Result::Ok; + } + + // Result a wasm-memory-local address to an absolute memory location. + template + Result getMemPtr(uint32_t address, + uint32_t num_elems, + T** result, + Trap::Ptr* trap) { + if (!memory->IsValidAccess(address, 0, num_elems * sizeof(T))) { + *trap = + Trap::New(*instance.store(), + StringPrintf("out of bounds memory access: " + "[%u, %" PRIu64 ") >= max value %u", + address, u64{address} + num_elems * sizeof(T), + memory->ByteSize())); + return Result::Error; + } + if (result) { + *result = reinterpret_cast(memory->UnsafeData() + address); + } + return Result::Ok; + } + + uvwasi_s* uvwasi; + // The memory accociated with the instance. Looked up once on startup + // and cached here. + Memory* memory; +}; + +std::unordered_map wasiInstances; + +// TODO(sbc): Auto-generate this. + +#define WASI_CALLBACK(NAME) \ + static Result NAME(Thread& thread, const Values& params, Values& results, \ + Trap::Ptr* trap) { \ + Instance* instance = thread.GetCallerInstance(); \ + assert(instance); \ + WasiInstance* wasi_instance = wasiInstances[instance]; \ + if (wasi_instance->trace_stream) { \ + wasi_instance->trace_stream->Writef( \ + ">>> running wasi function \"%s\":\n", #NAME); \ + } \ + return wasi_instance->NAME(params, results, trap); \ + } + +#define WASI_FUNC(NAME) WASI_CALLBACK(NAME) +#include "wasi_api.def" +#undef WASI_FUNC + +} // namespace + +namespace wabt { +namespace interp { + +Result WasiBindImports(const Module::Ptr& module, + RefVec& imports, + Stream* stream, + Stream* trace_stream) { + Store* store = module.store(); + for (auto&& import : module->desc().imports) { + if (import.type.type->kind != ExternKind::Func) { + stream->Writef("wasi error: invalid import type: %s\n", + import.type.name.c_str()); + return Result::Error; + } + + if (import.type.module != "wasi_snapshot_preview1" && + import.type.module != "wasi_unstable") { + stream->Writef("wasi error: unknown module import: `%s`\n", + import.type.module.c_str()); + return Result::Error; + } + + auto func_type = *cast(import.type.type.get()); + auto import_name = StringPrintf("%s.%s", import.type.module.c_str(), + import.type.name.c_str()); + HostFunc::Ptr host_func; + + // TODO(sbc): Validate signatures of imports. +#define WASI_FUNC(NAME) \ + if (import.type.name == #NAME) { \ + host_func = HostFunc::New(*store, func_type, NAME); \ + goto found; \ + } +#include "wasi_api.def" +#undef WASI_FUNC + + stream->Writef("unknown wasi API import: `%s`\n", import.type.name.c_str()); + return Result::Error; + found: + imports.push_back(host_func.ref()); + } + + return Result::Ok; +} + +Result WasiRunStart(const Instance::Ptr& instance, + uvwasi_s* uvwasi, + Stream* err_stream, + Stream* trace_stream) { + Store* store = instance.store(); + auto module = store->UnsafeGet(instance->module()); + auto&& module_desc = module->desc(); + + Func::Ptr start; + Memory::Ptr memory; + for (auto&& export_ : module_desc.exports) { + if (export_.type.name == "memory") { + if (export_.type.type->kind != ExternalKind::Memory) { + err_stream->Writef("wasi error: memory export has incorrect type\n"); + return Result::Error; + } + memory = store->UnsafeGet(instance->memories()[export_.index]); + } + if (export_.type.name == "_start") { + if (export_.type.type->kind != ExternalKind::Func) { + err_stream->Writef("wasi error: _start export is not a function\n"); + return Result::Error; + } + start = store->UnsafeGet(instance->funcs()[export_.index]); + } + if (start && memory) { + break; + } + } + + if (!start) { + err_stream->Writef("wasi error: _start export not found\n"); + return Result::Error; + } + + if (!memory) { + err_stream->Writef("wasi error: memory export not found\n"); + return Result::Error; + } + + if (start->type().params.size() || start->type().results.size()) { + err_stream->Writef("wasi error: invalid _start signature\n"); + return Result::Error; + } + + // Register memory + WasiInstance wasi(instance, uvwasi, memory.get(), trace_stream); + wasiInstances[instance.get()] = &wasi; + + // Call start ([] -> []) + Values params; + Values results; + Trap::Ptr trap; + Result res = start->Call(*store, params, results, &trap, trace_stream); + if (trap) { + WriteTrap(err_stream, "error", trap); + } + + // Unregister memory + wasiInstances.erase(instance.get()); + return res; +} + +} // namespace interp +} // namespace wabt + +#endif diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.h new file mode 100644 index 0000000..465d176 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.h @@ -0,0 +1,46 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_INTERP_WASI_H_ +#define WABT_INTERP_WASI_H_ + +#include "src/common.h" +#include "src/error.h" +#include "src/interp/interp.h" + +#ifdef WITH_WASI + +struct uvwasi_s; + +namespace wabt { +namespace interp { + +Result WasiBindImports(const Module::Ptr& module, + RefVec& imports, + Stream* err_stream, + Stream* trace_stream); + +Result WasiRunStart(const Instance::Ptr& instance, + uvwasi_s* uvwasi, + Stream* stream, + Stream* trace_stream); + +} // namespace interp +} // namespace wabt + +#endif + +#endif /* WABT_INTERP_WASI_H_ */ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasm-c-api.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasm-c-api.cc new file mode 100644 index 0000000..2a0c861 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasm-c-api.cc @@ -0,0 +1,1329 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#include + +#include "src/binary-reader.h" +#include "src/cast.h" +#include "src/error-formatter.h" +#include "src/interp/binary-reader-interp.h" +#include "src/interp/interp-util.h" +#include "src/interp/interp.h" + +using namespace wabt; +using namespace wabt::interp; + +#define own + +#ifndef NDEBUG +#define TRACE0() TRACE("") +#define TRACE(str, ...) \ + fprintf(stderr, "CAPI: [%s] " str "\n", __func__, ##__VA_ARGS__) +#define TRACE_NO_NL(str, ...) \ + fprintf(stderr, "CAPI: [%s] " str, __func__, ##__VA_ARGS__) +#else +#define TRACE0(...) +#define TRACE(...) +#define TRACE_NO_NL(...) +#endif + +static Features s_features; +static std::unique_ptr s_log_stream; +static std::unique_ptr s_stdout_stream; + +// Type conversion utilities +static ValueType ToWabtValueType(wasm_valkind_t); +static wasm_valkind_t FromWabtValueType(ValueType); + +static wasm_externkind_t FromWabtExternKind(ExternKind ); + +static ValueTypes ToWabtValueTypes(const wasm_valtype_vec_t* types); +static void FromWabtValueTypes(const ValueTypes&, wasm_valtype_vec_t* out); + +static wasm_mutability_t FromWabtMutability(Mutability); +static Mutability ToWabtMutability(wasm_mutability_t); + +static Limits ToWabtLimits(const wasm_limits_t&); +static wasm_limits_t FromWabtLimits(const Limits&); + +// Value conversion utilities +static TypedValue ToWabtValue(const wasm_val_t&); +static wasm_val_t FromWabtValue(Store&, const TypedValue&); + +static Values ToWabtValues(const wasm_val_t values[], size_t count); +static void FromWabtValues(Store& store, + wasm_val_t values[], + const ValueTypes& types, + const Values& wabt_values); + +// Structs +struct wasm_config_t {}; + +struct wasm_engine_t {}; + +struct wasm_valtype_t { + ValueType I; +}; + +struct wasm_externtype_t { + static std::unique_ptr New(std::unique_ptr); + + std::unique_ptr Clone() const { + return New(I->Clone()); + } + + virtual ~wasm_externtype_t() {} + + wasm_externtype_t(const wasm_externtype_t& other) = delete; + wasm_externtype_t& operator=(const wasm_externtype_t& other) = delete; + + template + T* As() const { return cast(I.get()); } + + std::unique_ptr I; + + protected: + wasm_externtype_t(std::unique_ptr et) : I(std::move(et)) {} +}; + +struct wasm_functype_t : wasm_externtype_t { + wasm_functype_t(own wasm_valtype_vec_t* params, + own wasm_valtype_vec_t* results) + : wasm_externtype_t{MakeUnique(ToWabtValueTypes(params), + ToWabtValueTypes(results))}, + params(*params), + results(*results) {} + + wasm_functype_t(FuncType ft) : wasm_externtype_t{MakeUnique(ft)} { + FromWabtValueTypes(ft.params, ¶ms); + FromWabtValueTypes(ft.results, &results); + } + + ~wasm_functype_t() { + wasm_valtype_vec_delete(¶ms); + wasm_valtype_vec_delete(&results); + } + + // Stored here because API requires returning pointers. + wasm_valtype_vec_t params; + wasm_valtype_vec_t results; +}; + +struct wasm_globaltype_t : wasm_externtype_t { + wasm_globaltype_t(own wasm_valtype_t* type, wasm_mutability_t mut) + : wasm_externtype_t{MakeUnique(type->I, + ToWabtMutability(mut))}, + valtype{*type} { + wasm_valtype_delete(type); + } + + wasm_globaltype_t(GlobalType gt) + : wasm_externtype_t{MakeUnique(gt)}, valtype{gt.type} {} + + // Stored here because API requires returning pointers. + wasm_valtype_t valtype; +}; + +struct wasm_tabletype_t : wasm_externtype_t { + wasm_tabletype_t(own wasm_valtype_t* type, const wasm_limits_t* limits) + : wasm_externtype_t{MakeUnique(type->I, + ToWabtLimits(*limits))}, + elemtype(*type), + limits(*limits) { + wasm_valtype_delete(type); + } + + wasm_tabletype_t(TableType tt) + : wasm_externtype_t{MakeUnique(tt)}, + elemtype{tt.element}, + limits{FromWabtLimits(tt.limits)} {} + + // Stored here because API requires returning pointers. + wasm_valtype_t elemtype; + wasm_limits_t limits; +}; + +struct wasm_memorytype_t : wasm_externtype_t { + wasm_memorytype_t(const wasm_limits_t* limits) + : wasm_externtype_t{MakeUnique(ToWabtLimits(*limits))}, + limits{*limits} {} + + wasm_memorytype_t(MemoryType mt) + : wasm_externtype_t{MakeUnique(mt)}, + limits{FromWabtLimits(mt.limits)} {} + + // Stored here because API requires returning pointers. + wasm_limits_t limits; +}; + +// static +std::unique_ptr wasm_externtype_t::New( + std::unique_ptr ptr) { + switch (ptr->kind) { + case ExternKind::Func: + return MakeUnique(*cast(ptr.get())); + + case ExternKind::Table: + return MakeUnique(*cast(ptr.get())); + + case ExternKind::Memory: + return MakeUnique(*cast(ptr.get())); + + case ExternKind::Global: + return MakeUnique(*cast(ptr.get())); + + case ExternKind::Event: + break; + } + + assert(false); + return {}; +} + +struct wasm_importtype_t { + wasm_importtype_t(ImportType it) + : I(it), + extern_{wasm_externtype_t::New(it.type->Clone())}, + module{I.module.size(), const_cast(I.module.data())}, + name{I.name.size(), const_cast(I.name.data())} {} + + wasm_importtype_t(const wasm_importtype_t& other) + : wasm_importtype_t(other.I) {} + + wasm_importtype_t& operator=(const wasm_importtype_t& other) { + wasm_importtype_t copy(other); + std::swap(I, copy.I); + std::swap(extern_, copy.extern_); + std::swap(module, copy.module); + std::swap(name, copy.name); + return *this; + } + + ImportType I; + // Stored here because API requires returning pointers. + std::unique_ptr extern_; + wasm_name_t module; + wasm_name_t name; +}; + +struct wasm_exporttype_t { + wasm_exporttype_t(ExportType et) + : I(et), + extern_{wasm_externtype_t::New(et.type->Clone())}, + name{I.name.size(), const_cast(I.name.data())} {} + + wasm_exporttype_t(const wasm_exporttype_t& other) + : wasm_exporttype_t(other.I) {} + + wasm_exporttype_t& operator=(const wasm_exporttype_t& other) { + wasm_exporttype_t copy(other); + std::swap(I, copy.I); + std::swap(extern_, copy.extern_); + std::swap(name, copy.name); + return *this; + } + + ExportType I; + // Stored here because API requires returning pointers. + std::unique_ptr extern_; + wasm_name_t name; +}; + +struct wasm_store_t { + wasm_store_t(const Features& features) : I(features) {} + Store I; +}; + +struct wasm_ref_t { + wasm_ref_t(RefPtr ptr) : I(ptr) {} + + template + T* As() const { return cast(I.get()); } + + RefPtr I; +}; + +struct wasm_frame_t { + Frame I; +}; + +struct wasm_trap_t : wasm_ref_t { + wasm_trap_t(RefPtr ptr) : wasm_ref_t(ptr) {} +}; + +struct wasm_foreign_t : wasm_ref_t { + wasm_foreign_t(RefPtr ptr) : wasm_ref_t(ptr) {} +}; + +struct wasm_module_t : wasm_ref_t { + wasm_module_t(RefPtr ptr, const wasm_byte_vec_t* in) + : wasm_ref_t(ptr) { + wasm_byte_vec_copy(&binary, in); + } + + wasm_module_t(const wasm_module_t& other) : wasm_ref_t(other.I) { + wasm_byte_vec_copy(&binary, &other.binary); + } + + wasm_module_t& operator=(const wasm_module_t& other) { + wasm_module_t copy(other); + std::swap(I, copy.I); + std::swap(binary, copy.binary); + return *this; + } + + ~wasm_module_t() { + wasm_byte_vec_delete(&binary); + } + // TODO: This is used for wasm_module_serialize/wasm_module_deserialize. + // Currently the standard wasm binary bytes are cached here, but it would be + // better to have a serialization of ModuleDesc instead. + wasm_byte_vec_t binary; +}; + +struct wasm_shared_module_t : wasm_module_t {}; + +struct wasm_extern_t : wasm_ref_t { + wasm_extern_t(RefPtr ptr) : wasm_ref_t(ptr) {} +}; + +struct wasm_func_t : wasm_extern_t { + wasm_func_t(RefPtr ptr) : wasm_extern_t(ptr) {} +}; + +struct wasm_global_t : wasm_extern_t { + wasm_global_t(RefPtr ptr) : wasm_extern_t(ptr) {} +}; + +struct wasm_table_t : wasm_extern_t { + wasm_table_t(RefPtr
ptr) : wasm_extern_t(ptr) {} +}; + +struct wasm_memory_t : wasm_extern_t { + wasm_memory_t(RefPtr ptr) : wasm_extern_t(ptr) {} +}; + +struct wasm_instance_t : wasm_ref_t { + wasm_instance_t(RefPtr ptr) : wasm_ref_t(ptr) {} +}; + +// Type conversion utilities +static ValueType ToWabtValueType(wasm_valkind_t kind) { + switch (kind) { + case WASM_I32: + return ValueType::I32; + case WASM_I64: + return ValueType::I64; + case WASM_F32: + return ValueType::F32; + case WASM_F64: + return ValueType::F64; + case WASM_ANYREF: + return ValueType::ExternRef; + case WASM_FUNCREF: + return ValueType::FuncRef; + default: + TRACE("unexpected wasm_valkind_t: %d", kind); + WABT_UNREACHABLE; + } + WABT_UNREACHABLE; +} + +static wasm_valkind_t FromWabtValueType(ValueType type) { + switch (type) { + case ValueType::I32: + return WASM_I32; + case ValueType::I64: + return WASM_I64; + case ValueType::F32: + return WASM_F32; + case ValueType::F64: + return WASM_F64; + case ValueType::ExternRef: + return WASM_ANYREF; + case ValueType::FuncRef: + return WASM_FUNCREF; + default: + WABT_UNREACHABLE; + } +} + +static wasm_externkind_t FromWabtExternKind(ExternKind kind) { + switch (kind) { + case ExternalKind::Func: + return WASM_EXTERN_FUNC; + case ExternalKind::Global: + return WASM_EXTERN_GLOBAL; + case ExternalKind::Table: + return WASM_EXTERN_TABLE; + case ExternalKind::Memory: + return WASM_EXTERN_MEMORY; + case ExternalKind::Event: + WABT_UNREACHABLE; + } + WABT_UNREACHABLE; +} + +static ValueTypes ToWabtValueTypes(const wasm_valtype_vec_t* types) { + ValueTypes result; + for (size_t i = 0; i < types->size; ++i) { + result.push_back(types->data[i]->I); + } + return result; +} + +static void FromWabtValueTypes(const ValueTypes& types, + wasm_valtype_vec_t* out) { + wasm_valtype_vec_new_uninitialized(out, types.size()); + for (size_t i = 0; i < types.size(); ++i) { + out->data[i] = wasm_valtype_new(FromWabtValueType(types[i])); + } +} + +static wasm_mutability_t FromWabtMutability(Mutability mut) { + return mut == Mutability::Var ? WASM_VAR : WASM_CONST; +} + +static Mutability ToWabtMutability(wasm_mutability_t mut) { + return mut == WASM_VAR ? Mutability::Var : Mutability::Const; +} + +// Value conversion utilities + +static TypedValue ToWabtValue(const wasm_val_t& value) { + TypedValue out; + out.type = ToWabtValueType(value.kind); + switch (value.kind) { + case WASM_I32: + out.value.Set(value.of.i32); + break; + case WASM_I64: + out.value.Set(value.of.i64); + break; + case WASM_F32: + out.value.Set(value.of.f32); + break; + case WASM_F64: + out.value.Set(value.of.f64); + break; + case WASM_ANYREF: + case WASM_FUNCREF: + out.value.Set(value.of.ref ? value.of.ref->I->self() : Ref::Null); + break; + default: + TRACE("unexpected wasm type: %d", value.kind); + assert(false); + } + TRACE("-> %s", TypedValueToString(out).c_str()); + return out; +} + +static wasm_val_t FromWabtValue(Store& store, const TypedValue& tv) { + TRACE("%s", TypedValueToString(tv).c_str()); + wasm_val_t out_value; + switch (tv.type) { + case Type::I32: + out_value.kind = WASM_I32; + out_value.of.i32 = tv.value.Get(); + break; + case Type::I64: + out_value.kind = WASM_I64; + out_value.of.i64 = tv.value.Get(); + break; + case Type::F32: + out_value.kind = WASM_F32; + out_value.of.f32 = tv.value.Get(); + break; + case Type::F64: + out_value.kind = WASM_F64; + out_value.of.f64 = tv.value.Get(); + break; + case Type::FuncRef: { + Ref ref = tv.value.Get(); + out_value.kind = WASM_FUNCREF; + out_value.of.ref = new wasm_func_t(store.UnsafeGet(ref)); + break; + } + case Type::ExternRef: { + Ref ref = tv.value.Get(); + out_value.kind = WASM_ANYREF; + out_value.of.ref = new wasm_foreign_t(store.UnsafeGet(ref)); + break; + } + default: + TRACE("unexpected wabt type: %d", static_cast(tv.type)); + assert(false); + } + return out_value; +} + +static Limits ToWabtLimits(const wasm_limits_t& limits) { + return Limits(limits.min, limits.max); +} + +static wasm_limits_t FromWabtLimits(const Limits& limits) { + return wasm_limits_t{(uint32_t)limits.initial, (uint32_t)limits.max}; +} + +static Values ToWabtValues(const wasm_val_t values[], size_t count) { + Values result; + for (size_t i = 0; i < count; ++i) { + result.push_back(ToWabtValue(values[i]).value); + } + return result; +} + +static void FromWabtValues(Store& store, + wasm_val_t values[], + const ValueTypes& types, + const Values& wabt_values) { + assert(types.size() == wabt_values.size()); + for (size_t i = 0; i < types.size(); ++i) { + values[i] = FromWabtValue(store, TypedValue{types[i], wabt_values[i]}); + } +} + +static std::string ToString(const wasm_message_t* msg) { + return std::string(msg->data, msg->size); +} + +static wasm_message_t FromString(const std::string& s) { + wasm_message_t result; + wasm_byte_vec_new(&result, s.size() + 1, s.c_str()); + return result; +} + +static ReadBinaryOptions GetOptions() { + const bool kReadDebugNames = true; + const bool kStopOnFirstError = true; + const bool kFailOnCustomSectionError = true; + s_features.EnableAll(); + if (getenv("WASM_API_DEBUG") != nullptr) { + s_log_stream = FileStream::CreateStderr(); + } + return ReadBinaryOptions(s_features, s_log_stream.get(), kReadDebugNames, + kStopOnFirstError, kFailOnCustomSectionError); +} + +extern "C" { + +// wasm_valtype + +own wasm_valtype_t* wasm_valtype_new(wasm_valkind_t kind) { + return new wasm_valtype_t{ToWabtValueType(kind)}; +} + +wasm_valkind_t wasm_valtype_kind(const wasm_valtype_t* type) { + assert(type); + return FromWabtValueType(type->I); +} + +// Helpers + +static void print_sig(const FuncType& sig) { +#ifndef NDEBUG + fprintf(stderr, "("); + bool first = true; + for (auto Type : sig.params) { + if (!first) { + fprintf(stderr, ", "); + } + first = false; + fprintf(stderr, "%s", Type.GetName()); + } + fprintf(stderr, ") -> ("); + first = true; + for (auto Type : sig.results) { + if (!first) { + fprintf(stderr, ", "); + } + first = false; + fprintf(stderr, "%s", Type.GetName()); + } + fprintf(stderr, ")\n"); +#endif +} + +// wasm_val + +void wasm_val_delete(own wasm_val_t* val) { + assert(val); + if (wasm_valkind_is_ref(val->kind)) { + delete val->of.ref; + val->of.ref = nullptr; + } +} + +void wasm_val_copy(own wasm_val_t* out, const wasm_val_t* in) { + TRACE("%s", TypedValueToString(ToWabtValue(*in)).c_str()); + if (wasm_valkind_is_ref(in->kind)) { + out->kind = in->kind; + out->of.ref = in->of.ref ? new wasm_ref_t{*in->of.ref} : nullptr; + } else { + *out = *in; + } + TRACE("-> %p %s", out, TypedValueToString(ToWabtValue(*out)).c_str()); +} + +// wasm_trap + +own wasm_trap_t* wasm_trap_new(wasm_store_t* store, const wasm_message_t* msg) { + return new wasm_trap_t{Trap::New(store->I, ToString(msg))}; +} + +void wasm_trap_message(const wasm_trap_t* trap, own wasm_message_t* out) { + assert(trap); + *out = FromString(trap->As()->message()); +} + +own wasm_frame_t* wasm_trap_origin(const wasm_trap_t* trap) { + // TODO(sbc): Implement stack traces + return nullptr; +} + +void wasm_trap_trace(const wasm_trap_t* trap, own wasm_frame_vec_t* out) { + assert(trap); + assert(out); + wasm_frame_vec_new_empty(out); + // std::string msg(trap->message.data, trap->message.size); + // TRACE(stderr, "error: %s\n", msg.c_str()); +} + +// wasm_config + +own wasm_config_t* wasm_config_new() { + return new wasm_config_t(); +} + +// wasm_engine + +own wasm_engine_t* wasm_engine_new() { + return new wasm_engine_t(); +} + +own wasm_engine_t* wasm_engine_new_with_config(own wasm_config_t*) { + assert(false); + return nullptr; +} + +// wasm_store + +own wasm_store_t* wasm_store_new(wasm_engine_t* engine) { + assert(engine); + return new wasm_store_t(s_features); +} + +void wasm_store_gc(wasm_store_t* store) { + assert(store); + store->I.Collect(); +} + +// wasm_module + +own wasm_module_t* wasm_module_new(wasm_store_t* store, + const wasm_byte_vec_t* binary) { + Errors errors; + ModuleDesc module_desc; + if (Failed(ReadBinaryInterp(binary->data, binary->size, GetOptions(), &errors, + &module_desc))) { + FormatErrorsToFile(errors, Location::Type::Binary); + return nullptr; + } + + return new wasm_module_t{Module::New(store->I, module_desc), binary}; +} + +bool wasm_module_validate(wasm_store_t* store, const wasm_byte_vec_t* binary) { + // TODO: Optimize this; for now it is generating a new module and discarding + // it. But since this call only needs to validate, it could do much less. + wasm_module_t* module = wasm_module_new(store, binary); + if (module == nullptr) { + return false; + } + wasm_module_delete(module); + return true; +} + +void wasm_module_imports(const wasm_module_t* module, + own wasm_importtype_vec_t* out) { + auto&& import_types = module->As()->import_types(); + TRACE("%" PRIzx, import_types.size()); + wasm_importtype_vec_new_uninitialized(out, import_types.size()); + + for (size_t i = 0; i < import_types.size(); ++i) { + out->data[i] = new wasm_importtype_t{import_types[i]}; + } +} + +void wasm_module_exports(const wasm_module_t* module, + own wasm_exporttype_vec_t* out) { + auto&& export_types = module->As()->export_types(); + TRACE("%" PRIzx, export_types.size()); + wasm_exporttype_vec_new_uninitialized(out, export_types.size()); + + for (size_t i = 0; i < export_types.size(); ++i) { + out->data[i] = new wasm_exporttype_t{export_types[i]}; + } +} + +void wasm_module_serialize(const wasm_module_t* module, + own wasm_byte_vec_t* out) { + wasm_byte_vec_copy(out, &module->binary); +} + +own wasm_module_t* wasm_module_deserialize(wasm_store_t* store, + const wasm_byte_vec_t* bytes) { + return wasm_module_new(store, bytes); +} + +// wasm_importtype + +own wasm_importtype_t* wasm_importtype_new(own wasm_name_t* module, + own wasm_name_t* name, + own wasm_externtype_t* type) { + return new wasm_importtype_t{ + ImportType{ToString(module), ToString(name), type->I->Clone()}}; +} + +const wasm_name_t* wasm_importtype_module(const wasm_importtype_t* im) { + return &im->module; +} + +const wasm_name_t* wasm_importtype_name(const wasm_importtype_t* im) { + return &im->name; +} + +const wasm_externtype_t* wasm_importtype_type(const wasm_importtype_t* im) { + return im->extern_.get(); +} + +// wasm_exporttype + +own wasm_exporttype_t* wasm_exporttype_new(own wasm_name_t* name, + wasm_externtype_t* type) { + return new wasm_exporttype_t{ExportType{ToString(name), type->I->Clone()}}; +} + +const wasm_name_t* wasm_exporttype_name(const wasm_exporttype_t* ex) { + return &ex->name; +} + +const wasm_externtype_t* wasm_exporttype_type(const wasm_exporttype_t* ex) { + TRACE("%p", ex); + assert(ex); + return ex->extern_.get(); +} + +// wasm_instance + +own wasm_instance_t* wasm_instance_new(wasm_store_t* store, + const wasm_module_t* module, + const wasm_extern_t* const imports[], + own wasm_trap_t** trap_out) { + TRACE("%p %p", store, module); + assert(module); + assert(store); + + RefVec import_refs; + for (size_t i = 0; i < module->As()->import_types().size(); i++) { + import_refs.push_back(imports[i]->I->self()); + } + + Trap::Ptr trap; + auto instance = + Instance::Instantiate(store->I, module->I->self(), import_refs, &trap); + if (trap) { + *trap_out = new wasm_trap_t{trap}; + return nullptr; + } + + return new wasm_instance_t{instance}; +} + +void wasm_instance_exports(const wasm_instance_t* instance, + own wasm_extern_vec_t* out) { + auto&& exports = instance->As()->exports(); + wasm_extern_vec_new_uninitialized(out, exports.size()); + TRACE("%" PRIzx, exports.size()); + + for (size_t i = 0; i < exports.size(); ++i) { + out->data[i] = + new wasm_extern_t{instance->I.store()->UnsafeGet(exports[i])}; + } +} + +uint32_t wasm_instance_func_index(const wasm_instance_t* instance, + const wasm_func_t* func) { + auto&& funcs = instance->As()->funcs(); + + assert(func.size() < wasm_limits_max_default); + for (size_t i = 0; i < funcs.size(); ++i) { + if (funcs[i] == func->I.ref()) { + return i; + } + } + + return wasm_limits_max_default; +} + +// wasm_functype + +own wasm_functype_t* wasm_functype_new(own wasm_valtype_vec_t* params, + own wasm_valtype_vec_t* results) { + TRACE("params=%" PRIzx " args=%" PRIzx, params->size, results->size); + auto* res = new wasm_functype_t{params, results}; + TRACE_NO_NL(""); + print_sig(*res->As()); + return res; +} + +const wasm_valtype_vec_t* wasm_functype_params(const wasm_functype_t* f) { + TRACE("%" PRIzx, f->params.size); + return &f->params; +} + +const wasm_valtype_vec_t* wasm_functype_results(const wasm_functype_t* f) { + return &f->results; +} + +// wasm_func +own wasm_func_t* wasm_func_new(wasm_store_t* store, + const wasm_functype_t* type, + wasm_func_callback_t callback) { + FuncType wabt_type = *type->As(); + auto lambda = [=](Thread& thread, const Values& wabt_params, + Values& wabt_results, Trap::Ptr* out_trap) -> Result { + wasm_val_vec_t params, results; + wasm_val_vec_new_uninitialized(¶ms, wabt_params.size()); + wasm_val_vec_new_uninitialized(&results, wabt_results.size()); + FromWabtValues(store->I, params.data, wabt_type.params, wabt_params); + auto trap = callback(params.data, results.data); + wasm_val_vec_delete(¶ms); + if (trap) { + *out_trap = trap->I.As(); + wasm_trap_delete(trap); + // Can't use wasm_val_vec_delete since it wasn't populated. + delete[] results.data; + return Result::Error; + } + wabt_results = ToWabtValues(results.data, results.size); + wasm_val_vec_delete(&results); + return Result::Ok; + }; + + return new wasm_func_t{HostFunc::New(store->I, wabt_type, lambda)}; +} + +own wasm_func_t* wasm_func_new_with_env(wasm_store_t* store, + const wasm_functype_t* type, + wasm_func_callback_with_env_t callback, + void* env, + void (*finalizer)(void*)) { + FuncType wabt_type = *type->As(); + auto lambda = [=](Thread& thread, const Values& wabt_params, + Values& wabt_results, Trap::Ptr* out_trap) -> Result { + wasm_val_vec_t params, results; + wasm_val_vec_new_uninitialized(¶ms, wabt_params.size()); + wasm_val_vec_new_uninitialized(&results, wabt_results.size()); + FromWabtValues(store->I, params.data, wabt_type.params, wabt_params); + auto trap = callback(env, params.data, results.data); + wasm_val_vec_delete(¶ms); + if (trap) { + *out_trap = trap->I.As(); + wasm_trap_delete(trap); + // Can't use wasm_val_vec_delete since it wasn't populated. + delete[] results.data; + return Result::Error; + } + wabt_results = ToWabtValues(results.data, results.size); + wasm_val_vec_delete(&results); + return Result::Ok; + }; + + // TODO: This finalizer is different from the host_info finalizer. + return new wasm_func_t{HostFunc::New(store->I, wabt_type, lambda)}; +} + +own wasm_functype_t* wasm_func_type(const wasm_func_t* func) { + TRACE0(); + return new wasm_functype_t{func->As()->type()}; +} + +size_t wasm_func_result_arity(const wasm_func_t* func) { + return func->As()->type().results.size(); +} + +size_t wasm_func_param_arity(const wasm_func_t* func) { + return func->As()->type().params.size(); +} + +own wasm_trap_t* wasm_func_call(const wasm_func_t* f, + const wasm_val_t args[], + wasm_val_t results[]) { + // TODO: get some information about the function; name/index + // TRACE("%d", f->index); + + auto&& func_type = f->As()->type(); + Values wabt_args = ToWabtValues(args, func_type.params.size()); + Values wabt_results; + Trap::Ptr trap; + if (Failed( + f->As()->Call(*f->I.store(), wabt_args, wabt_results, &trap))) { + return new wasm_trap_t{trap}; + } + FromWabtValues(*f->I.store(), results, func_type.results, wabt_results); + return nullptr; +} + +// wasm_globaltype + +own wasm_globaltype_t* wasm_globaltype_new(own wasm_valtype_t* type, + wasm_mutability_t mut) { + assert(type); + auto* result = new wasm_globaltype_t{GlobalType{ + type->I, mut == WASM_CONST ? Mutability::Const : Mutability::Var}}; + wasm_valtype_delete(type); + return result; +} + +wasm_mutability_t wasm_globaltype_mutability(const wasm_globaltype_t* type) { + assert(type); + return FromWabtMutability(type->As()->mut); +} + +const wasm_valtype_t* wasm_globaltype_content(const wasm_globaltype_t* type) { + assert(type); + return &type->valtype; +} + +// wasm_tabletype + +own wasm_tabletype_t* wasm_tabletype_new(own wasm_valtype_t* type, + const wasm_limits_t* limits) { + return new wasm_tabletype_t{type, limits}; +} + +const wasm_valtype_t* wasm_tabletype_element(const wasm_tabletype_t* type) { + return &type->elemtype; +} + +const wasm_limits_t* wasm_tabletype_limits(const wasm_tabletype_t* type) { + return &type->limits; +} + +// wasm_memorytype + +own wasm_memorytype_t* wasm_memorytype_new(const wasm_limits_t* limits) { + return new wasm_memorytype_t(limits); +} + +const wasm_limits_t* wasm_memorytype_limits(const wasm_memorytype_t* t) { + return &t->limits; +} + +// wasm_global + +own wasm_global_t* wasm_global_new(wasm_store_t* store, + const wasm_globaltype_t* type, + const wasm_val_t* val) { + assert(store && type); + TypedValue value = ToWabtValue(*val); + TRACE("%s", TypedValueToString(value).c_str()); + return new wasm_global_t{ + Global::New(store->I, *type->As(), value.value)}; +} + +own wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) { + return new wasm_globaltype_t{global->As()->type()}; +} + +void wasm_global_get(const wasm_global_t* global, own wasm_val_t* out) { + assert(global); + TRACE0(); + TypedValue tv{global->As()->type().type, global->As()->Get()}; + TRACE(" -> %s", TypedValueToString(tv).c_str()); + *out = FromWabtValue(*global->I.store(), tv); +} + +void wasm_global_set(wasm_global_t* global, const wasm_val_t* val) { + TRACE0(); + if (wasm_valkind_is_ref(val->kind)) { + global->As()->Set(*global->I.store(), val->of.ref->I->self()); + } else { + global->As()->UnsafeSet(ToWabtValue(*val).value); + } +} + +// wasm_table + +own wasm_table_t* wasm_table_new(wasm_store_t* store, + const wasm_tabletype_t* type, + wasm_ref_t* init) { + return new wasm_table_t{Table::New(store->I, *type->As())}; +} + +own wasm_tabletype_t* wasm_table_type(const wasm_table_t* table) { + return new wasm_tabletype_t{table->As
()->type()}; +} + +wasm_table_size_t wasm_table_size(const wasm_table_t* table) { + return table->As
()->size(); +} + +own wasm_ref_t* wasm_table_get(const wasm_table_t* table, + wasm_table_size_t index) { + Ref ref; + if (Failed(table->As
()->Get(index, &ref))) { + return nullptr; + } + if (ref == Ref::Null) { + return nullptr; + } + return new wasm_ref_t{table->I.store()->UnsafeGet(ref)}; +} + +bool wasm_table_set(wasm_table_t* table, + wasm_table_size_t index, + wasm_ref_t* ref) { + return Succeeded(table->As
()->Set(*table->I.store(), index, + ref ? ref->I->self() : Ref::Null)); +} + +bool wasm_table_grow(wasm_table_t* table, + wasm_table_size_t delta, + wasm_ref_t* init) { + return Succeeded(table->As
()->Grow( + *table->I.store(), delta, init ? init->I->self() : Ref::Null)); +} + +// wams_memory + +own wasm_memory_t* wasm_memory_new(wasm_store_t* store, + const wasm_memorytype_t* type) { + TRACE0(); + return new wasm_memory_t{Memory::New(store->I, *type->As())}; +} + +own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t* memory) { + return new wasm_memorytype_t{memory->As()->type()}; +} + +byte_t* wasm_memory_data(wasm_memory_t* memory) { + return reinterpret_cast(memory->As()->UnsafeData()); +} + +wasm_memory_pages_t wasm_memory_size(const wasm_memory_t* memory) { + return memory->As()->PageSize(); +} + +size_t wasm_memory_data_size(const wasm_memory_t* memory) { + return memory->As()->ByteSize(); +} + +bool wasm_memory_grow(wasm_memory_t* memory, wasm_memory_pages_t delta) { + return Succeeded(memory->As()->Grow(delta)); +} + +// wasm_frame + +own wasm_frame_t* wasm_frame_copy(const wasm_frame_t* frame) { + return new wasm_frame_t{*frame}; +} + +wasm_instance_t* wasm_frame_instance(const wasm_frame_t* frame) { + // TODO + return nullptr; +} + +size_t wasm_frame_module_offset(const wasm_frame_t* frame) { + // TODO + return 0; +} + +size_t wasm_frame_func_offset(const wasm_frame_t* frame) { + // TODO + return 0; +} + +uint32_t wasm_frame_func_index(const wasm_frame_t* frame) { + // TODO + return 0; +} + +// wasm_externtype + +wasm_externkind_t wasm_externtype_kind(const wasm_externtype_t* type) { + assert(type); + return FromWabtExternKind(type->I->kind); +} + +// wasm_extern + +own wasm_externtype_t* wasm_extern_type(const wasm_extern_t* extern_) { + return wasm_externtype_t::New(extern_->As()->extern_type().Clone()) + .release(); +} + +wasm_externkind_t wasm_extern_kind(const wasm_extern_t* extern_) { + return FromWabtExternKind(extern_->As()->extern_type().kind); +} + +// wasm_foreign + +own wasm_foreign_t* wasm_foreign_new(wasm_store_t* store) { + return new wasm_foreign_t{Foreign::New(store->I, nullptr)}; +} + +// vector types + +#define WASM_IMPL_OWN(name) \ + void wasm_##name##_delete(own wasm_##name##_t* t) { \ + assert(t); \ + TRACE0(); \ + delete t; \ + } + +WASM_IMPL_OWN(frame); +WASM_IMPL_OWN(config); +WASM_IMPL_OWN(engine); +WASM_IMPL_OWN(store); + +#define WASM_IMPL_VEC_BASE(name, ptr_or_none) \ + void wasm_##name##_vec_new_empty(own wasm_##name##_vec_t* out) { \ + TRACE0(); \ + wasm_##name##_vec_new_uninitialized(out, 0); \ + } \ + void wasm_##name##_vec_new_uninitialized(own wasm_##name##_vec_t* vec, \ + size_t size) { \ + TRACE("%" PRIzx, size); \ + vec->size = size; \ + vec->data = size ? new wasm_##name##_t ptr_or_none[size] : nullptr; \ + } + +#define WASM_IMPL_VEC_PLAIN(name) \ + WASM_IMPL_VEC_BASE(name, ) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t* vec, size_t size, \ + own wasm_##name##_t const src[]) { \ + TRACE0(); \ + wasm_##name##_vec_new_uninitialized(vec, size); \ + memcpy(vec->data, src, size * sizeof(wasm_##name##_t)); \ + } \ + void wasm_##name##_vec_copy(own wasm_##name##_vec_t* out, \ + const wasm_##name##_vec_t* vec) { \ + TRACE("%" PRIzx, vec->size); \ + wasm_##name##_vec_new_uninitialized(out, vec->size); \ + memcpy(out->data, vec->data, vec->size * sizeof(wasm_##name##_t)); \ + } \ + void wasm_##name##_vec_delete(own wasm_##name##_vec_t* vec) { \ + TRACE0(); \ + delete[] vec->data; \ + vec->size = 0; \ + } + +WASM_IMPL_VEC_PLAIN(byte); + +// Special implementation for wasm_val_t, since it's weird. +WASM_IMPL_VEC_BASE(val, ) +void wasm_val_vec_new(own wasm_val_vec_t* vec, + size_t size, + own wasm_val_t const src[]) { + TRACE0(); + wasm_val_vec_new_uninitialized(vec, size); + for (size_t i = 0; i < size; ++i) { + vec->data[i] = src[i]; + } +} + +void wasm_val_vec_copy(own wasm_val_vec_t* out, const wasm_val_vec_t* vec) { + TRACE("%" PRIzx, vec->size); + wasm_val_vec_new_uninitialized(out, vec->size); + for (size_t i = 0; i < vec->size; ++i) { + wasm_val_copy(&out->data[i], &vec->data[i]); + } +} + +void wasm_val_vec_delete(own wasm_val_vec_t* vec) { + TRACE0(); + for (size_t i = 0; i < vec->size; ++i) { + wasm_val_delete(&vec->data[i]); + } + delete[] vec->data; + vec->size = 0; +} + +#define WASM_IMPL_VEC_OWN(name) \ + WASM_IMPL_VEC_BASE(name, *) \ + void wasm_##name##_vec_new(own wasm_##name##_vec_t* vec, size_t size, \ + own wasm_##name##_t* const src[]) { \ + TRACE0(); \ + wasm_##name##_vec_new_uninitialized(vec, size); \ + for (size_t i = 0; i < size; ++i) { \ + vec->data[i] = src[i]; \ + } \ + } \ + void wasm_##name##_vec_copy(own wasm_##name##_vec_t* out, \ + const wasm_##name##_vec_t* vec) { \ + TRACE("%" PRIzx, vec->size); \ + wasm_##name##_vec_new_uninitialized(out, vec->size); \ + for (size_t i = 0; i < vec->size; ++i) { \ + out->data[i] = wasm_##name##_copy(vec->data[i]); \ + } \ + } \ + void wasm_##name##_vec_delete(wasm_##name##_vec_t* vec) { \ + TRACE0(); \ + for (size_t i = 0; i < vec->size; ++i) { \ + delete vec->data[i]; \ + } \ + delete[] vec->data; \ + vec->size = 0; \ + } \ + void wasm_##name##_vec_delete_with_size(wasm_##name##_vec_t* vec, \ + size_t size) { \ + assert(size <= vec->size); \ + TRACE0(); \ + for (size_t i = 0; i < size; ++i) { \ + delete vec->data[i]; \ + } \ + delete[] vec->data; \ + vec->size = 0; \ + } + +WASM_IMPL_VEC_OWN(frame); +WASM_IMPL_VEC_OWN(extern); + +#define WASM_IMPL_TYPE(name) \ + WASM_IMPL_OWN(name) \ + WASM_IMPL_VEC_OWN(name) \ + own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* other) { \ + TRACE0(); \ + return new wasm_##name##_t(*other); \ + } + +WASM_IMPL_TYPE(valtype); +WASM_IMPL_TYPE(importtype); +WASM_IMPL_TYPE(exporttype); + +#define WASM_IMPL_TYPE_CLONE(name) \ + WASM_IMPL_OWN(name) \ + WASM_IMPL_VEC_OWN(name) \ + own wasm_##name##_t* wasm_##name##_copy(wasm_##name##_t* other) { \ + TRACE0(); \ + return static_cast(other->Clone().release()); \ + } + +WASM_IMPL_TYPE_CLONE(functype); +WASM_IMPL_TYPE_CLONE(globaltype); +WASM_IMPL_TYPE_CLONE(tabletype); +WASM_IMPL_TYPE_CLONE(memorytype); +WASM_IMPL_TYPE_CLONE(externtype); + +#define WASM_IMPL_REF_BASE(name) \ + WASM_IMPL_OWN(name) \ + own wasm_##name##_t* wasm_##name##_copy(const wasm_##name##_t* ref) { \ + TRACE0(); \ + return new wasm_##name##_t(*ref); \ + } \ + bool wasm_##name##_same(const wasm_##name##_t* ref, \ + const wasm_##name##_t* other) { \ + TRACE0(); \ + return ref->I == other->I; \ + } \ + void* wasm_##name##_get_host_info(const wasm_##name##_t* ref) { \ + return ref->I->host_info(); \ + } \ + void wasm_##name##_set_host_info(wasm_##name##_t* ref, void* info) { \ + ref->I->set_host_info(info); \ + } \ + void wasm_##name##_set_host_info_with_finalizer( \ + wasm_##name##_t* ref, void* info, void (*finalizer)(void*)) { \ + ref->I->set_host_info(info); \ + ref->I->set_finalizer([=](Object* o) { finalizer(o->host_info()); }); \ + } + +#define WASM_IMPL_REF(name) \ + WASM_IMPL_REF_BASE(name) \ + wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t* subclass) { \ + return subclass; \ + } \ + wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t* ref) { \ + return static_cast(ref); \ + } \ + const wasm_ref_t* wasm_##name##_as_ref_const( \ + const wasm_##name##_t* subclass) { \ + return subclass; \ + } \ + const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t* ref) { \ + return static_cast(ref); \ + } + +WASM_IMPL_REF_BASE(ref); + +WASM_IMPL_REF(extern); +WASM_IMPL_REF(foreign); +WASM_IMPL_REF(func); +WASM_IMPL_REF(global); +WASM_IMPL_REF(instance); +WASM_IMPL_REF(memory); +WASM_IMPL_REF(table); +WASM_IMPL_REF(trap); + +#define WASM_IMPL_SHARABLE_REF(name) \ + WASM_IMPL_REF(name) \ + WASM_IMPL_OWN(shared_##name) \ + own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t* t) { \ + return static_cast( \ + const_cast(t)); \ + } \ + own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, \ + const wasm_shared_##name##_t* t) { \ + return static_cast( \ + const_cast(t)); \ + } + +WASM_IMPL_SHARABLE_REF(module) + +#define WASM_IMPL_EXTERN(name) \ + const wasm_##name##type_t* wasm_externtype_as_##name##type_const( \ + const wasm_externtype_t* t) { \ + return static_cast(t); \ + } \ + wasm_##name##type_t* wasm_externtype_as_##name##type(wasm_externtype_t* t) { \ + return static_cast(t); \ + } \ + wasm_externtype_t* wasm_##name##type_as_externtype(wasm_##name##type_t* t) { \ + return static_cast(t); \ + } \ + const wasm_externtype_t* wasm_##name##type_as_externtype_const( \ + const wasm_##name##type_t* t) { \ + return static_cast(t); \ + } \ + wasm_extern_t* wasm_##name##_as_extern(wasm_##name##_t* name) { \ + return static_cast(name); \ + } \ + const wasm_extern_t* wasm_##name##_as_extern_const( \ + const wasm_##name##_t* name) { \ + return static_cast(name); \ + } \ + wasm_##name##_t* wasm_extern_as_##name(wasm_extern_t* ext) { \ + return static_cast(ext); \ + } + +WASM_IMPL_EXTERN(table); +WASM_IMPL_EXTERN(func); +WASM_IMPL_EXTERN(global); +WASM_IMPL_EXTERN(memory); + +} // extern "C" diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.cc new file mode 100644 index 0000000..5988be1 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.cc @@ -0,0 +1,2330 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/interp/interp.h" + +#include +#include +#include + +#include "src/interp/interp-math.h" +#include "src/make-unique.h" + +namespace wabt { +namespace interp { + +const char* GetName(Mutability mut) { + static const char* kNames[] = {"immutable", "mutable"}; + return kNames[int(mut)]; +} + +const char* GetName(ValueType type) { + return type.GetName(); +} + +const char* GetName(ExternKind kind) { + return GetKindName(kind); +} + +const char* GetName(ObjectKind kind) { + static const char* kNames[] = { + "Null", "Foreign", "Trap", "DefinedFunc", "HostFunc", "Table", + "Memory", "Global", "Event", "Module", "Instance", "Thread", + }; + return kNames[int(kind)]; +} + +//// Refs //// +// static +const Ref Ref::Null{0}; + +//// Limits //// +Result Match(const Limits& expected, + const Limits& actual, + std::string* out_msg) { + if (actual.initial < expected.initial) { + *out_msg = StringPrintf("actual size (%" PRIu64 + ") smaller than declared (%" PRIu64 ")", + actual.initial, expected.initial); + return Result::Error; + } + + if (expected.has_max) { + if (!actual.has_max) { + *out_msg = StringPrintf( + "max size (unspecified) larger than declared (%" PRIu64 ")", + expected.max); + return Result::Error; + } else if (actual.max > expected.max) { + *out_msg = StringPrintf("max size (%" PRIu64 + ") larger than declared (%" PRIu64 ")", + actual.max, expected.max); + return Result::Error; + } + } + + return Result::Ok; +} + +//// FuncType //// +std::unique_ptr FuncType::Clone() const { + return MakeUnique(*this); +} + +Result Match(const FuncType& expected, + const FuncType& actual, + std::string* out_msg) { + if (expected.params != actual.params || expected.results != actual.results) { + if (out_msg) { + *out_msg = "import signature mismatch"; + } + return Result::Error; + } + return Result::Ok; +} + +//// TableType //// +std::unique_ptr TableType::Clone() const { + return MakeUnique(*this); +} + +Result Match(const TableType& expected, + const TableType& actual, + std::string* out_msg) { + if (expected.element != actual.element) { + *out_msg = + StringPrintf("type mismatch in imported table, expected %s but got %s.", + GetName(expected.element), GetName(actual.element)); + return Result::Error; + } + + if (Failed(Match(expected.limits, actual.limits, out_msg))) { + return Result::Error; + } + + return Result::Ok; +} + +//// MemoryType //// +std::unique_ptr MemoryType::Clone() const { + return MakeUnique(*this); +} + +Result Match(const MemoryType& expected, + const MemoryType& actual, + std::string* out_msg) { + return Match(expected.limits, actual.limits, out_msg); +} + +//// GlobalType //// +std::unique_ptr GlobalType::Clone() const { + return MakeUnique(*this); +} + +Result Match(const GlobalType& expected, + const GlobalType& actual, + std::string* out_msg) { + if (actual.mut != expected.mut) { + *out_msg = StringPrintf( + "mutability mismatch in imported global, expected %s but got %s.", + GetName(actual.mut), GetName(expected.mut)); + return Result::Error; + } + + if (actual.type != expected.type && + (expected.mut == Mutability::Var || + !TypesMatch(expected.type, actual.type))) { + *out_msg = StringPrintf( + "type mismatch in imported global, expected %s but got %s.", + GetName(expected.type), GetName(actual.type)); + return Result::Error; + } + + return Result::Ok; +} + +//// EventType //// +std::unique_ptr EventType::Clone() const { + return MakeUnique(*this); +} + +Result Match(const EventType& expected, + const EventType& actual, + std::string* out_msg) { + // TODO signature + return Result::Ok; +} + +//// Limits //// +template +bool CanGrow(const Limits& limits, T old_size, T delta, T* new_size) { + if (limits.max >= delta && old_size <= limits.max - delta) { + *new_size = old_size + delta; + return true; + } + return false; +} + +//// FuncDesc //// + +ValueType FuncDesc::GetLocalType(Index index) const { + if (index < type.params.size()) { + return type.params[index]; + } + index -= type.params.size(); + + auto iter = std::lower_bound( + locals.begin(), locals.end(), index + 1, + [](const LocalDesc& lhs, Index rhs) { return lhs.end < rhs; }); + assert(iter != locals.end()); + return iter->type; +} + +//// Store //// +Store::Store(const Features& features) : features_(features) { + Ref ref{objects_.New(new Object(ObjectKind::Null))}; + assert(ref == Ref::Null); + roots_.New(ref); +} + +bool Store::HasValueType(Ref ref, ValueType type) const { + // TODO opt? + if (!IsValid(ref)) { + return false; + } + if (type == ValueType::ExternRef) { + return true; + } + if (ref == Ref::Null) { + return true; + } + + Object* obj = objects_.Get(ref.index).get(); + switch (type) { + case ValueType::FuncRef: + return obj->kind() == ObjectKind::DefinedFunc || + obj->kind() == ObjectKind::HostFunc; + default: + return false; + } +} + +Store::RootList::Index Store::NewRoot(Ref ref) { + return roots_.New(ref); +} + +Store::RootList::Index Store::CopyRoot(RootList::Index index) { + // roots_.Get() returns a reference to an element in an internal vector, and + // roots_.New() might forward its arguments to emplace_back on the same + // vector. This seems to "work" in most environments, but fails on Visual + // Studio 2015 Win64. Copying it to a value fixes the issue. + auto obj_index = roots_.Get(index); + return roots_.New(obj_index); +} + +void Store::DeleteRoot(RootList::Index index) { + roots_.Delete(index); +} + +void Store::Collect() { + size_t object_count = objects_.size(); + marks_.resize(object_count); + std::fill(marks_.begin(), marks_.end(), false); + + // First mark all roots. + for (RootList::Index i = 0; i < roots_.size(); ++i) { + if (roots_.IsUsed(i)) { + Mark(roots_.Get(i)); + } + } + + // TODO: better GC algo. + // Loop through all newly marked objects and mark their referents. + std::vector all_marked(object_count, false); + bool new_marked; + do { + new_marked = false; + for (size_t i = 0; i < object_count; ++i) { + if (!all_marked[i] && marks_[i]) { + all_marked[i] = true; + objects_.Get(i)->Mark(*this); + new_marked = true; + } + } + } while (new_marked); + + // Delete all unmarked objects. + for (size_t i = 0; i < object_count; ++i) { + if (objects_.IsUsed(i) && !all_marked[i]) { + objects_.Delete(i); + } + } +} + +void Store::Mark(Ref ref) { + marks_[ref.index] = true; +} + +void Store::Mark(const RefVec& refs) { + for (auto&& ref: refs) { + Mark(ref); + } +} + +//// Object //// +Object::~Object() { + if (finalizer_) { + finalizer_(this); + } +} + +//// Foreign //// +Foreign::Foreign(Store&, void* ptr) : Object(skind), ptr_(ptr) {} + +void Foreign::Mark(Store&) {} + +//// Frame //// +void Frame::Mark(Store& store) { + store.Mark(func); +} + +//// Trap //// +Trap::Trap(Store& store, + const std::string& msg, + const std::vector& trace) + : Object(skind), message_(msg), trace_(trace) {} + +void Trap::Mark(Store& store) { + for (auto&& frame : trace_) { + frame.Mark(store); + } +} + +//// Extern //// +template +Result Extern::MatchImpl(Store& store, + const ImportType& import_type, + const T& actual, + Trap::Ptr* out_trap) { + const T* extern_type = dyn_cast(import_type.type.get()); + if (!extern_type) { + *out_trap = Trap::New( + store, + StringPrintf("expected import \"%s.%s\" to have kind %s, not %s", + import_type.module.c_str(), import_type.name.c_str(), + GetName(import_type.type->kind), GetName(T::skind))); + return Result::Error; + } + + std::string msg; + if (Failed(interp::Match(*extern_type, actual, &msg))) { + *out_trap = Trap::New(store, msg); + return Result::Error; + } + + return Result::Ok; +} + +//// Func //// +Func::Func(ObjectKind kind, FuncType type) : Extern(kind), type_(type) {} + +Result Func::Call(Store& store, + const Values& params, + Values& results, + Trap::Ptr* out_trap, + Stream* trace_stream) { + Thread::Options options; + options.trace_stream = trace_stream; + Thread::Ptr thread = Thread::New(store, options); + return DoCall(*thread, params, results, out_trap); +} + +Result Func::Call(Thread& thread, + const Values& params, + Values& results, + Trap::Ptr* out_trap) { + return DoCall(thread, params, results, out_trap); +} + +//// DefinedFunc //// +DefinedFunc::DefinedFunc(Store& store, Ref instance, FuncDesc desc) + : Func(skind, desc.type), instance_(instance), desc_(desc) {} + +void DefinedFunc::Mark(Store& store) { + store.Mark(instance_); +} + +Result DefinedFunc::Match(Store& store, + const ImportType& import_type, + Trap::Ptr* out_trap) { + return MatchImpl(store, import_type, type_, out_trap); +} + +Result DefinedFunc::DoCall(Thread& thread, + const Values& params, + Values& results, + Trap::Ptr* out_trap) { + assert(params.size() == type_.params.size()); + thread.PushValues(type_.params, params); + RunResult result = thread.PushCall(*this, out_trap); + if (result == RunResult::Trap) { + return Result::Error; + } + result = thread.Run(out_trap); + if (result == RunResult::Trap) { + return Result::Error; + } + thread.PopValues(type_.results, &results); + return Result::Ok; +} + +//// HostFunc //// +HostFunc::HostFunc(Store&, FuncType type, Callback callback) + : Func(skind, type), callback_(callback) {} + +void HostFunc::Mark(Store&) {} + +Result HostFunc::Match(Store& store, + const ImportType& import_type, + Trap::Ptr* out_trap) { + return MatchImpl(store, import_type, type_, out_trap); +} + +Result HostFunc::DoCall(Thread& thread, + const Values& params, + Values& results, + Trap::Ptr* out_trap) { + return callback_(thread, params, results, out_trap); +} + +//// Table //// +Table::Table(Store&, TableType type) : Extern(skind), type_(type) { + elements_.resize(type.limits.initial); +} + +void Table::Mark(Store& store) { + store.Mark(elements_); +} + +Result Table::Match(Store& store, + const ImportType& import_type, + Trap::Ptr* out_trap) { + return MatchImpl(store, import_type, type_, out_trap); +} + +bool Table::IsValidRange(u32 offset, u32 size) const { + size_t elem_size = elements_.size(); + return size <= elem_size && offset <= elem_size - size; +} + +Result Table::Get(u32 offset, Ref* out) const { + if (IsValidRange(offset, 1)) { + *out = elements_[offset]; + return Result::Ok; + } + return Result::Error; +} + +Ref Table::UnsafeGet(u32 offset) const { + assert(IsValidRange(offset, 1)); + return elements_[offset]; +} + +Result Table::Set(Store& store, u32 offset, Ref ref) { + if (IsValidRange(offset, 1) && store.HasValueType(ref, type_.element)) { + elements_[offset] = ref; + return Result::Ok; + } + return Result::Error; +} + +Result Table::Grow(Store& store, u32 count, Ref ref) { + size_t old_size = elements_.size(); + u32 new_size; + if (store.HasValueType(ref, type_.element) && + CanGrow(type_.limits, old_size, count, &new_size)) { + elements_.resize(new_size); + Fill(store, old_size, ref, new_size - old_size); + return Result::Ok; + } + return Result::Error; +} + +Result Table::Fill(Store& store, u32 offset, Ref ref, u32 size) { + if (IsValidRange(offset, size) && + store.HasValueType(ref, type_.element)) { + std::fill(elements_.begin() + offset, elements_.begin() + offset + size, + ref); + return Result::Ok; + } + return Result::Error; +} + +Result Table::Init(Store& store, + u32 dst_offset, + const ElemSegment& src, + u32 src_offset, + u32 size) { + if (IsValidRange(dst_offset, size) && src.IsValidRange(src_offset, size) && + TypesMatch(type_.element, src.desc().type)) { + std::copy(src.elements().begin() + src_offset, + src.elements().begin() + src_offset + size, + elements_.begin() + dst_offset); + return Result::Ok; + } + return Result::Error; +} + +// static +Result Table::Copy(Store& store, + Table& dst, + u32 dst_offset, + const Table& src, + u32 src_offset, + u32 size) { + if (dst.IsValidRange(dst_offset, size) && + src.IsValidRange(src_offset, size) && + TypesMatch(dst.type_.element, src.type_.element)) { + auto src_begin = src.elements_.begin() + src_offset; + auto src_end = src_begin + size; + auto dst_begin = dst.elements_.begin() + dst_offset; + auto dst_end = dst_begin + size; + if (dst.self() == src.self() && src_begin < dst_begin) { + std::move_backward(src_begin, src_end, dst_end); + } else { + std::move(src_begin, src_end, dst_begin); + } + return Result::Ok; + } + return Result::Error; +} + +//// Memory //// +Memory::Memory(class Store&, MemoryType type) + : Extern(skind), type_(type), pages_(type.limits.initial) { + data_.resize(pages_ * WABT_PAGE_SIZE); +} + +void Memory::Mark(class Store&) {} + +Result Memory::Match(class Store& store, + const ImportType& import_type, + Trap::Ptr* out_trap) { + return MatchImpl(store, import_type, type_, out_trap); +} + +Result Memory::Grow(u64 count) { + u64 new_pages; + if (CanGrow(type_.limits, pages_, count, &new_pages)) { +#if WABT_BIG_ENDIAN + auto old_size = data_.size(); +#endif + pages_ = new_pages; + data_.resize(new_pages * WABT_PAGE_SIZE); +#if WABT_BIG_ENDIAN + std::move_backward(data_.begin(), data_.begin() + old_size, data_.end()); + std::fill(data_.begin(), data_.end() - old_size, 0); +#endif + return Result::Ok; + } + return Result::Error; +} + +Result Memory::Fill(u64 offset, u8 value, u64 size) { + if (IsValidAccess(offset, 0, size)) { +#if WABT_BIG_ENDIAN + std::fill(data_.end() - offset - size, data_.end() - offset, value); +#else + std::fill(data_.begin() + offset, data_.begin() + offset + size, value); +#endif + return Result::Ok; + } + return Result::Error; +} + +Result Memory::Init(u64 dst_offset, + const DataSegment& src, + u64 src_offset, + u64 size) { + if (IsValidAccess(dst_offset, 0, size) && + src.IsValidRange(src_offset, size)) { + std::copy(src.desc().data.begin() + src_offset, + src.desc().data.begin() + src_offset + size, +#if WABT_BIG_ENDIAN + data_.rbegin() + dst_offset); +#else + data_.begin() + dst_offset); +#endif + return Result::Ok; + } + return Result::Error; +} + +// static +Result Memory::Copy(Memory& dst, + u64 dst_offset, + const Memory& src, + u64 src_offset, + u64 size) { + if (dst.IsValidAccess(dst_offset, 0, size) && + src.IsValidAccess(src_offset, 0, size)) { +#if WABT_BIG_ENDIAN + auto src_begin = src.data_.end() - src_offset - size; + auto dst_begin = dst.data_.end() - dst_offset - size; +#else + auto src_begin = src.data_.begin() + src_offset; + auto dst_begin = dst.data_.begin() + dst_offset; +#endif + auto src_end = src_begin + size; + auto dst_end = dst_begin + size; + if (src.self() == dst.self() && src_begin < dst_begin) { + std::move_backward(src_begin, src_end, dst_end); + } else { + std::move(src_begin, src_end, dst_begin); + } + return Result::Ok; + } + return Result::Error; +} + +Value Instance::ResolveInitExpr(Store& store, InitExpr init) { + Value result; + switch (init.kind) { + case InitExprKind::I32: result.Set(init.i32_); break; + case InitExprKind::I64: result.Set(init.i64_); break; + case InitExprKind::F32: result.Set(init.f32_); break; + case InitExprKind::F64: result.Set(init.f64_); break; + case InitExprKind::V128: result.Set(init.v128_); break; + case InitExprKind::GlobalGet: { + Global::Ptr global{store, globals_[init.index_]}; + result = global->Get(); + break; + } + case InitExprKind::RefFunc: { + result.Set(funcs_[init.index_]); + break; + } + case InitExprKind::RefNull: + result.Set(Ref::Null); + break; + + case InitExprKind::None: + WABT_UNREACHABLE; + } + return result; +} + +//// Global //// +Global::Global(Store& store, GlobalType type, Value value) + : Extern(skind), type_(type), value_(value) {} + +void Global::Mark(Store& store) { + if (IsReference(type_.type)) { + store.Mark(value_.Get()); + } +} + +Result Global::Match(Store& store, + const ImportType& import_type, + Trap::Ptr* out_trap) { + return MatchImpl(store, import_type, type_, out_trap); +} + +Result Global::Set(Store& store, Ref ref) { + if (store.HasValueType(ref, type_.type)) { + value_.Set(ref); + return Result::Ok; + } + return Result::Error; +} + +void Global::UnsafeSet(Value value) { + value_ = value; +} + +//// Event //// +Event::Event(Store&, EventType type) : Extern(skind), type_(type) {} + +void Event::Mark(Store&) {} + +Result Event::Match(Store& store, + const ImportType& import_type, + Trap::Ptr* out_trap) { + return MatchImpl(store, import_type, type_, out_trap); +} + +//// ElemSegment //// +ElemSegment::ElemSegment(const ElemDesc* desc, Instance::Ptr& inst) + : desc_(desc) { + elements_.reserve(desc->elements.size()); + for (auto&& elem_expr : desc->elements) { + switch (elem_expr.kind) { + case ElemKind::RefNull: + elements_.emplace_back(Ref::Null); + break; + + case ElemKind::RefFunc: + elements_.emplace_back(inst->funcs_[elem_expr.index]); + break; + } + } +} + +bool ElemSegment::IsValidRange(u32 offset, u32 size) const { + u32 elem_size = this->size(); + return size <= elem_size && offset <= elem_size - size; +} + +//// DataSegment //// +DataSegment::DataSegment(const DataDesc* desc) + : desc_(desc), size_(desc->data.size()) {} + +bool DataSegment::IsValidRange(u64 offset, u64 size) const { + u64 data_size = size_; + return size <= data_size && offset <= data_size - size; +} + +//// Module //// +Module::Module(Store&, ModuleDesc desc) + : Object(skind), desc_(std::move(desc)) { + for (auto&& import: desc_.imports) { + import_types_.emplace_back(import.type); + } + + for (auto&& export_: desc_.exports) { + export_types_.emplace_back(export_.type); + } +} + +void Module::Mark(Store&) {} + +//// ElemSegment //// +void ElemSegment::Mark(Store& store) { + store.Mark(elements_); +} + +//// Instance //// +Instance::Instance(Store& store, Ref module) : Object(skind), module_(module) { + assert(store.Is(module)); +} + +// static +Instance::Ptr Instance::Instantiate(Store& store, + Ref module, + const RefVec& imports, + Trap::Ptr* out_trap) { + Module::Ptr mod{store, module}; + Instance::Ptr inst = store.Alloc(store, module); + + size_t import_desc_count = mod->desc().imports.size(); + if (imports.size() < import_desc_count) { + *out_trap = Trap::New(store, "not enough imports!"); + return {}; + } + + // Imports. + for (size_t i = 0; i < import_desc_count; ++i) { + auto&& import_desc = mod->desc().imports[i]; + Ref extern_ref = imports[i]; + if (extern_ref == Ref::Null) { + *out_trap = Trap::New(store, StringPrintf("invalid import \"%s.%s\"", + import_desc.type.module.c_str(), + import_desc.type.name.c_str())); + return {}; + } + + Extern::Ptr extern_{store, extern_ref}; + if (Failed(extern_->Match(store, import_desc.type, out_trap))) { + return {}; + } + + inst->imports_.push_back(extern_ref); + + switch (import_desc.type.type->kind) { + case ExternKind::Func: inst->funcs_.push_back(extern_ref); break; + case ExternKind::Table: inst->tables_.push_back(extern_ref); break; + case ExternKind::Memory: inst->memories_.push_back(extern_ref); break; + case ExternKind::Global: inst->globals_.push_back(extern_ref); break; + case ExternKind::Event: inst->events_.push_back(extern_ref); break; + } + } + + // Funcs. + for (auto&& desc : mod->desc().funcs) { + inst->funcs_.push_back(DefinedFunc::New(store, inst.ref(), desc).ref()); + } + + // Tables. + for (auto&& desc : mod->desc().tables) { + inst->tables_.push_back(Table::New(store, desc.type).ref()); + } + + // Memories. + for (auto&& desc : mod->desc().memories) { + inst->memories_.push_back(Memory::New(store, desc.type).ref()); + } + + // Globals. + for (auto&& desc : mod->desc().globals) { + inst->globals_.push_back( + Global::New(store, desc.type, inst->ResolveInitExpr(store, desc.init)) + .ref()); + } + + // Events. + for (auto&& desc : mod->desc().events) { + inst->events_.push_back(Event::New(store, desc.type).ref()); + } + + // Exports. + for (auto&& desc : mod->desc().exports){ + Ref ref; + switch (desc.type.type->kind) { + case ExternKind::Func: ref = inst->funcs_[desc.index]; break; + case ExternKind::Table: ref = inst->tables_[desc.index]; break; + case ExternKind::Memory: ref = inst->memories_[desc.index]; break; + case ExternKind::Global: ref = inst->globals_[desc.index]; break; + case ExternKind::Event: ref = inst->events_[desc.index]; break; + } + inst->exports_.push_back(ref); + } + + // Elems. + for (auto&& desc : mod->desc().elems) { + inst->elems_.emplace_back(&desc, inst); + } + + // Datas. + for (auto&& desc : mod->desc().datas) { + inst->datas_.emplace_back(&desc); + } + + // Initialization. + enum Pass { Check, Init }; + int pass = store.features().bulk_memory_enabled() ? Init : Check; + for (; pass <= Init; ++pass) { + // Elems. + for (auto&& segment : inst->elems_) { + auto&& desc = segment.desc(); + if (desc.mode == SegmentMode::Active) { + Result result; + Table::Ptr table{store, inst->tables_[desc.table_index]}; + u32 offset = inst->ResolveInitExpr(store, desc.offset).Get(); + if (pass == Check) { + result = table->IsValidRange(offset, segment.size()) ? Result::Ok + : Result::Error; + } else { + result = table->Init(store, offset, segment, 0, segment.size()); + segment.Drop(); + } + + if (Failed(result)) { + *out_trap = Trap::New( + store, StringPrintf( + "out of bounds table access: elem segment is " + "out of bounds: [%u, %" PRIu64 ") >= max value %u", + offset, u64{offset} + segment.size(), table->size())); + return {}; + } + } else if (desc.mode == SegmentMode::Declared) { + segment.Drop(); + } + } + + // Data. + for (auto&& segment : inst->datas_) { + auto&& desc = segment.desc(); + if (desc.mode == SegmentMode::Active) { + Result result; + Memory::Ptr memory{store, inst->memories_[desc.memory_index]}; + u32 offset = inst->ResolveInitExpr(store, desc.offset).Get(); + if (pass == Check) { + result = memory->IsValidAccess(offset, 0, segment.size()) + ? Result::Ok + : Result::Error; + } else { + result = memory->Init(offset, segment, 0, segment.size()); + segment.Drop(); + } + + if (Failed(result)) { + *out_trap = Trap::New( + store, + StringPrintf("out of bounds memory access: data segment is " + "out of bounds: [%u, %" PRIu64 ") >= max value %" + PRIu64, offset, u64{offset} + segment.size(), + memory->ByteSize())); + return {}; + } + } else if (desc.mode == SegmentMode::Declared) { + segment.Drop(); + } + } + } + + // Start. + for (auto&& start : mod->desc().starts) { + Func::Ptr func{store, inst->funcs_[start.func_index]}; + Values results; + if (Failed(func->Call(store, {}, results, out_trap))) { + return {}; + } + } + + return inst; +} + +void Instance::Mark(Store& store) { + store.Mark(module_); + store.Mark(imports_); + store.Mark(funcs_); + store.Mark(memories_); + store.Mark(tables_); + store.Mark(globals_); + store.Mark(events_); + store.Mark(exports_); + for (auto&& elem : elems_) { + elem.Mark(store); + } +} + +//// Thread //// +Thread::Thread(Store& store, const Options& options) + : Object(skind), store_(store) { + frames_.reserve(options.call_stack_size); + values_.reserve(options.value_stack_size); + trace_stream_ = options.trace_stream; + if (options.trace_stream) { + trace_source_ = MakeUnique(this); + } +} + +void Thread::Mark(Store& store) { + for (auto&& frame : frames_) { + frame.Mark(store); + } + for (auto index: refs_) { + store.Mark(values_[index].Get()); + } +} + +void Thread::PushValues(const ValueTypes& types, const Values& values) { + assert(types.size() == values.size()); + for (size_t i = 0; i < types.size(); ++i) { + if (IsReference(types[i])) { + refs_.push_back(values_.size()); + } + values_.push_back(values[i]); + } +} + +#define TRAP(msg) *out_trap = Trap::New(store_, (msg), frames_), RunResult::Trap +#define TRAP_IF(cond, msg) \ + if (WABT_UNLIKELY((cond))) { \ + return TRAP(msg); \ + } +#define TRAP_UNLESS(cond, msg) TRAP_IF(!(cond), msg) + +Instance* Thread::GetCallerInstance() { + if (frames_.size() < 2) + return nullptr; + return frames_[frames_.size() - 2].inst; +} + +RunResult Thread::PushCall(Ref func, u32 offset, Trap::Ptr* out_trap) { + TRAP_IF(frames_.size() == frames_.capacity(), "call stack exhausted"); + frames_.emplace_back(func, values_.size(), offset, inst_, mod_); + return RunResult::Ok; +} + +RunResult Thread::PushCall(const DefinedFunc& func, Trap::Ptr* out_trap) { + TRAP_IF(frames_.size() == frames_.capacity(), "call stack exhausted"); + inst_ = store_.UnsafeGet(func.instance()).get(); + mod_ = store_.UnsafeGet(inst_->module()).get(); + frames_.emplace_back(func.self(), values_.size(), func.desc().code_offset, + inst_, mod_); + return RunResult::Ok; +} + +RunResult Thread::PushCall(const HostFunc& func, Trap::Ptr* out_trap) { + TRAP_IF(frames_.size() == frames_.capacity(), "call stack exhausted"); + inst_ = nullptr; + mod_ = nullptr; + frames_.emplace_back(func.self(), values_.size(), 0, inst_, mod_); + return RunResult::Ok; +} + +RunResult Thread::PopCall() { + frames_.pop_back(); + if (frames_.empty()) { + return RunResult::Return; + } + + auto& frame = frames_.back(); + if (!frame.inst) { + // Returning to a HostFunc called on this thread. + return RunResult::Return; + } + + inst_ = frame.inst; + mod_ = frame.mod; + return RunResult::Ok; +} + +RunResult Thread::DoReturnCall(const Func::Ptr& func, Trap::Ptr* out_trap) { + PopCall(); + DoCall(func, out_trap); + return frames_.empty() ? RunResult::Return : RunResult::Ok; +} + +void Thread::PopValues(const ValueTypes& types, Values* out_values) { + assert(values_.size() >= types.size()); + out_values->resize(types.size()); + std::copy(values_.end() - types.size(), values_.end(), out_values->begin()); + values_.resize(values_.size() - types.size()); +} + +RunResult Thread::Run(Trap::Ptr* out_trap) { + const int kDefaultInstructionCount = 1000; + RunResult result; + do { + result = Run(kDefaultInstructionCount, out_trap); + } while (result == RunResult::Ok); + return result; +} + +RunResult Thread::Run(int num_instructions, Trap::Ptr* out_trap) { + DefinedFunc::Ptr func{store_, frames_.back().func}; + for (;num_instructions > 0; --num_instructions) { + auto result = StepInternal(out_trap); + if (result != RunResult::Ok) { + return result; + } + } + return RunResult::Ok; +} + +RunResult Thread::Step(Trap::Ptr* out_trap) { + DefinedFunc::Ptr func{store_, frames_.back().func}; + return StepInternal(out_trap); +} + +Value& Thread::Pick(Index index) { + assert(index > 0 && index <= values_.size()); + return values_[values_.size() - index]; +} + +template +T WABT_VECTORCALL Thread::Pop() { + return Pop().Get(); +} + +Value Thread::Pop() { + if (!refs_.empty() && refs_.back() >= values_.size()) { + refs_.pop_back(); + } + auto value = values_.back(); + values_.pop_back(); + return value; +} + +u64 Thread::PopPtr(const Memory::Ptr& memory) { + return memory->type().limits.is_64 ? Pop() : Pop(); +} + +template +void WABT_VECTORCALL Thread::Push(T value) { + Push(Value::Make(value)); +} + +template <> +void Thread::Push(bool value) { + Push(Value::Make(static_cast(value ? 1 : 0))); +} + +void Thread::Push(Value value) { + values_.push_back(value); +} + +void Thread::Push(Ref ref) { + refs_.push_back(values_.size()); + values_.push_back(Value::Make(ref)); +} + +RunResult Thread::StepInternal(Trap::Ptr* out_trap) { + using O = Opcode; + + u32& pc = frames_.back().offset; + auto& istream = mod_->desc().istream; + + if (trace_stream_) { + istream.Trace(trace_stream_, pc, trace_source_.get()); + } + + auto instr = istream.Read(&pc); + switch (instr.op) { + case O::Unreachable: + return TRAP("unreachable executed"); + + case O::Br: + pc = instr.imm_u32; + break; + + case O::BrIf: + if (Pop()) { + pc = instr.imm_u32; + } + break; + + case O::BrTable: { + auto key = Pop(); + if (key >= instr.imm_u32) { + key = instr.imm_u32; + } + pc += key * Istream::kBrTableEntrySize; + break; + } + + case O::Return: + return PopCall(); + + case O::Call: { + Ref new_func_ref = inst_->funcs()[instr.imm_u32]; + DefinedFunc::Ptr new_func{store_, new_func_ref}; + if (PushCall(new_func_ref, new_func->desc().code_offset, out_trap) == + RunResult::Trap) { + return RunResult::Trap; + } + break; + } + + case O::CallIndirect: + case O::ReturnCallIndirect: { + Table::Ptr table{store_, inst_->tables()[instr.imm_u32x2.fst]}; + auto&& func_type = mod_->desc().func_types[instr.imm_u32x2.snd]; + auto entry = Pop(); + TRAP_IF(entry >= table->elements().size(), "undefined table index"); + auto new_func_ref = table->elements()[entry]; + TRAP_IF(new_func_ref == Ref::Null, "uninitialized table element"); + Func::Ptr new_func{store_, new_func_ref}; + TRAP_IF( + Failed(Match(new_func->type(), func_type, nullptr)), + "indirect call signature mismatch"); // TODO: don't use "signature" + if (instr.op == O::ReturnCallIndirect) { + return DoReturnCall(new_func, out_trap); + } else { + return DoCall(new_func, out_trap); + } + } + + case O::Drop: + Pop(); + break; + + case O::Select: { + // TODO: need to mark whether this is a ref. + auto cond = Pop(); + Value false_ = Pop(); + Value true_ = Pop(); + Push(cond ? true_ : false_); + break; + } + + case O::LocalGet: + // TODO: need to mark whether this is a ref. + Push(Pick(instr.imm_u32)); + break; + + case O::LocalSet: { + Pick(instr.imm_u32) = Pick(1); + Pop(); + break; + } + + case O::LocalTee: + Pick(instr.imm_u32) = Pick(1); + break; + + case O::GlobalGet: { + // TODO: need to mark whether this is a ref. + Global::Ptr global{store_, inst_->globals()[instr.imm_u32]}; + Push(global->Get()); + break; + } + + case O::GlobalSet: { + Global::Ptr global{store_, inst_->globals()[instr.imm_u32]}; + global->UnsafeSet(Pop()); + break; + } + + case O::I32Load: return DoLoad(instr, out_trap); + case O::I64Load: return DoLoad(instr, out_trap); + case O::F32Load: return DoLoad(instr, out_trap); + case O::F64Load: return DoLoad(instr, out_trap); + case O::I32Load8S: return DoLoad(instr, out_trap); + case O::I32Load8U: return DoLoad(instr, out_trap); + case O::I32Load16S: return DoLoad(instr, out_trap); + case O::I32Load16U: return DoLoad(instr, out_trap); + case O::I64Load8S: return DoLoad(instr, out_trap); + case O::I64Load8U: return DoLoad(instr, out_trap); + case O::I64Load16S: return DoLoad(instr, out_trap); + case O::I64Load16U: return DoLoad(instr, out_trap); + case O::I64Load32S: return DoLoad(instr, out_trap); + case O::I64Load32U: return DoLoad(instr, out_trap); + + case O::I32Store: return DoStore(instr, out_trap); + case O::I64Store: return DoStore(instr, out_trap); + case O::F32Store: return DoStore(instr, out_trap); + case O::F64Store: return DoStore(instr, out_trap); + case O::I32Store8: return DoStore(instr, out_trap); + case O::I32Store16: return DoStore(instr, out_trap); + case O::I64Store8: return DoStore(instr, out_trap); + case O::I64Store16: return DoStore(instr, out_trap); + case O::I64Store32: return DoStore(instr, out_trap); + + case O::MemorySize: { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32]}; + if (memory->type().limits.is_64) { + Push(memory->PageSize()); + } else { + Push(static_cast(memory->PageSize())); + } + break; + } + + case O::MemoryGrow: { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32]}; + u64 old_size = memory->PageSize(); + if (memory->type().limits.is_64) { + if (Failed(memory->Grow(Pop()))) { + Push(-1); + } else { + Push(old_size); + } + } else { + if (Failed(memory->Grow(Pop()))) { + Push(-1); + } else { + Push(old_size); + } + } + break; + } + + case O::I32Const: Push(instr.imm_u32); break; + case O::F32Const: Push(instr.imm_f32); break; + case O::I64Const: Push(instr.imm_u64); break; + case O::F64Const: Push(instr.imm_f64); break; + + case O::I32Eqz: return DoUnop(IntEqz); + case O::I32Eq: return DoBinop(Eq); + case O::I32Ne: return DoBinop(Ne); + case O::I32LtS: return DoBinop(Lt); + case O::I32LtU: return DoBinop(Lt); + case O::I32GtS: return DoBinop(Gt); + case O::I32GtU: return DoBinop(Gt); + case O::I32LeS: return DoBinop(Le); + case O::I32LeU: return DoBinop(Le); + case O::I32GeS: return DoBinop(Ge); + case O::I32GeU: return DoBinop(Ge); + + case O::I64Eqz: return DoUnop(IntEqz); + case O::I64Eq: return DoBinop(Eq); + case O::I64Ne: return DoBinop(Ne); + case O::I64LtS: return DoBinop(Lt); + case O::I64LtU: return DoBinop(Lt); + case O::I64GtS: return DoBinop(Gt); + case O::I64GtU: return DoBinop(Gt); + case O::I64LeS: return DoBinop(Le); + case O::I64LeU: return DoBinop(Le); + case O::I64GeS: return DoBinop(Ge); + case O::I64GeU: return DoBinop(Ge); + + case O::F32Eq: return DoBinop(Eq); + case O::F32Ne: return DoBinop(Ne); + case O::F32Lt: return DoBinop(Lt); + case O::F32Gt: return DoBinop(Gt); + case O::F32Le: return DoBinop(Le); + case O::F32Ge: return DoBinop(Ge); + + case O::F64Eq: return DoBinop(Eq); + case O::F64Ne: return DoBinop(Ne); + case O::F64Lt: return DoBinop(Lt); + case O::F64Gt: return DoBinop(Gt); + case O::F64Le: return DoBinop(Le); + case O::F64Ge: return DoBinop(Ge); + + case O::I32Clz: return DoUnop(IntClz); + case O::I32Ctz: return DoUnop(IntCtz); + case O::I32Popcnt: return DoUnop(IntPopcnt); + case O::I32Add: return DoBinop(Add); + case O::I32Sub: return DoBinop(Sub); + case O::I32Mul: return DoBinop(Mul); + case O::I32DivS: return DoBinop(IntDiv, out_trap); + case O::I32DivU: return DoBinop(IntDiv, out_trap); + case O::I32RemS: return DoBinop(IntRem, out_trap); + case O::I32RemU: return DoBinop(IntRem, out_trap); + case O::I32And: return DoBinop(IntAnd); + case O::I32Or: return DoBinop(IntOr); + case O::I32Xor: return DoBinop(IntXor); + case O::I32Shl: return DoBinop(IntShl); + case O::I32ShrS: return DoBinop(IntShr); + case O::I32ShrU: return DoBinop(IntShr); + case O::I32Rotl: return DoBinop(IntRotl); + case O::I32Rotr: return DoBinop(IntRotr); + + case O::I64Clz: return DoUnop(IntClz); + case O::I64Ctz: return DoUnop(IntCtz); + case O::I64Popcnt: return DoUnop(IntPopcnt); + case O::I64Add: return DoBinop(Add); + case O::I64Sub: return DoBinop(Sub); + case O::I64Mul: return DoBinop(Mul); + case O::I64DivS: return DoBinop(IntDiv, out_trap); + case O::I64DivU: return DoBinop(IntDiv, out_trap); + case O::I64RemS: return DoBinop(IntRem, out_trap); + case O::I64RemU: return DoBinop(IntRem, out_trap); + case O::I64And: return DoBinop(IntAnd); + case O::I64Or: return DoBinop(IntOr); + case O::I64Xor: return DoBinop(IntXor); + case O::I64Shl: return DoBinop(IntShl); + case O::I64ShrS: return DoBinop(IntShr); + case O::I64ShrU: return DoBinop(IntShr); + case O::I64Rotl: return DoBinop(IntRotl); + case O::I64Rotr: return DoBinop(IntRotr); + + case O::F32Abs: return DoUnop(FloatAbs); + case O::F32Neg: return DoUnop(FloatNeg); + case O::F32Ceil: return DoUnop(FloatCeil); + case O::F32Floor: return DoUnop(FloatFloor); + case O::F32Trunc: return DoUnop(FloatTrunc); + case O::F32Nearest: return DoUnop(FloatNearest); + case O::F32Sqrt: return DoUnop(FloatSqrt); + case O::F32Add: return DoBinop(Add); + case O::F32Sub: return DoBinop(Sub); + case O::F32Mul: return DoBinop(Mul); + case O::F32Div: return DoBinop(FloatDiv); + case O::F32Min: return DoBinop(FloatMin); + case O::F32Max: return DoBinop(FloatMax); + case O::F32Copysign: return DoBinop(FloatCopysign); + + case O::F64Abs: return DoUnop(FloatAbs); + case O::F64Neg: return DoUnop(FloatNeg); + case O::F64Ceil: return DoUnop(FloatCeil); + case O::F64Floor: return DoUnop(FloatFloor); + case O::F64Trunc: return DoUnop(FloatTrunc); + case O::F64Nearest: return DoUnop(FloatNearest); + case O::F64Sqrt: return DoUnop(FloatSqrt); + case O::F64Add: return DoBinop(Add); + case O::F64Sub: return DoBinop(Sub); + case O::F64Mul: return DoBinop(Mul); + case O::F64Div: return DoBinop(FloatDiv); + case O::F64Min: return DoBinop(FloatMin); + case O::F64Max: return DoBinop(FloatMax); + case O::F64Copysign: return DoBinop(FloatCopysign); + + case O::I32WrapI64: return DoConvert(out_trap); + case O::I32TruncF32S: return DoConvert(out_trap); + case O::I32TruncF32U: return DoConvert(out_trap); + case O::I32TruncF64S: return DoConvert(out_trap); + case O::I32TruncF64U: return DoConvert(out_trap); + case O::I64ExtendI32S: return DoConvert(out_trap); + case O::I64ExtendI32U: return DoConvert(out_trap); + case O::I64TruncF32S: return DoConvert(out_trap); + case O::I64TruncF32U: return DoConvert(out_trap); + case O::I64TruncF64S: return DoConvert(out_trap); + case O::I64TruncF64U: return DoConvert(out_trap); + case O::F32ConvertI32S: return DoConvert(out_trap); + case O::F32ConvertI32U: return DoConvert(out_trap); + case O::F32ConvertI64S: return DoConvert(out_trap); + case O::F32ConvertI64U: return DoConvert(out_trap); + case O::F32DemoteF64: return DoConvert(out_trap); + case O::F64ConvertI32S: return DoConvert(out_trap); + case O::F64ConvertI32U: return DoConvert(out_trap); + case O::F64ConvertI64S: return DoConvert(out_trap); + case O::F64ConvertI64U: return DoConvert(out_trap); + case O::F64PromoteF32: return DoConvert(out_trap); + + case O::I32ReinterpretF32: return DoReinterpret(); + case O::F32ReinterpretI32: return DoReinterpret(); + case O::I64ReinterpretF64: return DoReinterpret(); + case O::F64ReinterpretI64: return DoReinterpret(); + + case O::I32Extend8S: return DoUnop(IntExtend); + case O::I32Extend16S: return DoUnop(IntExtend); + case O::I64Extend8S: return DoUnop(IntExtend); + case O::I64Extend16S: return DoUnop(IntExtend); + case O::I64Extend32S: return DoUnop(IntExtend); + + case O::InterpAlloca: + values_.resize(values_.size() + instr.imm_u32); + // refs_ doesn't need to be updated; We may be allocating space for + // references, but they will be initialized to null, so it is OK if we + // don't mark them. + break; + + case O::InterpBrUnless: + if (!Pop()) { + pc = instr.imm_u32; + } + break; + + case O::InterpCallImport: { + Ref new_func_ref = inst_->funcs()[instr.imm_u32]; + Func::Ptr new_func{store_, new_func_ref}; + return DoCall(new_func, out_trap); + } + + case O::InterpDropKeep: { + auto drop = instr.imm_u32x2.fst; + auto keep = instr.imm_u32x2.snd; + // Shift kept refs down. + for (auto iter = refs_.rbegin(); iter != refs_.rend(); ++iter) { + if (*iter >= values_.size() - keep) { + *iter -= drop; + } else { + break; + } + } + std::move(values_.end() - keep, values_.end(), + values_.end() - drop - keep); + values_.resize(values_.size() - drop); + break; + } + + case O::I32TruncSatF32S: return DoUnop(IntTruncSat); + case O::I32TruncSatF32U: return DoUnop(IntTruncSat); + case O::I32TruncSatF64S: return DoUnop(IntTruncSat); + case O::I32TruncSatF64U: return DoUnop(IntTruncSat); + case O::I64TruncSatF32S: return DoUnop(IntTruncSat); + case O::I64TruncSatF32U: return DoUnop(IntTruncSat); + case O::I64TruncSatF64S: return DoUnop(IntTruncSat); + case O::I64TruncSatF64U: return DoUnop(IntTruncSat); + + case O::MemoryInit: return DoMemoryInit(instr, out_trap); + case O::DataDrop: return DoDataDrop(instr); + case O::MemoryCopy: return DoMemoryCopy(instr, out_trap); + case O::MemoryFill: return DoMemoryFill(instr, out_trap); + + case O::TableInit: return DoTableInit(instr, out_trap); + case O::ElemDrop: return DoElemDrop(instr); + case O::TableCopy: return DoTableCopy(instr, out_trap); + case O::TableGet: return DoTableGet(instr, out_trap); + case O::TableSet: return DoTableSet(instr, out_trap); + case O::TableGrow: return DoTableGrow(instr, out_trap); + case O::TableSize: return DoTableSize(instr); + case O::TableFill: return DoTableFill(instr, out_trap); + + case O::RefNull: + Push(Ref::Null); + break; + + case O::RefIsNull: + Push(Pop() == Ref::Null); + break; + + case O::RefFunc: + Push(inst_->funcs()[instr.imm_u32]); + break; + + case O::V128Load: return DoLoad(instr, out_trap); + case O::V128Store: return DoStore(instr, out_trap); + + case O::V128Const: + Push(instr.imm_v128); + break; + + case O::I8X16Splat: return DoSimdSplat(); + case O::I8X16ExtractLaneS: return DoSimdExtract(instr); + case O::I8X16ExtractLaneU: return DoSimdExtract(instr); + case O::I8X16ReplaceLane: return DoSimdReplace(instr); + case O::I16X8Splat: return DoSimdSplat(); + case O::I16X8ExtractLaneS: return DoSimdExtract(instr); + case O::I16X8ExtractLaneU: return DoSimdExtract(instr); + case O::I16X8ReplaceLane: return DoSimdReplace(instr); + case O::I32X4Splat: return DoSimdSplat(); + case O::I32X4ExtractLane: return DoSimdExtract(instr); + case O::I32X4ReplaceLane: return DoSimdReplace(instr); + case O::I64X2Splat: return DoSimdSplat(); + case O::I64X2ExtractLane: return DoSimdExtract(instr); + case O::I64X2ReplaceLane: return DoSimdReplace(instr); + case O::F32X4Splat: return DoSimdSplat(); + case O::F32X4ExtractLane: return DoSimdExtract(instr); + case O::F32X4ReplaceLane: return DoSimdReplace(instr); + case O::F64X2Splat: return DoSimdSplat(); + case O::F64X2ExtractLane: return DoSimdExtract(instr); + case O::F64X2ReplaceLane: return DoSimdReplace(instr); + + case O::I8X16Eq: return DoSimdBinop(EqMask); + case O::I8X16Ne: return DoSimdBinop(NeMask); + case O::I8X16LtS: return DoSimdBinop(LtMask); + case O::I8X16LtU: return DoSimdBinop(LtMask); + case O::I8X16GtS: return DoSimdBinop(GtMask); + case O::I8X16GtU: return DoSimdBinop(GtMask); + case O::I8X16LeS: return DoSimdBinop(LeMask); + case O::I8X16LeU: return DoSimdBinop(LeMask); + case O::I8X16GeS: return DoSimdBinop(GeMask); + case O::I8X16GeU: return DoSimdBinop(GeMask); + case O::I16X8Eq: return DoSimdBinop(EqMask); + case O::I16X8Ne: return DoSimdBinop(NeMask); + case O::I16X8LtS: return DoSimdBinop(LtMask); + case O::I16X8LtU: return DoSimdBinop(LtMask); + case O::I16X8GtS: return DoSimdBinop(GtMask); + case O::I16X8GtU: return DoSimdBinop(GtMask); + case O::I16X8LeS: return DoSimdBinop(LeMask); + case O::I16X8LeU: return DoSimdBinop(LeMask); + case O::I16X8GeS: return DoSimdBinop(GeMask); + case O::I16X8GeU: return DoSimdBinop(GeMask); + case O::I32X4Eq: return DoSimdBinop(EqMask); + case O::I32X4Ne: return DoSimdBinop(NeMask); + case O::I32X4LtS: return DoSimdBinop(LtMask); + case O::I32X4LtU: return DoSimdBinop(LtMask); + case O::I32X4GtS: return DoSimdBinop(GtMask); + case O::I32X4GtU: return DoSimdBinop(GtMask); + case O::I32X4LeS: return DoSimdBinop(LeMask); + case O::I32X4LeU: return DoSimdBinop(LeMask); + case O::I32X4GeS: return DoSimdBinop(GeMask); + case O::I32X4GeU: return DoSimdBinop(GeMask); + case O::F32X4Eq: return DoSimdBinop(EqMask); + case O::F32X4Ne: return DoSimdBinop(NeMask); + case O::F32X4Lt: return DoSimdBinop(LtMask); + case O::F32X4Gt: return DoSimdBinop(GtMask); + case O::F32X4Le: return DoSimdBinop(LeMask); + case O::F32X4Ge: return DoSimdBinop(GeMask); + case O::F64X2Eq: return DoSimdBinop(EqMask); + case O::F64X2Ne: return DoSimdBinop(NeMask); + case O::F64X2Lt: return DoSimdBinop(LtMask); + case O::F64X2Gt: return DoSimdBinop(GtMask); + case O::F64X2Le: return DoSimdBinop(LeMask); + case O::F64X2Ge: return DoSimdBinop(GeMask); + + case O::V128Not: return DoSimdUnop(IntNot); + case O::V128And: return DoSimdBinop(IntAnd); + case O::V128Or: return DoSimdBinop(IntOr); + case O::V128Xor: return DoSimdBinop(IntXor); + case O::V128BitSelect: return DoSimdBitSelect(); + + case O::I8X16Neg: return DoSimdUnop(IntNeg); + case O::I8X16AnyTrue: return DoSimdIsTrue(); + case O::I8X16Bitmask: return DoSimdBitmask(); + case O::I8X16AllTrue: return DoSimdIsTrue(); + case O::I8X16Shl: return DoSimdShift(IntShl); + case O::I8X16ShrS: return DoSimdShift(IntShr); + case O::I8X16ShrU: return DoSimdShift(IntShr); + case O::I8X16Add: return DoSimdBinop(Add); + case O::I8X16AddSatS: return DoSimdBinop(IntAddSat); + case O::I8X16AddSatU: return DoSimdBinop(IntAddSat); + case O::I8X16Sub: return DoSimdBinop(Sub); + case O::I8X16SubSatS: return DoSimdBinop(IntSubSat); + case O::I8X16SubSatU: return DoSimdBinop(IntSubSat); + case O::I8X16MinS: return DoSimdBinop(IntMin); + case O::I8X16MinU: return DoSimdBinop(IntMin); + case O::I8X16MaxS: return DoSimdBinop(IntMax); + case O::I8X16MaxU: return DoSimdBinop(IntMax); + + case O::I16X8Neg: return DoSimdUnop(IntNeg); + case O::I16X8AnyTrue: return DoSimdIsTrue(); + case O::I16X8Bitmask: return DoSimdBitmask(); + case O::I16X8AllTrue: return DoSimdIsTrue(); + case O::I16X8Shl: return DoSimdShift(IntShl); + case O::I16X8ShrS: return DoSimdShift(IntShr); + case O::I16X8ShrU: return DoSimdShift(IntShr); + case O::I16X8Add: return DoSimdBinop(Add); + case O::I16X8AddSatS: return DoSimdBinop(IntAddSat); + case O::I16X8AddSatU: return DoSimdBinop(IntAddSat); + case O::I16X8Sub: return DoSimdBinop(Sub); + case O::I16X8SubSatS: return DoSimdBinop(IntSubSat); + case O::I16X8SubSatU: return DoSimdBinop(IntSubSat); + case O::I16X8Mul: return DoSimdBinop(Mul); + case O::I16X8MinS: return DoSimdBinop(IntMin); + case O::I16X8MinU: return DoSimdBinop(IntMin); + case O::I16X8MaxS: return DoSimdBinop(IntMax); + case O::I16X8MaxU: return DoSimdBinop(IntMax); + + case O::I32X4Neg: return DoSimdUnop(IntNeg); + case O::I32X4AnyTrue: return DoSimdIsTrue(); + case O::I32X4Bitmask: return DoSimdBitmask(); + case O::I32X4AllTrue: return DoSimdIsTrue(); + case O::I32X4Shl: return DoSimdShift(IntShl); + case O::I32X4ShrS: return DoSimdShift(IntShr); + case O::I32X4ShrU: return DoSimdShift(IntShr); + case O::I32X4Add: return DoSimdBinop(Add); + case O::I32X4Sub: return DoSimdBinop(Sub); + case O::I32X4Mul: return DoSimdBinop(Mul); + case O::I32X4MinS: return DoSimdBinop(IntMin); + case O::I32X4MinU: return DoSimdBinop(IntMin); + case O::I32X4MaxS: return DoSimdBinop(IntMax); + case O::I32X4MaxU: return DoSimdBinop(IntMax); + + case O::I64X2Neg: return DoSimdUnop(IntNeg); + case O::I64X2Shl: return DoSimdShift(IntShl); + case O::I64X2ShrS: return DoSimdShift(IntShr); + case O::I64X2ShrU: return DoSimdShift(IntShr); + case O::I64X2Add: return DoSimdBinop(Add); + case O::I64X2Sub: return DoSimdBinop(Sub); + case O::I64X2Mul: return DoSimdBinop(Mul); + + case O::F32X4Ceil: return DoSimdUnop(FloatCeil); + case O::F32X4Floor: return DoSimdUnop(FloatFloor); + case O::F32X4Trunc: return DoSimdUnop(FloatTrunc); + case O::F32X4Nearest: return DoSimdUnop(FloatNearest); + + case O::F64X2Ceil: return DoSimdUnop(FloatCeil); + case O::F64X2Floor: return DoSimdUnop(FloatFloor); + case O::F64X2Trunc: return DoSimdUnop(FloatTrunc); + case O::F64X2Nearest: return DoSimdUnop(FloatNearest); + + case O::F32X4Abs: return DoSimdUnop(FloatAbs); + case O::F32X4Neg: return DoSimdUnop(FloatNeg); + case O::F32X4Sqrt: return DoSimdUnop(FloatSqrt); + case O::F32X4Add: return DoSimdBinop(Add); + case O::F32X4Sub: return DoSimdBinop(Sub); + case O::F32X4Mul: return DoSimdBinop(Mul); + case O::F32X4Div: return DoSimdBinop(FloatDiv); + case O::F32X4Min: return DoSimdBinop(FloatMin); + case O::F32X4Max: return DoSimdBinop(FloatMax); + case O::F32X4PMin: return DoSimdBinop(FloatPMin); + case O::F32X4PMax: return DoSimdBinop(FloatPMax); + + case O::F64X2Abs: return DoSimdUnop(FloatAbs); + case O::F64X2Neg: return DoSimdUnop(FloatNeg); + case O::F64X2Sqrt: return DoSimdUnop(FloatSqrt); + case O::F64X2Add: return DoSimdBinop(Add); + case O::F64X2Sub: return DoSimdBinop(Sub); + case O::F64X2Mul: return DoSimdBinop(Mul); + case O::F64X2Div: return DoSimdBinop(FloatDiv); + case O::F64X2Min: return DoSimdBinop(FloatMin); + case O::F64X2Max: return DoSimdBinop(FloatMax); + case O::F64X2PMin: return DoSimdBinop(FloatPMin); + case O::F64X2PMax: return DoSimdBinop(FloatPMax); + + case O::I32X4TruncSatF32X4S: return DoSimdUnop(IntTruncSat); + case O::I32X4TruncSatF32X4U: return DoSimdUnop(IntTruncSat); + case O::F32X4ConvertI32X4S: return DoSimdUnop(Convert); + case O::F32X4ConvertI32X4U: return DoSimdUnop(Convert); + + case O::I8X16Swizzle: return DoSimdSwizzle(); + case O::I8X16Shuffle: return DoSimdShuffle(instr); + + case O::V128Load8Splat: return DoSimdLoadSplat(instr, out_trap); + case O::V128Load16Splat: return DoSimdLoadSplat(instr, out_trap); + case O::V128Load32Splat: return DoSimdLoadSplat(instr, out_trap); + case O::V128Load64Splat: return DoSimdLoadSplat(instr, out_trap); + + case O::I8X16NarrowI16X8S: return DoSimdNarrow(); + case O::I8X16NarrowI16X8U: return DoSimdNarrow(); + case O::I16X8NarrowI32X4S: return DoSimdNarrow(); + case O::I16X8NarrowI32X4U: return DoSimdNarrow(); + case O::I16X8WidenLowI8X16S: return DoSimdWiden(); + case O::I16X8WidenHighI8X16S: return DoSimdWiden(); + case O::I16X8WidenLowI8X16U: return DoSimdWiden(); + case O::I16X8WidenHighI8X16U: return DoSimdWiden(); + case O::I32X4WidenLowI16X8S: return DoSimdWiden(); + case O::I32X4WidenHighI16X8S: return DoSimdWiden(); + case O::I32X4WidenLowI16X8U: return DoSimdWiden(); + case O::I32X4WidenHighI16X8U: return DoSimdWiden(); + + case O::V128Load8X8S: return DoSimdLoadExtend(instr, out_trap); + case O::V128Load8X8U: return DoSimdLoadExtend(instr, out_trap); + case O::V128Load16X4S: return DoSimdLoadExtend(instr, out_trap); + case O::V128Load16X4U: return DoSimdLoadExtend(instr, out_trap); + case O::V128Load32X2S: return DoSimdLoadExtend(instr, out_trap); + case O::V128Load32X2U: return DoSimdLoadExtend(instr, out_trap); + + case O::V128Andnot: return DoSimdBinop(IntAndNot); + case O::I8X16AvgrU: return DoSimdBinop(IntAvgr); + case O::I16X8AvgrU: return DoSimdBinop(IntAvgr); + + case O::I8X16Abs: return DoSimdUnop(IntAbs); + case O::I16X8Abs: return DoSimdUnop(IntAbs); + case O::I32X4Abs: return DoSimdUnop(IntAbs); + + case O::AtomicFence: + case O::MemoryAtomicNotify: + case O::MemoryAtomicWait32: + case O::MemoryAtomicWait64: + return TRAP("not implemented"); + + case O::I32AtomicLoad: return DoAtomicLoad(instr, out_trap); + case O::I64AtomicLoad: return DoAtomicLoad(instr, out_trap); + case O::I32AtomicLoad8U: return DoAtomicLoad(instr, out_trap); + case O::I32AtomicLoad16U: return DoAtomicLoad(instr, out_trap); + case O::I64AtomicLoad8U: return DoAtomicLoad(instr, out_trap); + case O::I64AtomicLoad16U: return DoAtomicLoad(instr, out_trap); + case O::I64AtomicLoad32U: return DoAtomicLoad(instr, out_trap); + case O::I32AtomicStore: return DoAtomicStore(instr, out_trap); + case O::I64AtomicStore: return DoAtomicStore(instr, out_trap); + case O::I32AtomicStore8: return DoAtomicStore(instr, out_trap); + case O::I32AtomicStore16: return DoAtomicStore(instr, out_trap); + case O::I64AtomicStore8: return DoAtomicStore(instr, out_trap); + case O::I64AtomicStore16: return DoAtomicStore(instr, out_trap); + case O::I64AtomicStore32: return DoAtomicStore(instr, out_trap); + case O::I32AtomicRmwAdd: return DoAtomicRmw(Add, instr, out_trap); + case O::I64AtomicRmwAdd: return DoAtomicRmw(Add, instr, out_trap); + case O::I32AtomicRmw8AddU: return DoAtomicRmw(Add, instr, out_trap); + case O::I32AtomicRmw16AddU: return DoAtomicRmw(Add, instr, out_trap); + case O::I64AtomicRmw8AddU: return DoAtomicRmw(Add, instr, out_trap); + case O::I64AtomicRmw16AddU: return DoAtomicRmw(Add, instr, out_trap); + case O::I64AtomicRmw32AddU: return DoAtomicRmw(Add, instr, out_trap); + case O::I32AtomicRmwSub: return DoAtomicRmw(Sub, instr, out_trap); + case O::I64AtomicRmwSub: return DoAtomicRmw(Sub, instr, out_trap); + case O::I32AtomicRmw8SubU: return DoAtomicRmw(Sub, instr, out_trap); + case O::I32AtomicRmw16SubU: return DoAtomicRmw(Sub, instr, out_trap); + case O::I64AtomicRmw8SubU: return DoAtomicRmw(Sub, instr, out_trap); + case O::I64AtomicRmw16SubU: return DoAtomicRmw(Sub, instr, out_trap); + case O::I64AtomicRmw32SubU: return DoAtomicRmw(Sub, instr, out_trap); + case O::I32AtomicRmwAnd: return DoAtomicRmw(IntAnd, instr, out_trap); + case O::I64AtomicRmwAnd: return DoAtomicRmw(IntAnd, instr, out_trap); + case O::I32AtomicRmw8AndU: return DoAtomicRmw(IntAnd, instr, out_trap); + case O::I32AtomicRmw16AndU: return DoAtomicRmw(IntAnd, instr, out_trap); + case O::I64AtomicRmw8AndU: return DoAtomicRmw(IntAnd, instr, out_trap); + case O::I64AtomicRmw16AndU: return DoAtomicRmw(IntAnd, instr, out_trap); + case O::I64AtomicRmw32AndU: return DoAtomicRmw(IntAnd, instr, out_trap); + case O::I32AtomicRmwOr: return DoAtomicRmw(IntOr, instr, out_trap); + case O::I64AtomicRmwOr: return DoAtomicRmw(IntOr, instr, out_trap); + case O::I32AtomicRmw8OrU: return DoAtomicRmw(IntOr, instr, out_trap); + case O::I32AtomicRmw16OrU: return DoAtomicRmw(IntOr, instr, out_trap); + case O::I64AtomicRmw8OrU: return DoAtomicRmw(IntOr, instr, out_trap); + case O::I64AtomicRmw16OrU: return DoAtomicRmw(IntOr, instr, out_trap); + case O::I64AtomicRmw32OrU: return DoAtomicRmw(IntOr, instr, out_trap); + case O::I32AtomicRmwXor: return DoAtomicRmw(IntXor, instr, out_trap); + case O::I64AtomicRmwXor: return DoAtomicRmw(IntXor, instr, out_trap); + case O::I32AtomicRmw8XorU: return DoAtomicRmw(IntXor, instr, out_trap); + case O::I32AtomicRmw16XorU: return DoAtomicRmw(IntXor, instr, out_trap); + case O::I64AtomicRmw8XorU: return DoAtomicRmw(IntXor, instr, out_trap); + case O::I64AtomicRmw16XorU: return DoAtomicRmw(IntXor, instr, out_trap); + case O::I64AtomicRmw32XorU: return DoAtomicRmw(IntXor, instr, out_trap); + case O::I32AtomicRmwXchg: return DoAtomicRmw(Xchg, instr, out_trap); + case O::I64AtomicRmwXchg: return DoAtomicRmw(Xchg, instr, out_trap); + case O::I32AtomicRmw8XchgU: return DoAtomicRmw(Xchg, instr, out_trap); + case O::I32AtomicRmw16XchgU: return DoAtomicRmw(Xchg, instr, out_trap); + case O::I64AtomicRmw8XchgU: return DoAtomicRmw(Xchg, instr, out_trap); + case O::I64AtomicRmw16XchgU: return DoAtomicRmw(Xchg, instr, out_trap); + case O::I64AtomicRmw32XchgU: return DoAtomicRmw(Xchg, instr, out_trap); + + case O::I32AtomicRmwCmpxchg: return DoAtomicRmwCmpxchg(instr, out_trap); + case O::I64AtomicRmwCmpxchg: return DoAtomicRmwCmpxchg(instr, out_trap); + case O::I32AtomicRmw8CmpxchgU: return DoAtomicRmwCmpxchg(instr, out_trap); + case O::I32AtomicRmw16CmpxchgU: return DoAtomicRmwCmpxchg(instr, out_trap); + case O::I64AtomicRmw8CmpxchgU: return DoAtomicRmwCmpxchg(instr, out_trap); + case O::I64AtomicRmw16CmpxchgU: return DoAtomicRmwCmpxchg(instr, out_trap); + case O::I64AtomicRmw32CmpxchgU: return DoAtomicRmwCmpxchg(instr, out_trap); + + // The following opcodes are either never generated or should never be + // executed. + case O::Nop: + case O::Block: + case O::Loop: + case O::If: + case O::Else: + case O::End: + case O::ReturnCall: + case O::SelectT: + + case O::Try: + case O::Catch: + case O::CatchAll: + case O::Unwind: + case O::Delegate: + case O::Throw: + case O::Rethrow: + case O::InterpData: + case O::Invalid: + WABT_UNREACHABLE; + break; + } + + return RunResult::Ok; +} + +RunResult Thread::DoCall(const Func::Ptr& func, Trap::Ptr* out_trap) { + if (auto* host_func = dyn_cast(func.get())) { + auto& func_type = host_func->type(); + + Values params; + PopValues(func_type.params, ¶ms); + if (PushCall(*host_func, out_trap) == RunResult::Trap) { + return RunResult::Trap; + } + + Values results(func_type.results.size()); + if (Failed(host_func->Call(*this, params, results, out_trap))) { + return RunResult::Trap; + } + + PopCall(); + PushValues(func_type.results, results); + } else { + if (PushCall(*cast(func.get()), out_trap) == RunResult::Trap) { + return RunResult::Ok; + } + } + return RunResult::Ok; +} + +template +RunResult Thread::Load(Instr instr, T* out, Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]}; + u64 offset = PopPtr(memory); + TRAP_IF(Failed(memory->Load(offset, instr.imm_u32x2.snd, out)), + StringPrintf("out of bounds memory access: access at %" PRIu64 + "+%" PRIzd " >= max value %" PRIu64, + offset + instr.imm_u32x2.snd, sizeof(T), + memory->ByteSize())); + return RunResult::Ok; +} + +template +RunResult Thread::DoLoad(Instr instr, Trap::Ptr* out_trap) { + V val; + if (Load(instr, &val, out_trap) != RunResult::Ok) { + return RunResult::Trap; + } + Push(static_cast(val)); + return RunResult::Ok; +} + +template +RunResult Thread::DoStore(Instr instr, Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]}; + V val = static_cast(Pop()); + u64 offset = PopPtr(memory); + TRAP_IF(Failed(memory->Store(offset, instr.imm_u32x2.snd, val)), + StringPrintf("out of bounds memory access: access at %" PRIu64 + "+%" PRIzd " >= max value %" PRIu64, + offset + instr.imm_u32x2.snd, sizeof(V), + memory->ByteSize())); + return RunResult::Ok; +} + +template +RunResult Thread::DoUnop(UnopFunc f) { + Push(f(Pop())); + return RunResult::Ok; +} + +template +RunResult Thread::DoUnop(UnopTrapFunc f, Trap::Ptr* out_trap) { + T out; + std::string msg; + TRAP_IF(f(Pop(), &out, &msg) == RunResult::Trap, msg); + Push(out); + return RunResult::Ok; +} + +template +RunResult Thread::DoBinop(BinopFunc f) { + auto rhs = Pop(); + auto lhs = Pop(); + Push(f(lhs, rhs)); + return RunResult::Ok; +} + +template +RunResult Thread::DoBinop(BinopTrapFunc f, Trap::Ptr* out_trap) { + auto rhs = Pop(); + auto lhs = Pop(); + T out; + std::string msg; + TRAP_IF(f(lhs, rhs, &out, &msg) == RunResult::Trap, msg); + Push(out); + return RunResult::Ok; +} + +template +RunResult Thread::DoConvert(Trap::Ptr* out_trap) { + auto val = Pop(); + if (std::is_integral::value && std::is_floating_point::value) { + // Don't use std::isnan here because T may be a non-floating-point type. + TRAP_IF(IsNaN(val), "invalid conversion to integer"); + } + TRAP_UNLESS(CanConvert(val), "integer overflow"); + Push(Convert(val)); + return RunResult::Ok; +} + +template +RunResult Thread::DoReinterpret() { + Push(Bitcast(Pop())); + return RunResult::Ok; +} + +RunResult Thread::DoMemoryInit(Instr instr, Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]}; + auto&& data = inst_->datas()[instr.imm_u32x2.snd]; + auto size = Pop(); + auto src = Pop(); + auto dst = PopPtr(memory); + TRAP_IF(Failed(memory->Init(dst, data, src, size)), + "out of bounds memory access: memory.init out of bounds"); + return RunResult::Ok; +} + +RunResult Thread::DoDataDrop(Instr instr) { + inst_->datas()[instr.imm_u32].Drop(); + return RunResult::Ok; +} + +RunResult Thread::DoMemoryCopy(Instr instr, Trap::Ptr* out_trap) { + Memory::Ptr mem_dst{store_, inst_->memories()[instr.imm_u32x2.fst]}; + Memory::Ptr mem_src{store_, inst_->memories()[instr.imm_u32x2.snd]}; + auto size = PopPtr(mem_src); + auto src = PopPtr(mem_src); + auto dst = PopPtr(mem_dst); + // TODO: change to "out of bounds" + TRAP_IF(Failed(Memory::Copy(*mem_dst, dst, *mem_src, src, size)), + "out of bounds memory access: memory.copy out of bound"); + return RunResult::Ok; +} + +RunResult Thread::DoMemoryFill(Instr instr, Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32]}; + auto size = PopPtr(memory); + auto value = Pop(); + auto dst = PopPtr(memory); + TRAP_IF(Failed(memory->Fill(dst, value, size)), + "out of bounds memory access: memory.fill out of bounds"); + return RunResult::Ok; +} + +RunResult Thread::DoTableInit(Instr instr, Trap::Ptr* out_trap) { + Table::Ptr table{store_, inst_->tables()[instr.imm_u32x2.fst]}; + auto&& elem = inst_->elems()[instr.imm_u32x2.snd]; + auto size = Pop(); + auto src = Pop(); + auto dst = Pop(); + TRAP_IF(Failed(table->Init(store_, dst, elem, src, size)), + "out of bounds table access: table.init out of bounds"); + return RunResult::Ok; +} + +RunResult Thread::DoElemDrop(Instr instr) { + inst_->elems()[instr.imm_u32].Drop(); + return RunResult::Ok; +} + +RunResult Thread::DoTableCopy(Instr instr, Trap::Ptr* out_trap) { + Table::Ptr table_dst{store_, inst_->tables()[instr.imm_u32x2.fst]}; + Table::Ptr table_src{store_, inst_->tables()[instr.imm_u32x2.snd]}; + auto size = Pop(); + auto src = Pop(); + auto dst = Pop(); + TRAP_IF(Failed(Table::Copy(store_, *table_dst, dst, *table_src, src, size)), + "out of bounds table access: table.copy out of bounds"); + return RunResult::Ok; +} + +RunResult Thread::DoTableGet(Instr instr, Trap::Ptr* out_trap) { + Table::Ptr table{store_, inst_->tables()[instr.imm_u32]}; + auto index = Pop(); + Ref ref; + TRAP_IF(Failed(table->Get(index, &ref)), + StringPrintf( + "out of bounds table access: table.get at %u >= max value %u", + index, table->size())); + Push(ref); + return RunResult::Ok; +} + +RunResult Thread::DoTableSet(Instr instr, Trap::Ptr* out_trap) { + Table::Ptr table{store_, inst_->tables()[instr.imm_u32]}; + auto ref = Pop(); + auto index = Pop(); + TRAP_IF(Failed(table->Set(store_, index, ref)), + StringPrintf( + "out of bounds table access: table.set at %u >= max value %u", + index, table->size())); + return RunResult::Ok; +} + +RunResult Thread::DoTableGrow(Instr instr, Trap::Ptr* out_trap) { + Table::Ptr table{store_, inst_->tables()[instr.imm_u32]}; + u32 old_size = table->size(); + auto delta = Pop(); + auto ref = Pop(); + if (Failed(table->Grow(store_, delta, ref))) { + Push(-1); + } else { + Push(old_size); + } + return RunResult::Ok; +} + +RunResult Thread::DoTableSize(Instr instr) { + Table::Ptr table{store_, inst_->tables()[instr.imm_u32]}; + Push(table->size()); + return RunResult::Ok; +} + +RunResult Thread::DoTableFill(Instr instr, Trap::Ptr* out_trap) { + Table::Ptr table{store_, inst_->tables()[instr.imm_u32]}; + auto size = Pop(); + auto value = Pop(); + auto dst = Pop(); + TRAP_IF(Failed(table->Fill(store_, dst, value, size)), + "out of bounds table access: table.fill out of bounds"); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdSplat() { + auto val = Pop(); + R result; + std::fill(std::begin(result.v), std::end(result.v), val); + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdExtract(Instr instr) { + Push(Pop()[instr.imm_u8]); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdReplace(Instr instr) { + auto val = Pop(); + auto simd = Pop(); + simd[instr.imm_u8] = val; + Push(simd); + return RunResult::Ok; +} + +template struct Simd128; +template <> struct Simd128 { using Type = s8x16; }; +template <> struct Simd128 { using Type = u8x16; }; +template <> struct Simd128 { using Type = s16x8; }; +template <> struct Simd128 { using Type = u16x8; }; +template <> struct Simd128 { using Type = s32x4; }; +template <> struct Simd128 { using Type = u32x4; }; +template <> struct Simd128 { using Type = s64x2; }; +template <> struct Simd128 { using Type = u64x2; }; +template <> struct Simd128 { using Type = f32x4; }; +template <> struct Simd128 { using Type = f64x2; }; + +template +RunResult Thread::DoSimdUnop(UnopFunc f) { + using ST = typename Simd128::Type; + using SR = typename Simd128::Type; + auto val = Pop(); + SR result; + std::transform(std::begin(val.v), std::end(val.v), std::begin(result.v), f); + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdBinop(BinopFunc f) { + using ST = typename Simd128::Type; + using SR = typename Simd128::Type; + static_assert(ST::lanes == SR::lanes, "SIMD lanes don't match"); + auto rhs = Pop(); + auto lhs = Pop(); + SR result; + for (u8 i = 0; i < SR::lanes; ++i) { + result[i] = f(lhs[i], rhs[i]); + } + Push(result); + return RunResult::Ok; +} + +RunResult Thread::DoSimdBitSelect() { + using S = u64x2; + auto c = Pop(); + auto rhs = Pop(); + auto lhs = Pop(); + S result; + for (u8 i = 0; i < S::lanes; ++i) { + result[i] = (lhs[i] & c[i]) | (rhs[i] & ~c[i]); + } + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdIsTrue() { + using L = typename S::LaneType; + auto val = Pop(); + Push(std::count_if(std::begin(val.v), std::end(val.v), + [](L x) { return x != 0; }) >= count); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdBitmask() { + auto val = Pop(); + u32 result = 0; + for (u8 i = 0; i < S::lanes; ++i) { + if (val[i] < 0) { + result |= 1 << i; + } + } + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdShift(BinopFunc f) { + using ST = typename Simd128::Type; + using SR = typename Simd128::Type; + static_assert(ST::lanes == SR::lanes, "SIMD lanes don't match"); + auto amount = Pop(); + auto lhs = Pop(); + SR result; + for (u8 i = 0; i < SR::lanes; ++i) { + result[i] = f(lhs[i], amount); + } + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdLoadSplat(Instr instr, Trap::Ptr* out_trap) { + using L = typename S::LaneType; + L val; + if (Load(instr, &val, out_trap) != RunResult::Ok) { + return RunResult::Trap; + } + S result; + std::fill(std::begin(result.v), std::end(result.v), val); + Push(result); + return RunResult::Ok; +} + +RunResult Thread::DoSimdSwizzle() { + using S = u8x16; + auto rhs = Pop(); + auto lhs = Pop(); + S result; + for (u8 i = 0; i < S::lanes; ++i) { + result[i] = rhs[i] < S::lanes ? lhs[rhs[i]] : 0; + } + Push(result); + return RunResult::Ok; +} + +RunResult Thread::DoSimdShuffle(Instr instr) { + using S = u8x16; + auto sel = Bitcast(instr.imm_v128); + auto rhs = Pop(); + auto lhs = Pop(); + S result; + for (u8 i = 0; i < S::lanes; ++i) { + result[i] = + sel[i] < S::lanes ? lhs[sel[i]] : rhs[sel[i] - S::lanes]; + } + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdNarrow() { + using SL = typename S::LaneType; + using TL = typename T::LaneType; + auto rhs = Pop(); + auto lhs = Pop(); + S result; + for (u8 i = 0; i < T::lanes; ++i) { + result[i] = Saturate(lhs[i]); + } + for (u8 i = 0; i < T::lanes; ++i) { + result[T::lanes + i] = Saturate(rhs[i]); + } + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdWiden() { + auto val = Pop(); + S result; + for (u8 i = 0; i < S::lanes; ++i) { + result[i] = val[(low ? 0 : S::lanes) + i]; + } + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoSimdLoadExtend(Instr instr, Trap::Ptr* out_trap) { + T val; + if (Load(instr, &val, out_trap) != RunResult::Ok) { + return RunResult::Trap; + } + S result; + for (u8 i = 0; i < S::lanes; ++i) { + result[i] = val[i]; + } + Push(result); + return RunResult::Ok; +} + +template +RunResult Thread::DoAtomicLoad(Instr instr, Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]}; + u64 offset = PopPtr(memory); + V val; + TRAP_IF(Failed(memory->AtomicLoad(offset, instr.imm_u32x2.snd, &val)), + StringPrintf("invalid atomic access at %" PRIaddress "+%u", offset, + instr.imm_u32x2.snd)); + Push(static_cast(val)); + return RunResult::Ok; +} + +template +RunResult Thread::DoAtomicStore(Instr instr, Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]}; + V val = static_cast(Pop()); + u64 offset = PopPtr(memory); + TRAP_IF(Failed(memory->AtomicStore(offset, instr.imm_u32x2.snd, val)), + StringPrintf("invalid atomic access at %" PRIaddress "+%u", offset, + instr.imm_u32x2.snd)); + return RunResult::Ok; +} + +template +RunResult Thread::DoAtomicRmw(BinopFunc f, + Instr instr, + Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]}; + T val = static_cast(Pop()); + u64 offset = PopPtr(memory); + T old; + TRAP_IF(Failed(memory->AtomicRmw(offset, instr.imm_u32x2.snd, val, f, &old)), + StringPrintf("invalid atomic access at %" PRIaddress "+%u", offset, + instr.imm_u32x2.snd)); + Push(static_cast(old)); + return RunResult::Ok; +} + +template +RunResult Thread::DoAtomicRmwCmpxchg(Instr instr, Trap::Ptr* out_trap) { + Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]}; + V replace = static_cast(Pop()); + V expect = static_cast(Pop()); + V old; + u64 offset = PopPtr(memory); + TRAP_IF(Failed(memory->AtomicRmwCmpxchg(offset, instr.imm_u32x2.snd, expect, + replace, &old)), + StringPrintf("invalid atomic access at %" PRIaddress "+%u", offset, + instr.imm_u32x2.snd)); + Push(static_cast(old)); + return RunResult::Ok; +} + +Thread::TraceSource::TraceSource(Thread* thread) : thread_(thread) {} + +std::string Thread::TraceSource::Header(Istream::Offset offset) { + return StringPrintf("#%" PRIzd ". %4u: V:%-3" PRIzd, + thread_->frames_.size() - 1, offset, + thread_->values_.size()); +} + +std::string Thread::TraceSource::Pick(Index index, Instr instr) { + Value val = thread_->Pick(index); + const char* reftype; + // Estimate number of operands. + // TODO: Instead, record this accurately in opcode.def. + Index num_operands = 3; + for (Index i = 3; i >= 1; i--) { + if (instr.op.GetParamType(i) == ValueType::Void) { + num_operands--; + } else { + break; + } + } + auto type = index > num_operands + ? Type(ValueType::Void) + : instr.op.GetParamType(num_operands - index + 1); + if (type == ValueType::Void) { + // Void should never be displayed normally; we only expect to see it when + // the stack may have different a different type. This is likely to occur + // with an index; try to see which type we should expect. + switch (instr.op) { + case Opcode::GlobalSet: type = GetGlobalType(instr.imm_u32); break; + case Opcode::LocalSet: + case Opcode::LocalTee: type = GetLocalType(instr.imm_u32); break; + case Opcode::TableSet: + case Opcode::TableGrow: + case Opcode::TableFill: type = GetTableElementType(instr.imm_u32); break; + default: return "?"; + } + } + + switch (type) { + case ValueType::I32: return StringPrintf("%u", val.Get()); + case ValueType::I64: return StringPrintf("%" PRIu64, val.Get()); + case ValueType::F32: return StringPrintf("%g", val.Get()); + case ValueType::F64: return StringPrintf("%g", val.Get()); + case ValueType::V128: { + auto v = val.Get(); + return StringPrintf("0x%08x 0x%08x 0x%08x 0x%08x", v.u32(0), v.u32(1), + v.u32(2), v.u32(3)); + } + + case ValueType::FuncRef: reftype = "funcref"; break; + case ValueType::ExternRef: reftype = "externref"; break; + + default: + WABT_UNREACHABLE; + break; + } + + // Handle ref types. + return StringPrintf("%s:%" PRIzd, reftype, val.Get().index); +} + +ValueType Thread::TraceSource::GetLocalType(Index stack_slot) { + const Frame& frame = thread_->frames_.back(); + DefinedFunc::Ptr func{thread_->store_, frame.func}; + // When a function is called, the arguments are first pushed on the stack by + // the caller, then the new call frame is pushed (which caches the current + // height of the value stack). At that point, any local variables will be + // allocated on the stack. For example, a function that has two parameters + // and one local variable will have a stack like this: + // + // frame.values top of stack + // v v + // param1 param2 | local1 .......... + // + // When the instruction stream is generated, all local variable access is + // translated into a value relative to the top of the stack, counting up from + // 1. So in the previous example, if there are three values above the local + // variable, the stack looks like: + // + // param1 param2 | local1 value1 value2 value3 + // stack slot: 6 5 4 3 2 1 + // local index: 0 1 2 + // + // local1 can be accessed with stack_slot 4, and param1 can be accessed with + // stack_slot 6. The formula below takes these values into account to convert + // the stack_slot into a local index. + Index local_index = + (thread_->values_.size() - frame.values + func->type().params.size()) - + stack_slot; + return func->desc().GetLocalType(local_index); +} + +ValueType Thread::TraceSource::GetGlobalType(Index index) { + return thread_->mod_->desc().globals[index].type.type; +} + +ValueType Thread::TraceSource::GetTableElementType(Index index) { + return thread_->mod_->desc().tables[index].type.element; +} + +} // namespace interp +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.h new file mode 100644 index 0000000..95d8908 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.h @@ -0,0 +1,1205 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_INTERP_H_ +#define WABT_INTERP_H_ + +#include +#include +#include +#include +#include +#include + +#include "src/cast.h" +#include "src/common.h" +#include "src/feature.h" +#include "src/opcode.h" +#include "src/result.h" +#include "src/string-view.h" + +#include "src/interp/istream.h" + +namespace wabt { +namespace interp { + +class Store; +class Object; +class Trap; +class DataSegment; +class ElemSegment; +class Module; +class Instance; +class Thread; +template class RefPtr; + +using s8 = int8_t; +using u8 = uint8_t; +using s16 = int16_t; +using u16 = uint16_t; +using s32 = int32_t; +using u32 = uint32_t; +using Index = uint32_t; +using s64 = int64_t; +using u64 = uint64_t; +using f32 = float; +using f64 = double; + +using Buffer = std::vector; + +using ValueType = wabt::Type; +using ValueTypes = std::vector; + +template bool HasType(ValueType); +template void RequireType(ValueType); +bool IsReference(ValueType); +bool TypesMatch(ValueType expected, ValueType actual); + +using ExternKind = ExternalKind; +enum class Mutability { Const, Var }; +enum class EventAttr { Exception }; +using SegmentMode = SegmentKind; +enum class ElemKind { RefNull, RefFunc }; + +enum class ObjectKind { + Null, + Foreign, + Trap, + DefinedFunc, + HostFunc, + Table, + Memory, + Global, + Event, + Module, + Instance, + Thread, +}; + +const char* GetName(Mutability); +const char* GetName(ValueType); +const char* GetName(ExternKind); +const char* GetName(ObjectKind); + +enum class InitExprKind { + None, + I32, + I64, + F32, + F64, + V128, + GlobalGet, + RefNull, + RefFunc +}; + +struct InitExpr { + InitExprKind kind; + union { + u32 i32_; + u64 i64_; + f32 f32_; + f64 f64_; + v128 v128_; + Index index_; + Type type_; + }; +}; + +struct Ref { + static const Ref Null; + + Ref() = default; + explicit Ref(size_t index); + + friend bool operator==(Ref, Ref); + friend bool operator!=(Ref, Ref); + + size_t index; +}; +using RefVec = std::vector; + +template +struct Simd { + using LaneType = T; + static const u8 lanes = L; + + T v[L]; + + inline T& operator[](u8 idx) { +#if WABT_BIG_ENDIAN + idx = (~idx) & (L-1); +#endif + return v[idx]; + } + inline T operator[](u8 idx) const { +#if WABT_BIG_ENDIAN + idx = (~idx) & (L-1); +#endif + return v[idx]; + } +}; +using s8x16 = Simd; +using u8x16 = Simd; +using s16x8 = Simd; +using u16x8 = Simd; +using s32x4 = Simd; +using u32x4 = Simd; +using s64x2 = Simd; +using u64x2 = Simd; +using f32x4 = Simd; +using f64x2 = Simd; + +// Used for load extend instructions. +using s8x8 = Simd; +using u8x8 = Simd; +using s16x4 = Simd; +using u16x4 = Simd; +using s32x2 = Simd; +using u32x2 = Simd; + +//// Types //// + +bool CanGrow(const Limits&, u32 old_size, u32 delta, u32* new_size); +Result Match(const Limits& expected, + const Limits& actual, + std::string* out_msg); + +struct ExternType { + explicit ExternType(ExternKind); + virtual ~ExternType() {} + virtual std::unique_ptr Clone() const = 0; + + ExternKind kind; +}; + +struct FuncType : ExternType { + static const ExternKind skind = ExternKind::Func; + static bool classof(const ExternType* type); + + explicit FuncType(ValueTypes params, ValueTypes results); + + std::unique_ptr Clone() const override; + + friend Result Match(const FuncType& expected, + const FuncType& actual, + std::string* out_msg); + + ValueTypes params; + ValueTypes results; +}; + +struct TableType : ExternType { + static const ExternKind skind = ExternKind::Table; + static bool classof(const ExternType* type); + + explicit TableType(ValueType, Limits); + + std::unique_ptr Clone() const override; + + friend Result Match(const TableType& expected, + const TableType& actual, + std::string* out_msg); + + ValueType element; + Limits limits; +}; + +struct MemoryType : ExternType { + static const ExternKind skind = ExternKind::Memory; + static bool classof(const ExternType* type); + + explicit MemoryType(Limits); + + std::unique_ptr Clone() const override; + + friend Result Match(const MemoryType& expected, + const MemoryType& actual, + std::string* out_msg); + + Limits limits; +}; + +struct GlobalType : ExternType { + static const ExternKind skind = ExternKind::Global; + static bool classof(const ExternType* type); + + explicit GlobalType(ValueType, Mutability); + + std::unique_ptr Clone() const override; + + friend Result Match(const GlobalType& expected, + const GlobalType& actual, + std::string* out_msg); + + ValueType type; + Mutability mut; +}; + +struct EventType : ExternType { + static const ExternKind skind = ExternKind::Event; + static bool classof(const ExternType* type); + + explicit EventType(EventAttr, const ValueTypes&); + + std::unique_ptr Clone() const override; + + friend Result Match(const EventType& expected, + const EventType& actual, + std::string* out_msg); + + EventAttr attr; + ValueTypes signature; +}; + +struct ImportType { + explicit ImportType(std::string module, + std::string name, + std::unique_ptr); + ImportType(const ImportType&); + ImportType& operator=(const ImportType&); + + std::string module; + std::string name; + std::unique_ptr type; +}; + +struct ExportType { + explicit ExportType(std::string name, std::unique_ptr); + ExportType(const ExportType&); + ExportType& operator=(const ExportType&); + + std::string name; + std::unique_ptr type; +}; + +//// Structure //// + +struct ImportDesc { + ImportType type; +}; + +struct LocalDesc { + ValueType type; + u32 count; + // One past the last local index that has this type. For example, a vector of + // LocalDesc might look like: + // + // {{I32, 2, 2}, {I64, 3, 5}, {F32, 1, 6}, ...} + // + // This makes it possible to use a binary search to find the type of a local + // at a given index. + u32 end; +}; + +struct FuncDesc { + // Includes params. + ValueType GetLocalType(Index) const; + + FuncType type; + std::vector locals; + u32 code_offset; +}; + +struct TableDesc { + TableType type; +}; + +struct MemoryDesc { + MemoryType type; +}; + +struct GlobalDesc { + GlobalType type; + InitExpr init; +}; + +struct EventDesc { + EventType type; +}; + +struct ExportDesc { + ExportType type; + Index index; +}; + +struct StartDesc { + Index func_index; +}; + +struct DataDesc { + Buffer data; + SegmentMode mode; + Index memory_index; + InitExpr offset; +}; + +struct ElemExpr { + ElemKind kind; + Index index; +}; + +struct ElemDesc { + std::vector elements; + ValueType type; + SegmentMode mode; + Index table_index; + InitExpr offset; +}; + +struct ModuleDesc { + std::vector func_types; + std::vector imports; + std::vector funcs; + std::vector tables; + std::vector memories; + std::vector globals; + std::vector events; + std::vector exports; + std::vector starts; + std::vector elems; + std::vector datas; + Istream istream; +}; + +//// Runtime //// + +struct Frame { + explicit Frame(Ref func, u32 values, u32 offset, Instance*, Module*); + + void Mark(Store&); + + Ref func; + u32 values; // Height of the value stack at this activation. + u32 offset; // Istream offset; either the return PC, or the current PC. + + // Cached for convenience. Both are null if func is a HostFunc. + Instance* inst; + Module* mod; +}; + +template +class FreeList { + public: + using Index = size_t; + + template + Index New(Args&&...); + void Delete(Index); + + bool IsUsed(Index) const; + + const T& Get(Index) const; + T& Get(Index); + + Index size() const; // 1 greater than the maximum index. + Index count() const; // The number of used elements. + + private: + // TODO: Optimize memory layout? We could probably store all of this + // information in one uintptr_t. + // + // For example, when T is a pointer to an Object (e.g. Store::ObjectList), we + // can assume alignment to 4 bytes at least. Given a 32-bit pointer, we can + // expect the following layout: + // + // nnnnnnnn nnnnnnnn nnnnnnnn nnnnnnn0 f + // + // where: + // f: "is_free": 0 when the payload is of type T + // 1 when the payload is the index of the next free object + // n: the payload + // + // When T is a Ref (see Store::RootList below), we'd need to store the + // "is_free" bit in most-significant bit instead. + // + std::vector list_; + std::vector free_; + std::vector is_free_; +}; + +class Store { + public: + using ObjectList = FreeList>; + using RootList = FreeList; + + explicit Store(const Features& = Features{}); + + bool IsValid(Ref) const; + bool HasValueType(Ref, ValueType) const; + template + bool Is(Ref) const; + + template + RefPtr Alloc(Args&&...); + template + Result Get(Ref, RefPtr* out); + template + RefPtr UnsafeGet(Ref); + + RootList::Index NewRoot(Ref); + RootList::Index CopyRoot(RootList::Index); + void DeleteRoot(RootList::Index); + + void Collect(); + void Mark(Ref); + void Mark(const RefVec&); + + ObjectList::Index object_count() const; + + const Features& features() const; + + private: + template + friend class RefPtr; + + Features features_; + ObjectList objects_; + RootList roots_; + std::vector marks_; +}; + +template +class RefPtr { + public: + RefPtr(); + RefPtr(Store&, Ref); + RefPtr(const RefPtr&); + RefPtr& operator=(const RefPtr&); + RefPtr(RefPtr&&); + RefPtr& operator=(RefPtr&&); + ~RefPtr(); + + template + RefPtr(const RefPtr&); + template + RefPtr& operator=(const RefPtr&); + template + RefPtr(RefPtr&&); + template + RefPtr& operator=(RefPtr&&); + + template + RefPtr As(); + + bool empty() const; + void reset(); + + T* get() const; + T* operator->() const; + T& operator*() const; + explicit operator bool() const; + + Ref ref() const; + Store* store() const; + + template + friend bool operator==(const RefPtr& lhs, const RefPtr& rhs); + template + friend bool operator!=(const RefPtr& lhs, const RefPtr& rhs); + + private: + template + friend class RefPtr; + + T* obj_; + Store* store_; + Store::RootList::Index root_index_; +}; + +struct Value { + static Value WABT_VECTORCALL Make(s32); + static Value WABT_VECTORCALL Make(u32); + static Value WABT_VECTORCALL Make(s64); + static Value WABT_VECTORCALL Make(u64); + static Value WABT_VECTORCALL Make(f32); + static Value WABT_VECTORCALL Make(f64); + static Value WABT_VECTORCALL Make(v128); + static Value WABT_VECTORCALL Make(Ref); + template + static Value WABT_VECTORCALL Make(Simd); + + template + T WABT_VECTORCALL Get() const; + template + void WABT_VECTORCALL Set(T); + + private: + union { + u32 i32_; + u64 i64_; + f32 f32_; + f64 f64_; + v128 v128_; + Ref ref_; + }; + + public: +#ifndef NDEBUG + Value() : v128_(0, 0, 0, 0), type(ValueType::Any) {} + void SetType(ValueType t) { type = t; } + void CheckType(ValueType t) const { + // Sadly we must allow Any here, since locals may be uninitialized. + // Alternatively we could modify InterpAlloca to set the type. + assert(t == type || type == ValueType::Any); + } + ValueType type; +#else + Value() : v128_(0, 0, 0, 0) {} + void SetType(ValueType) {} + void CheckType(ValueType) const {} +#endif +}; +using Values = std::vector; + +struct TypedValue { + ValueType type; + Value value; +}; +using TypedValues = std::vector; + +using Finalizer = std::function; + +class Object { + public: + static bool classof(const Object* obj); + static const char* GetTypeName() { return "Object"; } + using Ptr = RefPtr; + + Object(const Object&) = delete; + Object& operator=(const Object&) = delete; + + virtual ~Object(); + + ObjectKind kind() const; + Ref self() const; + + void* host_info() const; + void set_host_info(void*); + + Finalizer get_finalizer() const; + void set_finalizer(Finalizer); + + protected: + friend Store; + explicit Object(ObjectKind); + virtual void Mark(Store&) {} + + ObjectKind kind_; + Finalizer finalizer_ = nullptr; + void* host_info_ = nullptr; + Ref self_ = Ref::Null; +}; + +class Foreign : public Object { + public: + static const ObjectKind skind = ObjectKind::Foreign; + static bool classof(const Object* obj); + static const char* GetTypeName() { return "Foreign"; } + using Ptr = RefPtr; + + static Foreign::Ptr New(Store&, void*); + + void* ptr(); + + private: + friend Store; + explicit Foreign(Store&, void*); + void Mark(Store&) override; + + void* ptr_; +}; + +class Trap : public Object { + public: + static const ObjectKind skind = ObjectKind::Trap; + static bool classof(const Object* obj); + using Ptr = RefPtr; + + static Trap::Ptr New(Store&, + const std::string& msg, + const std::vector& trace = std::vector()); + + std::string message() const; + + private: + friend Store; + explicit Trap(Store&, + const std::string& msg, + const std::vector& trace = std::vector()); + void Mark(Store&) override; + + std::string message_; + std::vector trace_; +}; + +class Extern : public Object { + public: + static bool classof(const Object* obj); + static const char* GetTypeName() { return "Foreign"; } + using Ptr = RefPtr; + + virtual Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) = 0; + virtual const ExternType& extern_type() = 0; + + protected: + friend Store; + explicit Extern(ObjectKind); + + template + Result MatchImpl(Store&, + const ImportType&, + const T& actual, + Trap::Ptr* out_trap); +}; + +class Func : public Extern { + public: + static bool classof(const Object* obj); + using Ptr = RefPtr; + + Result Call(Thread& thread, + const Values& params, + Values& results, + Trap::Ptr* out_trap); + + // Convenience function that creates new Thread. + Result Call(Store&, + const Values& params, + Values& results, + Trap::Ptr* out_trap, + Stream* = nullptr); + + const ExternType& extern_type() override; + const FuncType& type() const; + + protected: + explicit Func(ObjectKind, FuncType); + virtual Result DoCall(Thread& thread, + const Values& params, + Values& results, + Trap::Ptr* out_trap) = 0; + + FuncType type_; +}; + +class DefinedFunc : public Func { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::DefinedFunc; + static const char* GetTypeName() { return "DefinedFunc"; } + using Ptr = RefPtr; + + static DefinedFunc::Ptr New(Store&, Ref instance, FuncDesc); + + Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; + + Ref instance() const; + const FuncDesc& desc() const; + + protected: + Result DoCall(Thread& thread, + const Values& params, + Values& results, + Trap::Ptr* out_trap) override; + + private: + friend Store; + explicit DefinedFunc(Store&, Ref instance, FuncDesc); + void Mark(Store&) override; + + Ref instance_; + FuncDesc desc_; +}; + +class HostFunc : public Func { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::HostFunc; + static const char* GetTypeName() { return "HostFunc"; } + using Ptr = RefPtr; + + using Callback = std::function; + + static HostFunc::Ptr New(Store&, FuncType, Callback); + + Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; + + protected: + Result DoCall(Thread& thread, + const Values& params, + Values& results, + Trap::Ptr* out_trap) override; + + private: + friend Store; + friend Thread; + explicit HostFunc(Store&, FuncType, Callback); + void Mark(Store&) override; + + Callback callback_; +}; + +class Table : public Extern { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Table; + static const char* GetTypeName() { return "Table"; } + using Ptr = RefPtr
; + + static Table::Ptr New(Store&, TableType); + + Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; + + bool IsValidRange(u32 offset, u32 size) const; + + Result Get(u32 offset, Ref* out) const; + Result Set(Store&, u32 offset, Ref); + Result Grow(Store&, u32 count, Ref); + Result Fill(Store&, u32 offset, Ref, u32 size); + Result Init(Store&, + u32 dst_offset, + const ElemSegment&, + u32 src_offset, + u32 size); + static Result Copy(Store&, + Table& dst, + u32 dst_offset, + const Table& src, + u32 src_offset, + u32 size); + + // Unsafe API. + Ref UnsafeGet(u32 offset) const; + + const ExternType& extern_type() override; + const TableType& type() const; + const RefVec& elements() const; + u32 size() const; + + private: + friend Store; + explicit Table(Store&, TableType); + void Mark(Store&) override; + + TableType type_; + RefVec elements_; +}; + +class Memory : public Extern { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Memory; + static const char* GetTypeName() { return "Memory"; } + using Ptr = RefPtr; + + static Memory::Ptr New(Store&, MemoryType); + + Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; + + bool IsValidAccess(u64 offset, u64 addend, u64 size) const; + bool IsValidAtomicAccess(u64 offset, u64 addend, u64 size) const; + + template + Result Load(u64 offset, u64 addend, T* out) const; + template + Result WABT_VECTORCALL Store(u64 offset, u64 addend, T); + Result Grow(u64 pages); + Result Fill(u64 offset, u8 value, u64 size); + Result Init(u64 dst_offset, const DataSegment&, u64 src_offset, u64 size); + static Result Copy(Memory& dst, + u64 dst_offset, + const Memory& src, + u64 src_offset, + u64 size); + + // Fake atomics; just checks alignment. + template + Result AtomicLoad(u64 offset, u64 addend, T* out) const; + template + Result AtomicStore(u64 offset, u64 addend, T); + template + Result AtomicRmw(u64 offset, u64 addend, T, F&& func, T* out); + template + Result AtomicRmwCmpxchg(u64 offset, u64 addend, T expect, T replace, T* out); + + u64 ByteSize() const; + u64 PageSize() const; + + // Unsafe API. + template + T WABT_VECTORCALL UnsafeLoad(u64 offset, u64 addend) const; + u8* UnsafeData(); + + const ExternType& extern_type() override; + const MemoryType& type() const; + + private: + friend class Store; + explicit Memory(class Store&, MemoryType); + void Mark(class Store&) override; + + MemoryType type_; + Buffer data_; + u64 pages_; +}; + +class Global : public Extern { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Global; + static const char* GetTypeName() { return "Global"; } + using Ptr = RefPtr; + + static Global::Ptr New(Store&, GlobalType, Value); + + Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; + + Value Get() const; + template + Result Get(T* out) const; + template + Result WABT_VECTORCALL Set(T); + Result Set(Store&, Ref); + + template + T WABT_VECTORCALL UnsafeGet() const; + void UnsafeSet(Value); + + const ExternType& extern_type() override; + const GlobalType& type() const; + + private: + friend Store; + explicit Global(Store&, GlobalType, Value); + void Mark(Store&) override; + + GlobalType type_; + Value value_; +}; + +class Event : public Extern { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Event; + static const char* GetTypeName() { return "Event"; } + using Ptr = RefPtr; + + static Event::Ptr New(Store&, EventType); + + Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override; + + const ExternType& extern_type() override; + const EventType& type() const; + + private: + friend Store; + explicit Event(Store&, EventType); + void Mark(Store&) override; + + EventType type_; +}; + +class ElemSegment { + public: + explicit ElemSegment(const ElemDesc*, RefPtr&); + + bool IsValidRange(u32 offset, u32 size) const; + void Drop(); + + const ElemDesc& desc() const; + const RefVec& elements() const; + u32 size() const; + + private: + friend Instance; + void Mark(Store&); + + const ElemDesc* desc_; // Borrowed from the Module. + RefVec elements_; +}; + +class DataSegment { + public: + explicit DataSegment(const DataDesc*); + + bool IsValidRange(u64 offset, u64 size) const; + void Drop(); + + const DataDesc& desc() const; + u64 size() const; + + private: + const DataDesc* desc_; // Borrowed from the Module. + u64 size_; +}; + +class Module : public Object { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Module; + static const char* GetTypeName() { return "Module"; } + using Ptr = RefPtr; + + static Module::Ptr New(Store&, ModuleDesc); + + const ModuleDesc& desc() const; + const std::vector& import_types() const; + const std::vector& export_types() const; + + private: + friend Store; + friend Instance; + explicit Module(Store&, ModuleDesc); + void Mark(Store&) override; + + ModuleDesc desc_; + std::vector import_types_; + std::vector export_types_; +}; + +class Instance : public Object { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Instance; + static const char* GetTypeName() { return "Instance"; } + using Ptr = RefPtr; + + static Instance::Ptr Instantiate(Store&, + Ref module, + const RefVec& imports, + Trap::Ptr* out_trap); + + Ref module() const; + const RefVec& imports() const; + const RefVec& funcs() const; + const RefVec& tables() const; + const RefVec& memories() const; + const RefVec& globals() const; + const RefVec& events() const; + const RefVec& exports() const; + const std::vector& elems() const; + std::vector& elems(); + const std::vector& datas() const; + std::vector& datas(); + + private: + friend Store; + friend ElemSegment; + friend DataSegment; + explicit Instance(Store&, Ref module); + void Mark(Store&) override; + + Value ResolveInitExpr(Store&, InitExpr); + + Ref module_; + RefVec imports_; + RefVec funcs_; + RefVec tables_; + RefVec memories_; + RefVec globals_; + RefVec events_; + RefVec exports_; + std::vector elems_; + std::vector datas_; +}; + +enum class RunResult { + Ok, + Return, + Trap, +}; + +// TODO: Kinda weird to have a thread as an object, but it makes reference +// marking simpler. +class Thread : public Object { + public: + static bool classof(const Object* obj); + static const ObjectKind skind = ObjectKind::Thread; + static const char* GetTypeName() { return "Thread"; } + using Ptr = RefPtr; + + struct Options { + static const u32 kDefaultValueStackSize = 64 * 1024 / sizeof(Value); + static const u32 kDefaultCallStackSize = 64 * 1024 / sizeof(Frame); + + u32 value_stack_size = kDefaultValueStackSize; + u32 call_stack_size = kDefaultCallStackSize; + Stream* trace_stream = nullptr; + }; + + static Thread::Ptr New(Store&, const Options&); + + RunResult Run(Trap::Ptr* out_trap); + RunResult Run(int num_instructions, Trap::Ptr* out_trap); + RunResult Step(Trap::Ptr* out_trap); + + Store& store(); + + Instance* GetCallerInstance(); + + private: + friend Store; + friend DefinedFunc; + + struct TraceSource; + + explicit Thread(Store&, const Options&); + void Mark(Store&) override; + + RunResult PushCall(Ref func, u32 offset, Trap::Ptr* out_trap); + RunResult PushCall(const DefinedFunc&, Trap::Ptr* out_trap); + RunResult PushCall(const HostFunc&, Trap::Ptr* out_trap); + RunResult PopCall(); + RunResult DoCall(const Func::Ptr&, Trap::Ptr* out_trap); + RunResult DoReturnCall(const Func::Ptr&, Trap::Ptr* out_trap); + + void PushValues(const ValueTypes&, const Values&); + void PopValues(const ValueTypes&, Values*); + + Value& Pick(Index); + + template + T WABT_VECTORCALL Pop(); + Value Pop(); + u64 PopPtr(const Memory::Ptr& memory); + + template + void WABT_VECTORCALL Push(T); + void Push(Value); + void Push(Ref); + + template + using UnopFunc = R WABT_VECTORCALL(T); + template + using UnopTrapFunc = RunResult WABT_VECTORCALL(T, R*, std::string*); + template + using BinopFunc = R WABT_VECTORCALL(T, T); + template + using BinopTrapFunc = RunResult WABT_VECTORCALL(T, T, R*, std::string*); + + template + RunResult DoUnop(UnopFunc); + template + RunResult DoUnop(UnopTrapFunc, Trap::Ptr* out_trap); + template + RunResult DoBinop(BinopFunc); + template + RunResult DoBinop(BinopTrapFunc, Trap::Ptr* out_trap); + + template + RunResult DoConvert(Trap::Ptr* out_trap); + template + RunResult DoReinterpret(); + + template + RunResult Load(Instr, T* out, Trap::Ptr* out_trap); + template + RunResult DoLoad(Instr, Trap::Ptr* out_trap); + template + RunResult DoStore(Instr, Trap::Ptr* out_trap); + + RunResult DoMemoryInit(Instr, Trap::Ptr* out_trap); + RunResult DoDataDrop(Instr); + RunResult DoMemoryCopy(Instr, Trap::Ptr* out_trap); + RunResult DoMemoryFill(Instr, Trap::Ptr* out_trap); + + RunResult DoTableInit(Instr, Trap::Ptr* out_trap); + RunResult DoElemDrop(Instr); + RunResult DoTableCopy(Instr, Trap::Ptr* out_trap); + RunResult DoTableGet(Instr, Trap::Ptr* out_trap); + RunResult DoTableSet(Instr, Trap::Ptr* out_trap); + RunResult DoTableGrow(Instr, Trap::Ptr* out_trap); + RunResult DoTableSize(Instr); + RunResult DoTableFill(Instr, Trap::Ptr* out_trap); + + template + RunResult DoSimdSplat(); + template + RunResult DoSimdExtract(Instr); + template + RunResult DoSimdReplace(Instr); + + template + RunResult DoSimdUnop(UnopFunc); + template + RunResult DoSimdBinop(BinopFunc); + RunResult DoSimdBitSelect(); + template + RunResult DoSimdIsTrue(); + template + RunResult DoSimdBitmask(); + template + RunResult DoSimdShift(BinopFunc); + template + RunResult DoSimdLoadSplat(Instr, Trap::Ptr* out_trap); + RunResult DoSimdSwizzle(); + RunResult DoSimdShuffle(Instr); + template + RunResult DoSimdNarrow(); + template + RunResult DoSimdWiden(); + template + RunResult DoSimdLoadExtend(Instr, Trap::Ptr* out_trap); + + template + RunResult DoAtomicLoad(Instr, Trap::Ptr* out_trap); + template + RunResult DoAtomicStore(Instr, Trap::Ptr* out_trap); + template + RunResult DoAtomicRmw(BinopFunc, Instr, Trap::Ptr* out_trap); + template + RunResult DoAtomicRmwCmpxchg(Instr, Trap::Ptr* out_trap); + + RunResult StepInternal(Trap::Ptr* out_trap); + + std::vector frames_; + std::vector values_; + std::vector refs_; // Index into values_. + + // Cached for convenience. + Store& store_; + Instance* inst_ = nullptr; + Module* mod_ = nullptr; + + // Tracing. + Stream* trace_stream_; + std::unique_ptr trace_source_; +}; + +struct Thread::TraceSource : Istream::TraceSource { + public: + explicit TraceSource(Thread*); + std::string Header(Istream::Offset) override; + std::string Pick(Index, Instr) override; + + private: + ValueType GetLocalType(Index); + ValueType GetGlobalType(Index); + ValueType GetTableElementType(Index); + + Thread* thread_; +}; + +} // namespace interp +} // namespace wabt + +#include "src/interp/interp-inl.h" + +#endif // WABT_INTERP_H_ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.cc new file mode 100644 index 0000000..6e95667 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.cc @@ -0,0 +1,885 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/interp/istream.h" + +#include + +namespace wabt { +namespace interp { + +template +void WABT_VECTORCALL Istream::EmitAt(Offset offset, T val) { + u32 new_size = offset + sizeof(T); + if (new_size > data_.size()) { + data_.resize(new_size); + } + memcpy(data_.data() + offset, &val, sizeof(val)); +} + +template +void WABT_VECTORCALL Istream::EmitInternal(T val) { + EmitAt(end(), val); +} + +void Istream::Emit(u32 val) { + EmitInternal(val); +} + +void Istream::Emit(Opcode::Enum op) { + EmitInternal(static_cast(op)); +} + +void Istream::Emit(Opcode::Enum op, u8 val) { + Emit(op); + EmitInternal(val); +} + +void Istream::Emit(Opcode::Enum op, u32 val) { + Emit(op); + EmitInternal(val); +} + +void Istream::Emit(Opcode::Enum op, u64 val) { + Emit(op); + EmitInternal(val); +} + +void Istream::Emit(Opcode::Enum op, v128 val) { + Emit(op); + EmitInternal(val); +} + +void Istream::Emit(Opcode::Enum op, u32 val1, u32 val2) { + Emit(op); + EmitInternal(val1); + EmitInternal(val2); +} + +void Istream::EmitDropKeep(u32 drop, u32 keep) { + if (drop > 0) { + if (drop == 1 && keep == 0) { + Emit(Opcode::Drop); + } else { + Emit(Opcode::InterpDropKeep, drop, keep); + } + } +} + +Istream::Offset Istream::EmitFixupU32() { + auto result = end(); + EmitInternal(kInvalidOffset); + return result; +} + +void Istream::ResolveFixupU32(Offset fixup_offset) { + EmitAt(fixup_offset, end()); +} + +Istream::Offset Istream::end() const { + return static_cast(data_.size()); +} + +template +T WABT_VECTORCALL Istream::ReadAt(Offset* offset) const { + assert(*offset + sizeof(T) <= data_.size()); + T result; + memcpy(&result, data_.data() + *offset, sizeof(T)); + *offset += sizeof(T); + return result; +} + +Instr Istream::Read(Offset* offset) const { + Instr instr; + instr.op = static_cast(ReadAt(offset)); + + switch (instr.op) { + case Opcode::Drop: + case Opcode::Nop: + case Opcode::Return: + case Opcode::Unreachable: + case Opcode::RefNull: + // 0 immediates, 0 operands. + instr.kind = InstrKind::Imm_0_Op_0; + break; + + case Opcode::F32Abs: + case Opcode::F32Ceil: + case Opcode::F32ConvertI32S: + case Opcode::F32ConvertI32U: + case Opcode::F32ConvertI64S: + case Opcode::F32ConvertI64U: + case Opcode::F32DemoteF64: + case Opcode::F32Floor: + case Opcode::F32Nearest: + case Opcode::F32Neg: + case Opcode::F32ReinterpretI32: + case Opcode::F32Sqrt: + case Opcode::F32Trunc: + case Opcode::F32X4Abs: + case Opcode::F32X4Ceil: + case Opcode::F32X4ConvertI32X4S: + case Opcode::F32X4ConvertI32X4U: + case Opcode::F32X4Floor: + case Opcode::F32X4Nearest: + case Opcode::F32X4Neg: + case Opcode::F32X4Splat: + case Opcode::F32X4Sqrt: + case Opcode::F32X4Trunc: + case Opcode::F64Abs: + case Opcode::F64Ceil: + case Opcode::F64ConvertI32S: + case Opcode::F64ConvertI32U: + case Opcode::F64ConvertI64S: + case Opcode::F64ConvertI64U: + case Opcode::F64Floor: + case Opcode::F64Nearest: + case Opcode::F64Neg: + case Opcode::F64PromoteF32: + case Opcode::F64ReinterpretI64: + case Opcode::F64Sqrt: + case Opcode::F64Trunc: + case Opcode::F64X2Abs: + case Opcode::F64X2Ceil: + case Opcode::F64X2Floor: + case Opcode::F64X2Nearest: + case Opcode::F64X2Neg: + case Opcode::F64X2Splat: + case Opcode::F64X2Sqrt: + case Opcode::F64X2Trunc: + case Opcode::I16X8AllTrue: + case Opcode::I16X8AnyTrue: + case Opcode::I16X8Bitmask: + case Opcode::I16X8Neg: + case Opcode::I16X8Splat: + case Opcode::I16X8WidenHighI8X16S: + case Opcode::I16X8WidenHighI8X16U: + case Opcode::I16X8WidenLowI8X16S: + case Opcode::I16X8WidenLowI8X16U: + case Opcode::I32Clz: + case Opcode::I32Ctz: + case Opcode::I32Eqz: + case Opcode::I32Extend16S: + case Opcode::I32Extend8S: + case Opcode::I32Popcnt: + case Opcode::I32ReinterpretF32: + case Opcode::I32TruncF32S: + case Opcode::I32TruncF32U: + case Opcode::I32TruncF64S: + case Opcode::I32TruncF64U: + case Opcode::I32TruncSatF32S: + case Opcode::I32TruncSatF32U: + case Opcode::I32TruncSatF64S: + case Opcode::I32TruncSatF64U: + case Opcode::I32WrapI64: + case Opcode::I32X4AllTrue: + case Opcode::I32X4AnyTrue: + case Opcode::I32X4Bitmask: + case Opcode::I32X4Neg: + case Opcode::I32X4Splat: + case Opcode::I32X4TruncSatF32X4S: + case Opcode::I32X4TruncSatF32X4U: + case Opcode::I32X4WidenHighI16X8S: + case Opcode::I32X4WidenHighI16X8U: + case Opcode::I32X4WidenLowI16X8S: + case Opcode::I32X4WidenLowI16X8U: + case Opcode::I64Clz: + case Opcode::I64Ctz: + case Opcode::I64Eqz: + case Opcode::I64Extend16S: + case Opcode::I64Extend32S: + case Opcode::I64Extend8S: + case Opcode::I64ExtendI32S: + case Opcode::I64ExtendI32U: + case Opcode::I64Popcnt: + case Opcode::I64ReinterpretF64: + case Opcode::I64TruncF32S: + case Opcode::I64TruncF32U: + case Opcode::I64TruncF64S: + case Opcode::I64TruncF64U: + case Opcode::I64TruncSatF32S: + case Opcode::I64TruncSatF32U: + case Opcode::I64TruncSatF64S: + case Opcode::I64TruncSatF64U: + case Opcode::I64X2Neg: + case Opcode::I64X2Splat: + case Opcode::I8X16AllTrue: + case Opcode::I8X16AnyTrue: + case Opcode::I8X16Bitmask: + case Opcode::I8X16Neg: + case Opcode::I8X16Splat: + case Opcode::RefIsNull: + case Opcode::V128Not: + case Opcode::I8X16Abs: + case Opcode::I16X8Abs: + case Opcode::I32X4Abs: + // 0 immediates, 1 operand. + instr.kind = InstrKind::Imm_0_Op_1; + break; + + case Opcode::F32Add: + case Opcode::F32Copysign: + case Opcode::F32Div: + case Opcode::F32Eq: + case Opcode::F32Ge: + case Opcode::F32Gt: + case Opcode::F32Le: + case Opcode::F32Lt: + case Opcode::F32Max: + case Opcode::F32Min: + case Opcode::F32Mul: + case Opcode::F32Ne: + case Opcode::F32Sub: + case Opcode::F32X4Add: + case Opcode::F32X4Div: + case Opcode::F32X4Eq: + case Opcode::F32X4Ge: + case Opcode::F32X4Gt: + case Opcode::F32X4Le: + case Opcode::F32X4Lt: + case Opcode::F32X4Max: + case Opcode::F32X4Min: + case Opcode::F32X4Mul: + case Opcode::F32X4Ne: + case Opcode::F32X4PMax: + case Opcode::F32X4PMin: + case Opcode::F32X4Sub: + case Opcode::F64Add: + case Opcode::F64Copysign: + case Opcode::F64Div: + case Opcode::F64Eq: + case Opcode::F64Ge: + case Opcode::F64Gt: + case Opcode::F64Le: + case Opcode::F64Lt: + case Opcode::F64Max: + case Opcode::F64Min: + case Opcode::F64Mul: + case Opcode::F64Ne: + case Opcode::F64Sub: + case Opcode::F64X2Add: + case Opcode::F64X2Div: + case Opcode::F64X2Eq: + case Opcode::F64X2Ge: + case Opcode::F64X2Gt: + case Opcode::F64X2Le: + case Opcode::F64X2Lt: + case Opcode::F64X2Max: + case Opcode::F64X2Min: + case Opcode::F64X2Mul: + case Opcode::F64X2Ne: + case Opcode::F64X2PMax: + case Opcode::F64X2PMin: + case Opcode::F64X2Sub: + case Opcode::I16X8Add: + case Opcode::I16X8AddSatS: + case Opcode::I16X8AddSatU: + case Opcode::I16X8AvgrU: + case Opcode::I16X8Eq: + case Opcode::I16X8GeS: + case Opcode::I16X8GeU: + case Opcode::I16X8GtS: + case Opcode::I16X8GtU: + case Opcode::I16X8LeS: + case Opcode::I16X8LeU: + case Opcode::I16X8LtS: + case Opcode::I16X8LtU: + case Opcode::I16X8MaxS: + case Opcode::I16X8MaxU: + case Opcode::I16X8MinS: + case Opcode::I16X8MinU: + case Opcode::I16X8Mul: + case Opcode::I16X8NarrowI32X4S: + case Opcode::I16X8NarrowI32X4U: + case Opcode::I16X8Ne: + case Opcode::I16X8Shl: + case Opcode::I16X8ShrS: + case Opcode::I16X8ShrU: + case Opcode::I16X8Sub: + case Opcode::I16X8SubSatS: + case Opcode::I16X8SubSatU: + case Opcode::I32Add: + case Opcode::I32And: + case Opcode::I32DivS: + case Opcode::I32DivU: + case Opcode::I32Eq: + case Opcode::I32GeS: + case Opcode::I32GeU: + case Opcode::I32GtS: + case Opcode::I32GtU: + case Opcode::I32LeS: + case Opcode::I32LeU: + case Opcode::I32LtS: + case Opcode::I32LtU: + case Opcode::I32Mul: + case Opcode::I32Ne: + case Opcode::I32Or: + case Opcode::I32RemS: + case Opcode::I32RemU: + case Opcode::I32Rotl: + case Opcode::I32Rotr: + case Opcode::I32Shl: + case Opcode::I32ShrS: + case Opcode::I32ShrU: + case Opcode::I32Sub: + case Opcode::I32X4Add: + case Opcode::I32X4Eq: + case Opcode::I32X4GeS: + case Opcode::I32X4GeU: + case Opcode::I32X4GtS: + case Opcode::I32X4GtU: + case Opcode::I32X4LeS: + case Opcode::I32X4LeU: + case Opcode::I32X4LtS: + case Opcode::I32X4LtU: + case Opcode::I32X4MaxS: + case Opcode::I32X4MaxU: + case Opcode::I32X4MinS: + case Opcode::I32X4MinU: + case Opcode::I32X4Mul: + case Opcode::I32X4Ne: + case Opcode::I32X4Shl: + case Opcode::I32X4ShrS: + case Opcode::I32X4ShrU: + case Opcode::I32X4Sub: + case Opcode::I32Xor: + case Opcode::I64Add: + case Opcode::I64And: + case Opcode::I64DivS: + case Opcode::I64DivU: + case Opcode::I64Eq: + case Opcode::I64GeS: + case Opcode::I64GeU: + case Opcode::I64GtS: + case Opcode::I64GtU: + case Opcode::I64LeS: + case Opcode::I64LeU: + case Opcode::I64LtS: + case Opcode::I64LtU: + case Opcode::I64Mul: + case Opcode::I64Ne: + case Opcode::I64Or: + case Opcode::I64RemS: + case Opcode::I64RemU: + case Opcode::I64Rotl: + case Opcode::I64Rotr: + case Opcode::I64Shl: + case Opcode::I64ShrS: + case Opcode::I64ShrU: + case Opcode::I64Sub: + case Opcode::I64X2Add: + case Opcode::I64X2Shl: + case Opcode::I64X2ShrS: + case Opcode::I64X2ShrU: + case Opcode::I64X2Sub: + case Opcode::I64X2Mul: + case Opcode::I64Xor: + case Opcode::I8X16Add: + case Opcode::I8X16AddSatS: + case Opcode::I8X16AddSatU: + case Opcode::I8X16AvgrU: + case Opcode::I8X16Eq: + case Opcode::I8X16GeS: + case Opcode::I8X16GeU: + case Opcode::I8X16GtS: + case Opcode::I8X16GtU: + case Opcode::I8X16LeS: + case Opcode::I8X16LeU: + case Opcode::I8X16LtS: + case Opcode::I8X16LtU: + case Opcode::I8X16MaxS: + case Opcode::I8X16MaxU: + case Opcode::I8X16MinS: + case Opcode::I8X16MinU: + case Opcode::I8X16NarrowI16X8S: + case Opcode::I8X16NarrowI16X8U: + case Opcode::I8X16Ne: + case Opcode::I8X16Shl: + case Opcode::I8X16ShrS: + case Opcode::I8X16ShrU: + case Opcode::I8X16Sub: + case Opcode::I8X16SubSatS: + case Opcode::I8X16SubSatU: + case Opcode::V128And: + case Opcode::V128Andnot: + case Opcode::V128BitSelect: + case Opcode::V128Or: + case Opcode::V128Xor: + case Opcode::I8X16Swizzle: + // 0 immediates, 2 operands + instr.kind = InstrKind::Imm_0_Op_2; + break; + + case Opcode::Select: + case Opcode::SelectT: + // 0 immediates, 3 operands + instr.kind = InstrKind::Imm_0_Op_3; + break; + + case Opcode::Br: + // Jump target immediate, 0 operands. + instr.kind = InstrKind::Imm_Jump_Op_0; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::BrIf: + case Opcode::BrTable: + case Opcode::InterpBrUnless: + // Jump target immediate, 1 operand. + instr.kind = InstrKind::Imm_Jump_Op_1; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::GlobalGet: + case Opcode::LocalGet: + case Opcode::MemorySize: + case Opcode::TableSize: + case Opcode::DataDrop: + case Opcode::ElemDrop: + case Opcode::RefFunc: + // Index immediate, 0 operands. + instr.kind = InstrKind::Imm_Index_Op_0; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::GlobalSet: + case Opcode::LocalSet: + case Opcode::LocalTee: + case Opcode::MemoryGrow: + case Opcode::TableGet: + // Index immediate, 1 operand. + instr.kind = InstrKind::Imm_Index_Op_1; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::TableSet: + case Opcode::TableGrow: + // Index immediate, 2 operands. + instr.kind = InstrKind::Imm_Index_Op_2; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::MemoryFill: + case Opcode::TableFill: + // Index immediate, 3 operands. + instr.kind = InstrKind::Imm_Index_Op_3; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::Call: + case Opcode::InterpCallImport: + instr.kind = InstrKind::Imm_Index_Op_N; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::CallIndirect: + case Opcode::ReturnCallIndirect: + // Index immediate, N operands. + instr.kind = InstrKind::Imm_Index_Index_Op_N; + instr.imm_u32x2.fst = ReadAt(offset); + instr.imm_u32x2.snd = ReadAt(offset); + break; + + case Opcode::MemoryInit: + case Opcode::TableInit: + case Opcode::MemoryCopy: + case Opcode::TableCopy: + // Index + index immediates, 3 operands. + instr.kind = InstrKind::Imm_Index_Index_Op_3; + instr.imm_u32x2.fst = ReadAt(offset); + instr.imm_u32x2.snd = ReadAt(offset); + break; + + case Opcode::F32Load: + case Opcode::F64Load: + case Opcode::V128Load8X8S: + case Opcode::V128Load8X8U: + case Opcode::V128Load16Splat: + case Opcode::I32AtomicLoad: + case Opcode::I32AtomicLoad16U: + case Opcode::I32AtomicLoad8U: + case Opcode::I32Load: + case Opcode::I32Load16S: + case Opcode::I32Load16U: + case Opcode::I32Load8S: + case Opcode::I32Load8U: + case Opcode::V128Load16X4S: + case Opcode::V128Load16X4U: + case Opcode::V128Load32Splat: + case Opcode::I64AtomicLoad: + case Opcode::I64AtomicLoad16U: + case Opcode::I64AtomicLoad32U: + case Opcode::I64AtomicLoad8U: + case Opcode::I64Load: + case Opcode::I64Load16S: + case Opcode::I64Load16U: + case Opcode::I64Load32S: + case Opcode::I64Load32U: + case Opcode::I64Load8S: + case Opcode::I64Load8U: + case Opcode::V128Load32X2S: + case Opcode::V128Load32X2U: + case Opcode::V128Load64Splat: + case Opcode::V128Load8Splat: + case Opcode::V128Load: + // Index + memory offset immediates, 1 operand. + instr.kind = InstrKind::Imm_Index_Offset_Op_1; + instr.imm_u32x2.fst = ReadAt(offset); + instr.imm_u32x2.snd = ReadAt(offset); + break; + + case Opcode::MemoryAtomicNotify: + case Opcode::F32Store: + case Opcode::F64Store: + case Opcode::I32AtomicRmw16AddU: + case Opcode::I32AtomicRmw16AndU: + case Opcode::I32AtomicRmw16OrU: + case Opcode::I32AtomicRmw16SubU: + case Opcode::I32AtomicRmw16XchgU: + case Opcode::I32AtomicRmw16XorU: + case Opcode::I32AtomicRmw8AddU: + case Opcode::I32AtomicRmw8AndU: + case Opcode::I32AtomicRmw8OrU: + case Opcode::I32AtomicRmw8SubU: + case Opcode::I32AtomicRmw8XchgU: + case Opcode::I32AtomicRmw8XorU: + case Opcode::I32AtomicRmwAdd: + case Opcode::I32AtomicRmwAnd: + case Opcode::I32AtomicRmwOr: + case Opcode::I32AtomicRmwSub: + case Opcode::I32AtomicRmwXchg: + case Opcode::I32AtomicRmwXor: + case Opcode::I32AtomicStore: + case Opcode::I32AtomicStore16: + case Opcode::I32AtomicStore8: + case Opcode::I32Store: + case Opcode::I32Store16: + case Opcode::I32Store8: + case Opcode::I64AtomicRmw16AddU: + case Opcode::I64AtomicRmw16AndU: + case Opcode::I64AtomicRmw16OrU: + case Opcode::I64AtomicRmw16SubU: + case Opcode::I64AtomicRmw16XchgU: + case Opcode::I64AtomicRmw16XorU: + case Opcode::I64AtomicRmw32AddU: + case Opcode::I64AtomicRmw32AndU: + case Opcode::I64AtomicRmw32OrU: + case Opcode::I64AtomicRmw32SubU: + case Opcode::I64AtomicRmw32XchgU: + case Opcode::I64AtomicRmw32XorU: + case Opcode::I64AtomicRmw8AddU: + case Opcode::I64AtomicRmw8AndU: + case Opcode::I64AtomicRmw8OrU: + case Opcode::I64AtomicRmw8SubU: + case Opcode::I64AtomicRmw8XchgU: + case Opcode::I64AtomicRmw8XorU: + case Opcode::I64AtomicRmwAdd: + case Opcode::I64AtomicRmwAnd: + case Opcode::I64AtomicRmwOr: + case Opcode::I64AtomicRmwSub: + case Opcode::I64AtomicRmwXchg: + case Opcode::I64AtomicRmwXor: + case Opcode::I64AtomicStore: + case Opcode::I64AtomicStore16: + case Opcode::I64AtomicStore32: + case Opcode::I64AtomicStore8: + case Opcode::I64Store: + case Opcode::I64Store16: + case Opcode::I64Store32: + case Opcode::I64Store8: + case Opcode::V128Store: + // Index and memory offset immediates, 2 operands. + instr.kind = InstrKind::Imm_Index_Offset_Op_2; + instr.imm_u32x2.fst = ReadAt(offset); + instr.imm_u32x2.snd = ReadAt(offset); + break; + + case Opcode::I32AtomicRmw16CmpxchgU: + case Opcode::I32AtomicRmw8CmpxchgU: + case Opcode::I32AtomicRmwCmpxchg: + case Opcode::I64AtomicRmw16CmpxchgU: + case Opcode::I64AtomicRmw32CmpxchgU: + case Opcode::I64AtomicRmw8CmpxchgU: + case Opcode::I64AtomicRmwCmpxchg: + case Opcode::MemoryAtomicWait32: + case Opcode::MemoryAtomicWait64: + // Index and memory offset immediates, 3 operands. + instr.kind = InstrKind::Imm_Index_Offset_Op_3; + instr.imm_u32x2.fst = ReadAt(offset); + instr.imm_u32x2.snd = ReadAt(offset); + break; + + case Opcode::AtomicFence: + case Opcode::I32Const: + case Opcode::InterpAlloca: + // i32/f32 immediate, 0 operands. + instr.kind = InstrKind::Imm_I32_Op_0; + instr.imm_u32 = ReadAt(offset); + break; + + case Opcode::I64Const: + // i64 immediate, 0 operands. + instr.kind = InstrKind::Imm_I64_Op_0; + instr.imm_u64 = ReadAt(offset); + break; + + case Opcode::F32Const: + // f32 immediate, 0 operands. + instr.kind = InstrKind::Imm_F32_Op_0; + instr.imm_f32 = ReadAt(offset); + break; + + case Opcode::F64Const: + // f64 immediate, 0 operands. + instr.kind = InstrKind::Imm_F64_Op_0; + instr.imm_f64 = ReadAt(offset); + break; + + case Opcode::InterpDropKeep: + // i32 and i32 immediates, 0 operands. + instr.kind = InstrKind::Imm_I32_I32_Op_0; + instr.imm_u32x2.fst = ReadAt(offset); + instr.imm_u32x2.snd = ReadAt(offset); + break; + + case Opcode::I8X16ExtractLaneS: + case Opcode::I8X16ExtractLaneU: + case Opcode::I16X8ExtractLaneS: + case Opcode::I16X8ExtractLaneU: + case Opcode::I32X4ExtractLane: + case Opcode::I64X2ExtractLane: + case Opcode::F32X4ExtractLane: + case Opcode::F64X2ExtractLane: + // u8 immediate, 1 operand. + instr.kind = InstrKind::Imm_I8_Op_1; + instr.imm_u8 = ReadAt(offset); + break; + + case Opcode::I8X16ReplaceLane: + case Opcode::I16X8ReplaceLane: + case Opcode::I32X4ReplaceLane: + case Opcode::I64X2ReplaceLane: + case Opcode::F32X4ReplaceLane: + case Opcode::F64X2ReplaceLane: + // u8 immediate, 2 operands. + instr.kind = InstrKind::Imm_I8_Op_2; + instr.imm_u8 = ReadAt(offset); + break; + + case Opcode::V128Const: + // v128 immediate, 0 operands. + instr.kind = InstrKind::Imm_V128_Op_0; + instr.imm_v128 = ReadAt(offset); + break; + + case Opcode::I8X16Shuffle: + // v128 immediate, 2 operands. + instr.kind = InstrKind::Imm_V128_Op_2; + instr.imm_v128 = ReadAt(offset); + break; + + case Opcode::Block: + case Opcode::Catch: + case Opcode::CatchAll: + case Opcode::Delegate: + case Opcode::Else: + case Opcode::End: + case Opcode::If: + case Opcode::InterpData: + case Opcode::Invalid: + case Opcode::Loop: + case Opcode::Rethrow: + case Opcode::Throw: + case Opcode::Try: + case Opcode::Unwind: + case Opcode::ReturnCall: + // Not used. + break; + } + return instr; +} + +void Istream::Disassemble(Stream* stream) const { + Disassemble(stream, 0, data_.size()); +} + +std::string Istream::DisassemblySource::Header(Offset offset) { + return StringPrintf("%4u", offset); +} + +std::string Istream::DisassemblySource::Pick(Index index, Instr instr) { + return StringPrintf("%%[-%d]", index); +} + +Istream::Offset Istream::Disassemble(Stream* stream, Offset offset) const { + DisassemblySource source; + return Trace(stream, offset, &source); +} + +void Istream::Disassemble(Stream* stream, Offset from, Offset to) const { + DisassemblySource source; + assert(from <= data_.size() && to <= data_.size() && from <= to); + + Offset pc = from; + while (pc < to) { + pc = Trace(stream, pc, &source); + } +} + +Istream::Offset Istream::Trace(Stream* stream, + Offset offset, + TraceSource* source) const { + Offset start = offset; + Instr instr = Read(&offset); + stream->Writef("%s| %s", source->Header(start).c_str(), instr.op.GetName()); + + switch (instr.kind) { + case InstrKind::Imm_0_Op_0: + stream->Writef("\n"); + break; + + case InstrKind::Imm_0_Op_1: + stream->Writef(" %s\n", source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_0_Op_2: + stream->Writef(" %s, %s\n", source->Pick(2, instr).c_str(), + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_0_Op_3: + stream->Writef(" %s, %s, %s\n", source->Pick(3, instr).c_str(), + source->Pick(2, instr).c_str(), + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_Jump_Op_0: + stream->Writef(" @%u\n", instr.imm_u32); + break; + + case InstrKind::Imm_Jump_Op_1: + stream->Writef(" @%u, %s\n", instr.imm_u32, + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_Index_Op_0: + stream->Writef(" $%u\n", instr.imm_u32); + break; + + case InstrKind::Imm_Index_Op_1: + stream->Writef(" $%u, %s\n", instr.imm_u32, + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_Index_Op_2: + stream->Writef(" $%u, %s, %s\n", instr.imm_u32, + source->Pick(2, instr).c_str(), + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_Index_Op_3: + stream->Writef( + " $%u, %s, %s, %s\n", instr.imm_u32, source->Pick(3, instr).c_str(), + source->Pick(2, instr).c_str(), source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_Index_Op_N: + stream->Writef(" $%u\n", instr.imm_u32); // TODO param/result count? + break; + + case InstrKind::Imm_Index_Index_Op_3: + stream->Writef(" $%u, $%u, %s, %s, %s\n", instr.imm_u32x2.fst, + instr.imm_u32x2.snd, source->Pick(3, instr).c_str(), + source->Pick(2, instr).c_str(), + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_Index_Index_Op_N: + stream->Writef(" $%u, $%u\n", instr.imm_u32x2.fst, + instr.imm_u32x2.snd); // TODO param/result count? + break; + + case InstrKind::Imm_Index_Offset_Op_1: + stream->Writef(" $%u:%s+$%u\n", instr.imm_u32x2.fst, + source->Pick(1, instr).c_str(), instr.imm_u32x2.snd); + break; + + case InstrKind::Imm_Index_Offset_Op_2: + stream->Writef(" $%u:%s+$%u, %s\n", instr.imm_u32x2.fst, + source->Pick(2, instr).c_str(), instr.imm_u32x2.snd, + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_Index_Offset_Op_3: + stream->Writef(" $%u:%s+$%u, %s, %s\n", instr.imm_u32x2.fst, + source->Pick(3, instr).c_str(), instr.imm_u32x2.snd, + source->Pick(2, instr).c_str(), + source->Pick(1, instr).c_str()); + break; + + case InstrKind::Imm_I32_Op_0: + stream->Writef(" %u\n", instr.imm_u32); + break; + + case InstrKind::Imm_I64_Op_0: + stream->Writef(" %" PRIu64 "\n", instr.imm_u64); + break; + + case InstrKind::Imm_F32_Op_0: + stream->Writef(" %g\n", instr.imm_f32); + break; + + case InstrKind::Imm_F64_Op_0: + stream->Writef(" %g\n", instr.imm_f64); + break; + + case InstrKind::Imm_I32_I32_Op_0: + stream->Writef(" $%u $%u\n", instr.imm_u32x2.fst, instr.imm_u32x2.snd); + break; + + case InstrKind::Imm_I8_Op_1: + // TODO: cleanup + stream->Writef(" %s : (Lane imm: %u)\n", source->Pick(1, instr).c_str(), + instr.imm_u8); + break; + + case InstrKind::Imm_I8_Op_2: + // TODO: cleanup + stream->Writef(" %s, %s : (Lane imm: $%u)\n", + source->Pick(2, instr).c_str(), + source->Pick(1, instr).c_str(), instr.imm_u8); + break; + + case InstrKind::Imm_V128_Op_0: + stream->Writef(" i32x4 0x%08x 0x%08x 0x%08x 0x%08x\n", + instr.imm_v128.u32(0), instr.imm_v128.u32(1), + instr.imm_v128.u32(2), instr.imm_v128.u32(3)); + break; + + case InstrKind::Imm_V128_Op_2: + // TODO: cleanup + stream->Writef( + " %s, %s : (Lane imm: i32x4 0x%08x 0x%08x 0x%08x 0x%08x )\n", + source->Pick(2, instr).c_str(), source->Pick(1, instr).c_str(), + instr.imm_v128.u32(0), instr.imm_v128.u32(1), instr.imm_v128.u32(2), + instr.imm_v128.u32(3)); + break; + } + return offset; +} + +} // namespace interp +} // namespace wabt diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.h new file mode 100644 index 0000000..69079df --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.h @@ -0,0 +1,155 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_INTERP_ISTREAM_H_ +#define WABT_INTERP_ISTREAM_H_ + +#include +#include +#include + +#include "src/common.h" +#include "src/opcode.h" +#include "src/stream.h" + +namespace wabt { +namespace interp { + +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; +using f32 = float; +using f64 = double; + +using Buffer = std::vector; + +using ValueType = wabt::Type; + +// Group instructions based on their immediates their operands. This way we can +// simplify instruction decoding, disassembling, and tracing. There is an +// example of an instruction that uses this encoding on the right. +enum class InstrKind { + Imm_0_Op_0, // Nop + Imm_0_Op_1, // i32.eqz + Imm_0_Op_2, // i32.add + Imm_0_Op_3, // select + Imm_Jump_Op_0, // br + Imm_Jump_Op_1, // br_if + Imm_Index_Op_0, // global.get + Imm_Index_Op_1, // global.set + Imm_Index_Op_2, // table.set + Imm_Index_Op_3, // memory.fill + Imm_Index_Op_N, // call + Imm_Index_Index_Op_3, // memory.init + Imm_Index_Index_Op_N, // call_indirect + Imm_Index_Offset_Op_1, // i32.load + Imm_Index_Offset_Op_2, // i32.store + Imm_Index_Offset_Op_3, // i32.atomic.rmw.cmpxchg + Imm_I32_Op_0, // i32.const + Imm_I64_Op_0, // i64.const + Imm_F32_Op_0, // f32.const + Imm_F64_Op_0, // f64.const + Imm_I32_I32_Op_0, // drop_keep + Imm_I8_Op_1, // i32x4.extract_lane + Imm_I8_Op_2, // i32x4.replace_lane + Imm_V128_Op_0, // v128.const + Imm_V128_Op_2, // i8x16.shuffle +}; + +struct Instr { + Opcode op; + InstrKind kind; + union { + u8 imm_u8; + u32 imm_u32; + f32 imm_f32; + u64 imm_u64; + f64 imm_f64; + v128 imm_v128; + struct { u32 fst, snd; } imm_u32x2; + }; +}; + +class Istream { + public: + using SerializedOpcode = u32; // TODO: change to u16 + using Offset = u32; + static const Offset kInvalidOffset = ~0; + // Each br_table entry is made up of two instructions: + // + // interp_drop_keep $drop $keep + // br $label + // + // Each opcode is a SerializedOpcode, and each immediate is a u32. + static const Offset kBrTableEntrySize = + sizeof(SerializedOpcode) * 2 + 3 * sizeof(u32); + + // Emit API. + void Emit(u32); + void Emit(Opcode::Enum); + void Emit(Opcode::Enum, u8); + void Emit(Opcode::Enum, u32); + void Emit(Opcode::Enum, u64); + void Emit(Opcode::Enum, v128); + void Emit(Opcode::Enum, u32, u32); + void EmitDropKeep(u32 drop, u32 keep); + + Offset EmitFixupU32(); + void ResolveFixupU32(Offset); + + Offset end() const; + + // Read API. + Instr Read(Offset*) const; + + // Disassemble/Trace API. + // TODO separate out disassembly/tracing? + struct TraceSource { + virtual ~TraceSource() {} + // Whatever content should go before the instruction on each line, e.g. the + // call stack size, value stack size, and istream offset. + virtual std::string Header(Offset) = 0; + virtual std::string Pick(Index, Instr) = 0; + }; + + struct DisassemblySource : TraceSource { + std::string Header(Offset) override; + std::string Pick(Index, Instr) override; + }; + + void Disassemble(Stream*) const; + Offset Disassemble(Stream*, Offset) const; + void Disassemble(Stream*, Offset from, Offset to) const; + + Offset Trace(Stream*, Offset, TraceSource*) const; + +private: + template + void WABT_VECTORCALL EmitAt(Offset, T val); + template + void WABT_VECTORCALL EmitInternal(T val); + + template + T WABT_VECTORCALL ReadAt(Offset*) const; + + Buffer data_; +}; + +} // namespace interp +} // namespace wabt + +#endif // WABT_INTERP_ISTREAM_H_ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/wasi_api.def b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/wasi_api.def new file mode 100644 index 0000000..008e9fd --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/wasi_api.def @@ -0,0 +1,28 @@ +WASI_FUNC(proc_exit) +WASI_FUNC(fd_read) +WASI_FUNC(fd_pread) +WASI_FUNC(fd_write) +WASI_FUNC(fd_pwrite) +WASI_FUNC(fd_close) +WASI_FUNC(fd_seek) +WASI_FUNC(fd_prestat_get) +WASI_FUNC(fd_prestat_dir_name) +WASI_FUNC(fd_fdstat_get) +WASI_FUNC(fd_fdstat_set_flags) +WASI_FUNC(fd_filestat_get) +WASI_FUNC(fd_readdir) +WASI_FUNC(environ_sizes_get) +WASI_FUNC(environ_get) +WASI_FUNC(args_sizes_get) +WASI_FUNC(args_get) +WASI_FUNC(path_open) +WASI_FUNC(path_filestat_get) +WASI_FUNC(path_symlink) +WASI_FUNC(path_unlink_file) +WASI_FUNC(path_remove_directory) +WASI_FUNC(path_create_directory) +WASI_FUNC(path_readlink) +WASI_FUNC(path_rename) +WASI_FUNC(clock_time_get) +WASI_FUNC(poll_oneoff) +WASI_FUNC(random_get) diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/intrusive-list.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/intrusive-list.h new file mode 100644 index 0000000..7d9611a --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/intrusive-list.h @@ -0,0 +1,633 @@ +/* + * Copyright 2017 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_INTRUSIVE_LIST_H_ +#define WABT_INTRUSIVE_LIST_H_ + +#include +#include +#include + +#include "src/make-unique.h" + +// This uses a similar interface as std::list, but is missing the following +// features: +// +// * Add "extract_" functions that remove an element from the list and return +// it. +// * Only supports move-only operations +// * No allocator support +// * No initializer lists +// * Asserts instead of exceptions +// * Some functions are not implemented (merge, remove, remove_if, reverse, +// unique, sort, non-member comparison operators) + +namespace wabt { + +template +class intrusive_list; + +template +class intrusive_list_base { + private: + friend class intrusive_list; + + mutable T* next_ = nullptr; + mutable T* prev_ = nullptr; +}; + +template +class intrusive_list { + public: + // types: + typedef T value_type; + typedef value_type& reference; + typedef const value_type& const_reference; + class iterator; + class const_iterator; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + // construct/copy/destroy: + intrusive_list(); + explicit intrusive_list(std::unique_ptr node); + explicit intrusive_list(T&& node); + intrusive_list(const intrusive_list&) = delete; + intrusive_list(intrusive_list&&); + ~intrusive_list(); + intrusive_list& operator=(const intrusive_list& other) = delete; + intrusive_list& operator=(intrusive_list&& other); + + // iterators: + iterator begin() noexcept; + const_iterator begin() const noexcept; + iterator end() noexcept; + const_iterator end() const noexcept; + + reverse_iterator rbegin() noexcept; + const_reverse_iterator rbegin() const noexcept; + reverse_iterator rend() noexcept; + const_reverse_iterator rend() const noexcept; + + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + // capacity: + size_type size() const noexcept; + bool empty() const noexcept; + + // element access: + reference front(); + const_reference front() const; + reference back(); + const_reference back() const; + + // modifiers: + template + void emplace_front(Args&&... args); + template + void emplace_back(Args&&... args); + void push_front(std::unique_ptr node); + void push_front(T&& node); + void push_back(std::unique_ptr node); + void push_back(T&& node); + void pop_front(); + void pop_back(); + std::unique_ptr extract_front(); + std::unique_ptr extract_back(); + + template + iterator emplace(iterator pos, Args&&... args); + iterator insert(iterator pos, std::unique_ptr node); + iterator insert(iterator pos, T&& node); + std::unique_ptr extract(iterator it); + + iterator erase(iterator pos); + iterator erase(iterator first, iterator last); + void swap(intrusive_list&); + void clear() noexcept; + + void splice(iterator pos, intrusive_list& node); + void splice(iterator pos, intrusive_list&& node); + void splice(iterator pos, intrusive_list& node, iterator it); + void splice(iterator pos, + intrusive_list& node, + iterator first, + iterator last); + + private: + T* first_ = nullptr; + T* last_ = nullptr; + size_t size_ = 0; +}; + +/// iterator +template +class intrusive_list::iterator { + public: + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + typedef T value_type; + typedef T* pointer; + typedef T& reference; + + iterator(const intrusive_list& list, T* node) + : list_(&list), node_(node) {} + + reference operator*() const { + assert(node_); + return *node_; + } + + pointer operator->() const { + assert(node_); + return node_; + } + + iterator& operator++() { + assert(node_); + node_ = node_->next_; + return *this; + } + + iterator operator++(int) { + iterator tmp = *this; + operator++(); + return tmp; + } + + iterator& operator--() { + node_ = node_ ? node_->prev_ : list_->last_; + return *this; + } + + iterator operator--(int) { + iterator tmp = *this; + operator--(); + return tmp; + } + + bool operator==(iterator rhs) const { + assert(list_ == rhs.list_); + return node_ == rhs.node_; + } + + bool operator!=(iterator rhs) const { + assert(list_ == rhs.list_); + return node_ != rhs.node_; + } + + private: + friend class const_iterator; + + const intrusive_list* list_; + T* node_; +}; + +/// const_iterator +template +class intrusive_list::const_iterator { + public: + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + typedef T value_type; + typedef const T* pointer; + typedef const T& reference; + + const_iterator(const intrusive_list& list, T* node) + : list_(&list), node_(node) {} + + const_iterator(const iterator& other) + : list_(other.list_), node_(other.node_) {} + + reference operator*() const { + assert(node_); + return *node_; + } + + pointer operator->() const { + assert(node_); + return node_; + } + + const_iterator& operator++() { + assert(node_); + node_ = node_->next_; + return *this; + } + + const_iterator operator++(int) { + const_iterator tmp = *this; + operator++(); + return tmp; + } + + const_iterator& operator--() { + node_ = node_ ? node_->prev_ : list_->last_; + return *this; + } + + const_iterator operator--(int) { + const_iterator tmp = *this; + operator--(); + return tmp; + } + + bool operator==(const_iterator rhs) const { + assert(list_ == rhs.list_); + return node_ == rhs.node_; + } + + bool operator!=(const_iterator rhs) const { + assert(list_ == rhs.list_); + return node_ != rhs.node_; + } + + private: + const intrusive_list* list_; + T* node_; +}; + +template +inline intrusive_list::intrusive_list() {} + +template +inline intrusive_list::intrusive_list(std::unique_ptr node) { + push_back(std::move(node)); +} + +template +inline intrusive_list::intrusive_list(T&& node) { + push_back(std::move(node)); +} + +template +inline intrusive_list::intrusive_list(intrusive_list&& other) + : first_(other.first_), last_(other.last_), size_(other.size_) { + other.first_ = other.last_ = nullptr; + other.size_ = 0; +} + +template +inline intrusive_list::~intrusive_list() { + clear(); +} + +template +inline intrusive_list& intrusive_list::operator=( + intrusive_list&& other) { + clear(); + first_ = other.first_; + last_ = other.last_; + size_ = other.size_; + other.first_ = other.last_ = nullptr; + other.size_ = 0; + return *this; +} + +template +inline typename intrusive_list::iterator +intrusive_list::begin() noexcept { + return iterator(*this, first_); +} + +template +inline typename intrusive_list::const_iterator intrusive_list::begin() + const noexcept { + return const_iterator(*this, first_); +} + +template +inline typename intrusive_list::iterator intrusive_list::end() noexcept { + return iterator(*this, nullptr); +} + +template +inline typename intrusive_list::const_iterator intrusive_list::end() const + noexcept { + return const_iterator(*this, nullptr); +} + +template +inline typename intrusive_list::reverse_iterator +intrusive_list::rbegin() noexcept { + return reverse_iterator(iterator(*this, nullptr)); +} + +template +inline typename intrusive_list::const_reverse_iterator +intrusive_list::rbegin() const noexcept { + return const_reverse_iterator(const_iterator(*this, nullptr)); +} + +template +inline typename intrusive_list::reverse_iterator +intrusive_list::rend() noexcept { + return reverse_iterator(iterator(*this, first_)); +} + +template +inline typename intrusive_list::const_reverse_iterator +intrusive_list::rend() const noexcept { + return const_reverse_iterator(const_iterator(*this, first_)); +} + +template +inline typename intrusive_list::const_iterator intrusive_list::cbegin() + const noexcept { + return const_iterator(*this, first_); +} + +template +inline typename intrusive_list::const_iterator intrusive_list::cend() + const noexcept { + return const_iterator(*this, nullptr); +} + +template +inline typename intrusive_list::const_reverse_iterator +intrusive_list::crbegin() const noexcept { + return const_reverse_iterator(const_iterator(*this, nullptr)); +} + +template +inline typename intrusive_list::const_reverse_iterator +intrusive_list::crend() const noexcept { + return const_reverse_iterator(const_iterator(*this, first_)); +} + +template +inline typename intrusive_list::size_type intrusive_list::size() const + noexcept { + return size_; +} + +template +inline bool intrusive_list::empty() const noexcept { + return size_ == 0; +} + +template +inline typename intrusive_list::reference intrusive_list::front() { + assert(!empty()); + return *first_; +} + +template +inline typename intrusive_list::const_reference intrusive_list::front() + const { + assert(!empty()); + return *first_; +} + +template +inline typename intrusive_list::reference intrusive_list::back() { + assert(!empty()); + return *last_; +} + +template +inline typename intrusive_list::const_reference intrusive_list::back() + const { + assert(!empty()); + return *last_; +} + +template +template +inline void intrusive_list::emplace_front(Args&&... args) { + push_front(MakeUnique(std::forward(args)...)); +} + +template +template +inline void intrusive_list::emplace_back(Args&&... args) { + push_back(MakeUnique(std::forward(args)...)); +} + +template +inline void intrusive_list::push_front(std::unique_ptr node) { + assert(node->prev_ == nullptr && node->next_ == nullptr); + + T* node_p = node.release(); + if (first_) { + node_p->next_ = first_; + first_->prev_ = node_p; + } else { + last_ = node_p; + } + first_ = node_p; + size_++; +} + +template +inline void intrusive_list::push_front(T&& node) { + push_front(MakeUnique(std::move(node))); +} + +template +inline void intrusive_list::push_back(std::unique_ptr node) { + assert(node->prev_ == nullptr && node->next_ == nullptr); + + T* node_p = node.release(); + if (last_) { + node_p->prev_ = last_; + last_->next_ = node_p; + } else { + first_ = node_p; + } + last_ = node_p; + size_++; +} + +template +inline void intrusive_list::push_back(T&& node) { + push_back(MakeUnique(std::move(node))); +} + +template +inline void intrusive_list::pop_front() { + extract_front(); +} + +template +inline void intrusive_list::pop_back() { + extract_back(); +} + +template +inline std::unique_ptr intrusive_list::extract_front() { + assert(!empty()); + T* node = first_; + if (first_ == last_) { + first_ = last_ = nullptr; + } else { + first_ = first_->next_; + first_->prev_ = nullptr; + } + node->next_ = node->prev_ = nullptr; + size_--; + return std::unique_ptr(node); +} + +template +inline std::unique_ptr intrusive_list::extract_back() { + assert(!empty()); + T* node = last_; + if (first_ == last_) { + first_ = last_ = nullptr; + } else { + last_ = last_->prev_; + last_->next_ = nullptr; + } + node->next_ = node->prev_ = nullptr; + size_--; + return std::unique_ptr(node); +} + +template +template +inline typename intrusive_list::iterator intrusive_list::emplace( + iterator pos, + Args&&... args) { + return insert(pos, MakeUnique(std::forward(args)...)); +} + +template +inline typename intrusive_list::iterator intrusive_list::insert( + iterator pos, + std::unique_ptr node) { + assert(node->prev_ == nullptr && node->next_ == nullptr); + + T* node_p; + if (pos == end()) { + push_back(std::move(node)); + node_p = &back(); + } else { + node_p = node.release(); + node_p->prev_ = pos->prev_; + node_p->next_ = &*pos; + if (pos->prev_) { + pos->prev_->next_ = node_p; + } else { + first_ = node_p; + } + pos->prev_ = node_p; + size_++; + } + return iterator(*this, node_p); +} + +template +inline typename intrusive_list::iterator intrusive_list::insert( + iterator pos, + T&& node) { + return insert(pos, MakeUnique(std::move(node))); +} + +template +inline std::unique_ptr intrusive_list::extract(iterator pos) { + assert(!empty()); + assert(pos != end()); + T* node = &*pos; + if (first_ == last_) { + first_ = last_ = nullptr; + } else { + if (node->prev_) { + node->prev_->next_ = node->next_; + } else { + first_ = node->next_; + } + + if (node->next_) { + node->next_->prev_ = node->prev_; + } else { + last_ = node->prev_; + } + } + node->next_ = node->prev_ = nullptr; + size_--; + return std::unique_ptr(node); +} + +template +inline typename intrusive_list::iterator intrusive_list::erase( + iterator pos) { + iterator next = std::next(pos); + extract(pos); + return next; +} + +template +inline typename intrusive_list::iterator intrusive_list::erase( + iterator first, + iterator last) { + while (first != last) + first = erase(first); + return first; +} + +template +inline void intrusive_list::swap(intrusive_list& other) { + std::swap(first_, other.first_); + std::swap(last_, other.last_); + std::swap(size_, other.size_); +} + +template +inline void intrusive_list::clear() noexcept { + for (T* iter = first_; iter;) { + T* next = iter->next_; + delete iter; + iter = next; + } + first_ = last_ = nullptr; + size_ = 0; +} + +template +inline void intrusive_list::splice(iterator pos, intrusive_list& other) { + splice(pos, other, other.begin(), other.end()); +} + +template +inline void intrusive_list::splice(iterator pos, intrusive_list&& other) { + splice(pos, other, other.begin(), other.end()); +} + +template +inline void intrusive_list::splice(iterator pos, + intrusive_list& other, + iterator it) { + insert(pos, other.extract(it)); +} + +template +inline void intrusive_list::splice(iterator pos, + intrusive_list& other, + iterator first, + iterator last) { + while (first != last) + insert(pos, other.extract(first++)); +} + +} // namespace wabt + +#endif // WABT_INTRUSIVE_LIST_H_ diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.cc new file mode 100644 index 0000000..ef1c9a2 --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.cc @@ -0,0 +1,261 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#include "src/ir-util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "src/cast.h" +#include "src/common.h" +#include "src/expr-visitor.h" +#include "src/ir.h" +#include "src/ir-util.h" +#include "src/literal.h" +#include "src/stream.h" + +#define WABT_TRACING 0 +#include "src/tracing.h" + +using namespace wabt; + +const Label* ModuleContext::GetLabel(const Var& var) const { + if (var.is_name()) { + for (Index i = GetLabelStackSize(); i > 0; --i) { + auto label = &label_stack_[i - 1]; + if (label->name == var.name()) { + return label; + } + } + } else if (var.index() < GetLabelStackSize()) { + auto label = &label_stack_[GetLabelStackSize() - var.index() - 1]; + return label; + } + return nullptr; +} + +Index ModuleContext::GetLabelArity(const Var& var) const { + auto label = GetLabel(var); + if (!label) { + return 0; + } + + return label->label_type == LabelType::Loop ? label->param_types.size() + : label->result_types.size(); +} + +Index ModuleContext::GetFuncParamCount(const Var& var) const { + const Func* func = module.GetFunc(var); + return func ? func->GetNumParams() : 0; +} + +Index ModuleContext::GetFuncResultCount(const Var& var) const { + const Func* func = module.GetFunc(var); + return func ? func->GetNumResults() : 0; +} + +void ModuleContext::BeginBlock(LabelType label_type, const Block& block) { + label_stack_.emplace_back(label_type, block.label, block.decl.sig.param_types, + block.decl.sig.result_types); +} + +void ModuleContext::EndBlock() { + label_stack_.pop_back(); +} + +void ModuleContext::BeginFunc(const Func& func) { + label_stack_.clear(); + label_stack_.emplace_back(LabelType::Func, std::string(), TypeVector(), + func.decl.sig.result_types); + current_func_ = &func; +} + +void ModuleContext::EndFunc() { + current_func_ = nullptr; +} + +ModuleContext::Arities ModuleContext::GetExprArity(const Expr& expr) const { + switch (expr.type()) { + case ExprType::AtomicNotify: + case ExprType::AtomicRmw: + case ExprType::Binary: + case ExprType::Compare: + case ExprType::TableGrow: + return { 2, 1 }; + + case ExprType::AtomicStore: + case ExprType::Store: + case ExprType::TableSet: + return { 2, 0 }; + + case ExprType::Block: + return { 0, cast(&expr)->block.decl.sig.GetNumResults() }; + + case ExprType::Br: + return { GetLabelArity(cast(&expr)->var), 1, true }; + + case ExprType::BrIf: { + Index arity = GetLabelArity(cast(&expr)->var); + return { arity + 1, arity }; + } + + case ExprType::BrTable: + return { GetLabelArity(cast(&expr)->default_target) + 1, 1, + true }; + + case ExprType::Call: { + const Var& var = cast(&expr)->var; + return { GetFuncParamCount(var), GetFuncResultCount(var) }; + } + + case ExprType::ReturnCall: { + const Var& var = cast(&expr)->var; + return { GetFuncParamCount(var), GetFuncResultCount(var), true }; + } + + case ExprType::CallIndirect: { + const auto* ci_expr = cast(&expr); + return { ci_expr->decl.GetNumParams() + 1, + ci_expr->decl.GetNumResults() }; + } + + case ExprType::ReturnCallIndirect: { + const auto* rci_expr = cast(&expr); + return { rci_expr->decl.GetNumParams() + 1, + rci_expr->decl.GetNumResults(), true }; + } + + case ExprType::Const: + case ExprType::GlobalGet: + case ExprType::LocalGet: + case ExprType::MemorySize: + case ExprType::TableSize: + case ExprType::RefNull: + case ExprType::RefFunc: + return { 0, 1 }; + + case ExprType::Unreachable: + return { 0, 1, true }; + + case ExprType::DataDrop: + case ExprType::ElemDrop: + case ExprType::AtomicFence: + return { 0, 0 }; + + case ExprType::MemoryInit: + case ExprType::TableInit: + case ExprType::MemoryFill: + case ExprType::MemoryCopy: + case ExprType::TableCopy: + case ExprType::TableFill: + return { 3, 0 }; + + case ExprType::AtomicLoad: + case ExprType::Convert: + case ExprType::Load: + case ExprType::LocalTee: + case ExprType::MemoryGrow: + case ExprType::Unary: + case ExprType::TableGet: + case ExprType::RefIsNull: + case ExprType::LoadSplat: + return { 1, 1 }; + + case ExprType::Drop: + case ExprType::GlobalSet: + case ExprType::LocalSet: + return { 1, 0 }; + + case ExprType::If: + return { 1, cast(&expr)->true_.decl.sig.GetNumResults() }; + + case ExprType::Loop: + return { 0, cast(&expr)->block.decl.sig.GetNumResults() }; + + case ExprType::Nop: + return { 0, 0 }; + + case ExprType::Return: + return + { static_cast(current_func_->decl.sig.result_types.size()), 1, + true }; + + case ExprType::Rethrow: + return { 0, 0, true }; + + case ExprType::AtomicRmwCmpxchg: + case ExprType::AtomicWait: + case ExprType::Select: + return { 3, 1 }; + + case ExprType::Throw: { + auto throw_ = cast(&expr); + Index operand_count = 0; + if (Event* event = module.GetEvent(throw_->var)) { + operand_count = event->decl.sig.param_types.size(); + } + return { operand_count, 0, true }; + } + + case ExprType::Try: + return { 0, cast(&expr)->block.decl.sig.GetNumResults() }; + + case ExprType::Ternary: + return { 3, 1 }; + + case ExprType::SimdLaneOp: { + const Opcode opcode = cast(&expr)->opcode; + switch (opcode) { + case Opcode::I8X16ExtractLaneS: + case Opcode::I8X16ExtractLaneU: + case Opcode::I16X8ExtractLaneS: + case Opcode::I16X8ExtractLaneU: + case Opcode::I32X4ExtractLane: + case Opcode::I64X2ExtractLane: + case Opcode::F32X4ExtractLane: + case Opcode::F64X2ExtractLane: + return { 1, 1 }; + + case Opcode::I8X16ReplaceLane: + case Opcode::I16X8ReplaceLane: + case Opcode::I32X4ReplaceLane: + case Opcode::I64X2ReplaceLane: + case Opcode::F32X4ReplaceLane: + case Opcode::F64X2ReplaceLane: + return { 2, 1 }; + + default: + fprintf(stderr, "Invalid Opcode for expr type: %s\n", + GetExprTypeName(expr)); + assert(0); + return { 0, 0 }; + } + } + + case ExprType::SimdShuffleOp: + return { 2, 1 }; + } + + WABT_UNREACHABLE; +} diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.h new file mode 100644 index 0000000..226e81a --- /dev/null +++ b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.h @@ -0,0 +1,76 @@ +/* + * Copyright 2016 WebAssembly Community Group participants + * + * 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. + */ + +#ifndef WABT_IR_UTIL_H_ +#define WABT_IR_UTIL_H_ + +#include "src/common.h" +#include "src/ir.h" + +namespace wabt { + +struct Label { + Label(LabelType label_type, + const std::string& name, + const TypeVector& param_types, + const TypeVector& result_types) + : name(name), + label_type(label_type), + param_types(param_types), + result_types(result_types) {} + + std::string name; + LabelType label_type; + TypeVector param_types; + TypeVector result_types; +}; + +struct ModuleContext { + ModuleContext(const Module &module) : module(module) {} + + Index GetLabelStackSize() const { return label_stack_.size(); } + const Label* GetLabel(const Var& var) const; + Index GetLabelArity(const Var& var) const; + void SetTopLabelType(LabelType label_type) { + label_stack_.back().label_type = label_type; + } + + Index GetFuncParamCount(const Var& var) const; + Index GetFuncResultCount(const Var& var) const; + + void BeginBlock(LabelType label_type, const Block& block); + void EndBlock(); + void BeginFunc(const Func& func); + void EndFunc(); + + struct Arities { + Index nargs; + Index nreturns; + bool unreachable; + Arities(Index na, Index nr, bool ur = false) + : nargs(na), nreturns(nr), unreachable(ur) {} + }; + Arities GetExprArity(const Expr& expr) const; + + const Module &module; + private: + const Func* current_func_ = nullptr; + std::vector