LWNode_Release_210903_60ce3db 56/263456/1 submit/tizen/20210903.043505
authorRyan Hyun Choi <ryan.choi@samsung.com>
Fri, 3 Sep 2021 00:21:24 +0000 (09:21 +0900)
committerRyan Hyun Choi <ryan.choi@samsung.com>
Fri, 3 Sep 2021 01:29:34 +0000 (10:29 +0900)
Change-Id: I693792d1029267e456f09feff8cc76341ba18b5e
Signed-off-by: Ryan Choi <ryan.choi@samsung.com>
157 files changed:
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.clang-format [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.flake8 [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/.gitignore [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/CMakeLists.txt [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Contributing.md [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/LICENSE [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/Makefile [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/README.md [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/cmake/README.md [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/apply-names.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-ir.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-logging.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-nop.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-objdump.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader-opcnt.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-reader.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer-spec.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary-writer.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binary.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/binding-hash.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/cast.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/circular-array.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.h.in [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ast.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ls.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-naming.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-exported.json [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-helpers.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.def [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-inl.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-math.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-util.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasi.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-wasm-c-api.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/istream.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/wasi_api.def [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/intrusive-list.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir-util.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-keywords.txt [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/make-unique.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.c [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.def [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/lexer-keywords.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.c [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/range.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/result.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-binary-reader.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-circular-array.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-filenames.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-hexfloat.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-interp.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-intrusive-list.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-literal.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-option-parser.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-string-view.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-utf8.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-wast-parser.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.def [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/spectest-interp.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-decompile.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-interp.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-objdump.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-opcodecnt.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-strip.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-validate.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2c.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat-fuzz.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wast2json.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat-desugar.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat2wasm.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.c.tmpl [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.h.tmpl [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c_tmpl.py [new file with mode: 0755]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.cc [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.h [new file with mode: 0644]
lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/ubsan.blacklist [new file with mode: 0644]
lwnode/test/node/cctest.gypi [new file with mode: 0644]

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 (file)
index 0000000..3f19e61
--- /dev/null
@@ -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 (file)
index 0000000..76b6006
--- /dev/null
@@ -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 (file)
index 0000000..645634f
--- /dev/null
@@ -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 (file)
index 0000000..43ce516
--- /dev/null
@@ -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 $<$<COMPILE_LANGUAGE:CXX>:-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 $<TARGET_FILE:${EXE_NAME}> ${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 $<TARGET_FILE_DIR:wat2wasm>
+    DEPENDS ${WABT_EXECUTABLES}
+    WORKING_DIRECTORY ${WABT_SOURCE_DIR}
+    ${USES_TERMINAL}
+  )
+
+  add_custom_target(run-unittests
+    COMMAND $<TARGET_FILE:wabt-unittests>
+    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 $<TARGET_FILE_DIR:wat2wasm>
+    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 $<TARGET_FILE:${EXENAME}> ${WABT_SOURCE_DIR}/bin/
+      COMMAND ${CMAKE_COMMAND} -E copy ${WABT_SOURCE_DIR}/third_party/wasm-c-api/example/${NAME}.wasm $<TARGET_FILE_DIR:${EXENAME}>/
+      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 (file)
index 0000000..1cc607f
--- /dev/null
@@ -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 (file)
index 0000000..d645695
--- /dev/null
@@ -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 (file)
index 0000000..00476ae
--- /dev/null
@@ -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 (file)
index 0000000..7e317a8
--- /dev/null
@@ -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 <https://aka.ms/cmake> 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 (file)
index 0000000..ee8057f
--- /dev/null
@@ -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 (file)
index 0000000..0159091
--- /dev/null
@@ -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 <cassert>
+#include <cstdio>
+#include <vector>
+
+#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<std::string> param_and_local_index_to_name_;
+  std::vector<std::string> 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,
+                                &param_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 (file)
index 0000000..1837c37
--- /dev/null
@@ -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 (file)
index 0000000..cdda331
--- /dev/null
@@ -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 <cassert>
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+#include <vector>
+
+#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> 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<LabelNode> 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) {
+  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<TypeModuleField>(GetLocation());
+  auto func_type = MakeUnique<FuncType>();
+  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<TypeModuleField>(GetLocation());
+  auto struct_type = MakeUnique<StructType>();
+  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<TypeModuleField>(GetLocation());
+  auto array_type = MakeUnique<ArrayType>();
+  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<FuncImport>();
+  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<ImportModuleField>(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<TableImport>();
+  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<ImportModuleField>(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<MemoryImport>();
+  import->module_name = module_name.to_string();
+  import->field_name = field_name.to_string();
+  import->memory.page_limits = *page_limits;
+  module_->AppendField(
+      MakeUnique<ImportModuleField>(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<GlobalImport>();
+  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<ImportModuleField>(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<EventImport>();
+  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<ImportModuleField>(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<FuncModuleField>(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<TableModuleField>(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<MemoryModuleField>(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<GlobalModuleField>(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<ExportModuleField>(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<StartModuleField>(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, &current_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<AtomicLoadExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnAtomicStoreExpr(Opcode opcode,
+                                         Address alignment_log2,
+                                         Address offset) {
+  return AppendExpr(
+      MakeUnique<AtomicStoreExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnAtomicRmwExpr(Opcode opcode,
+                                       Address alignment_log2,
+                                       Address offset) {
+  return AppendExpr(
+      MakeUnique<AtomicRmwExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnAtomicRmwCmpxchgExpr(Opcode opcode,
+                                              Address alignment_log2,
+                                              Address offset) {
+  return AppendExpr(
+      MakeUnique<AtomicRmwCmpxchgExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnAtomicWaitExpr(Opcode opcode,
+                                        Address alignment_log2,
+                                        Address offset) {
+  return AppendExpr(
+      MakeUnique<AtomicWaitExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnAtomicFenceExpr(uint32_t consistency_model) {
+  return AppendExpr(MakeUnique<AtomicFenceExpr>(consistency_model));
+}
+
+Result BinaryReaderIR::OnAtomicNotifyExpr(Opcode opcode,
+                                          Address alignment_log2,
+                                          Address offset) {
+  return AppendExpr(
+      MakeUnique<AtomicNotifyExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnBinaryExpr(Opcode opcode) {
+  return AppendExpr(MakeUnique<BinaryExpr>(opcode));
+}
+
+Result BinaryReaderIR::OnBlockExpr(Type sig_type) {
+  auto expr = MakeUnique<BlockExpr>();
+  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<BrExpr>(Var(depth)));
+}
+
+Result BinaryReaderIR::OnBrIfExpr(Index depth) {
+  return AppendExpr(MakeUnique<BrIfExpr>(Var(depth)));
+}
+
+Result BinaryReaderIR::OnBrTableExpr(Index num_targets,
+                                     Index* target_depths,
+                                     Index default_target_depth) {
+  auto expr = MakeUnique<BrTableExpr>();
+  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<CallExpr>(Var(func_index)));
+}
+
+Result BinaryReaderIR::OnCallIndirectExpr(Index sig_index, Index table_index) {
+  auto expr = MakeUnique<CallIndirectExpr>();
+  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<ReturnCallExpr>(Var(func_index)));
+}
+
+Result BinaryReaderIR::OnReturnCallIndirectExpr(Index sig_index, Index table_index) {
+  auto expr = MakeUnique<ReturnCallIndirectExpr>();
+  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<CompareExpr>(opcode));
+}
+
+Result BinaryReaderIR::OnConvertExpr(Opcode opcode) {
+  return AppendExpr(MakeUnique<ConvertExpr>(opcode));
+}
+
+Result BinaryReaderIR::OnDropExpr() {
+  return AppendExpr(MakeUnique<DropExpr>());
+}
+
+Result BinaryReaderIR::OnElseExpr() {
+  LabelNode* label;
+  Expr* expr;
+  CHECK_RESULT(TopLabelExpr(&label, &expr));
+
+  if (label->label_type == LabelType::If) {
+    auto* if_expr = cast<IfExpr>(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<BlockExpr>(expr)->block.end_loc = GetLocation();
+      break;
+    case LabelType::Loop:
+      cast<LoopExpr>(expr)->block.end_loc = GetLocation();
+      break;
+    case LabelType::If:
+      cast<IfExpr>(expr)->true_.end_loc = GetLocation();
+      break;
+    case LabelType::Else:
+      cast<IfExpr>(expr)->false_end_loc = GetLocation();
+      break;
+    case LabelType::Try:
+      cast<TryExpr>(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<ConstExpr>(Const::F32(value_bits, GetLocation())));
+}
+
+Result BinaryReaderIR::OnF64ConstExpr(uint64_t value_bits) {
+  return AppendExpr(
+      MakeUnique<ConstExpr>(Const::F64(value_bits, GetLocation())));
+}
+
+Result BinaryReaderIR::OnV128ConstExpr(v128 value_bits) {
+  return AppendExpr(
+      MakeUnique<ConstExpr>(Const::V128(value_bits, GetLocation())));
+}
+
+Result BinaryReaderIR::OnGlobalGetExpr(Index global_index) {
+  return AppendExpr(
+      MakeUnique<GlobalGetExpr>(Var(global_index, GetLocation())));
+}
+
+Result BinaryReaderIR::OnLocalGetExpr(Index local_index) {
+  return AppendExpr(MakeUnique<LocalGetExpr>(Var(local_index, GetLocation())));
+}
+
+Result BinaryReaderIR::OnI32ConstExpr(uint32_t value) {
+  return AppendExpr(MakeUnique<ConstExpr>(Const::I32(value, GetLocation())));
+}
+
+Result BinaryReaderIR::OnI64ConstExpr(uint64_t value) {
+  return AppendExpr(MakeUnique<ConstExpr>(Const::I64(value, GetLocation())));
+}
+
+Result BinaryReaderIR::OnIfExpr(Type sig_type) {
+  auto expr = MakeUnique<IfExpr>();
+  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<LoadExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnLoopExpr(Type sig_type) {
+  auto expr = MakeUnique<LoopExpr>();
+  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<MemoryCopyExpr>());
+}
+
+Result BinaryReaderIR::OnDataDropExpr(Index segment) {
+  return AppendExpr(MakeUnique<DataDropExpr>(Var(segment)));
+}
+
+Result BinaryReaderIR::OnMemoryFillExpr() {
+  return AppendExpr(MakeUnique<MemoryFillExpr>());
+}
+
+Result BinaryReaderIR::OnMemoryGrowExpr() {
+  return AppendExpr(MakeUnique<MemoryGrowExpr>());
+}
+
+Result BinaryReaderIR::OnMemoryInitExpr(Index segment) {
+  return AppendExpr(MakeUnique<MemoryInitExpr>(Var(segment)));
+}
+
+Result BinaryReaderIR::OnMemorySizeExpr() {
+  return AppendExpr(MakeUnique<MemorySizeExpr>());
+}
+
+Result BinaryReaderIR::OnTableCopyExpr(Index dst_index, Index src_index) {
+  return AppendExpr(MakeUnique<TableCopyExpr>(Var(dst_index), Var(src_index)));
+}
+
+Result BinaryReaderIR::OnElemDropExpr(Index segment) {
+  return AppendExpr(MakeUnique<ElemDropExpr>(Var(segment)));
+}
+
+Result BinaryReaderIR::OnTableInitExpr(Index segment, Index table_index) {
+  return AppendExpr(MakeUnique<TableInitExpr>(Var(segment), Var(table_index)));
+}
+
+Result BinaryReaderIR::OnTableGetExpr(Index table_index) {
+  return AppendExpr(MakeUnique<TableGetExpr>(Var(table_index)));
+}
+
+Result BinaryReaderIR::OnTableSetExpr(Index table_index) {
+  return AppendExpr(MakeUnique<TableSetExpr>(Var(table_index)));
+}
+
+Result BinaryReaderIR::OnTableGrowExpr(Index table_index) {
+  return AppendExpr(MakeUnique<TableGrowExpr>(Var(table_index)));
+}
+
+Result BinaryReaderIR::OnTableSizeExpr(Index table_index) {
+  return AppendExpr(MakeUnique<TableSizeExpr>(Var(table_index)));
+}
+
+Result BinaryReaderIR::OnTableFillExpr(Index table_index) {
+  return AppendExpr(MakeUnique<TableFillExpr>(Var(table_index)));
+}
+
+Result BinaryReaderIR::OnRefFuncExpr(Index func_index) {
+  return AppendExpr(MakeUnique<RefFuncExpr>(Var(func_index)));
+}
+
+Result BinaryReaderIR::OnRefNullExpr(Type type) {
+  return AppendExpr(MakeUnique<RefNullExpr>(type));
+}
+
+Result BinaryReaderIR::OnRefIsNullExpr() {
+  return AppendExpr(MakeUnique<RefIsNullExpr>());
+}
+
+Result BinaryReaderIR::OnNopExpr() {
+  return AppendExpr(MakeUnique<NopExpr>());
+}
+
+Result BinaryReaderIR::OnRethrowExpr(Index depth) {
+  return AppendExpr(MakeUnique<RethrowExpr>(Var(depth, GetLocation())));
+}
+
+Result BinaryReaderIR::OnReturnExpr() {
+  return AppendExpr(MakeUnique<ReturnExpr>());
+}
+
+Result BinaryReaderIR::OnSelectExpr(Index result_count, Type* result_types) {
+  TypeVector results;
+  results.assign(result_types, result_types + result_count);
+  return AppendExpr(MakeUnique<SelectExpr>(results));
+}
+
+Result BinaryReaderIR::OnGlobalSetExpr(Index global_index) {
+  return AppendExpr(
+      MakeUnique<GlobalSetExpr>(Var(global_index, GetLocation())));
+}
+
+Result BinaryReaderIR::OnLocalSetExpr(Index local_index) {
+  return AppendExpr(MakeUnique<LocalSetExpr>(Var(local_index, GetLocation())));
+}
+
+Result BinaryReaderIR::OnStoreExpr(Opcode opcode,
+                                   Address alignment_log2,
+                                   Address offset) {
+  return AppendExpr(MakeUnique<StoreExpr>(opcode, 1 << alignment_log2, offset));
+}
+
+Result BinaryReaderIR::OnThrowExpr(Index event_index) {
+  return AppendExpr(MakeUnique<ThrowExpr>(Var(event_index, GetLocation())));
+}
+
+Result BinaryReaderIR::OnLocalTeeExpr(Index local_index) {
+  return AppendExpr(MakeUnique<LocalTeeExpr>(Var(local_index, GetLocation())));
+}
+
+Result BinaryReaderIR::OnTryExpr(Type sig_type) {
+  auto expr_ptr = MakeUnique<TryExpr>();
+  // 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<TryExpr>(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<TryExpr>(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<TryExpr>(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<UnaryExpr>(opcode));
+}
+
+Result BinaryReaderIR::OnTernaryExpr(Opcode opcode) {
+  return AppendExpr(MakeUnique<TernaryExpr>(opcode));
+}
+
+Result BinaryReaderIR::OnUnreachableExpr() {
+  return AppendExpr(MakeUnique<UnreachableExpr>());
+}
+
+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<SimdLaneOpExpr>(opcode, value));
+}
+
+Result BinaryReaderIR::OnSimdShuffleOpExpr(Opcode opcode, v128 value) {
+  return AppendExpr(MakeUnique<SimdShuffleOpExpr>(opcode, value));
+}
+
+Result BinaryReaderIR::OnLoadSplatExpr(Opcode opcode,
+                                       Address alignment_log2,
+                                       Address offset) {
+  return AppendExpr(
+      MakeUnique<LoadSplatExpr>(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<ElemSegmentModuleField>(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<DataSegmentModuleField>(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<ConstExpr>(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<ConstExpr>(Const::F64(value, loc), loc));
+  return Result::Ok;
+}
+
+Result BinaryReaderIR::OnInitExprV128ConstExpr(Index index, v128 value) {
+  Location loc = GetLocation();
+  current_init_expr_->push_back(
+      MakeUnique<ConstExpr>(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<GlobalGetExpr>(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<ConstExpr>(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<ConstExpr>(Const::I64(value, loc), loc));
+  return Result::Ok;
+}
+
+Result BinaryReaderIR::OnInitExprRefNull(Index index, Type type) {
+  Location loc = GetLocation();
+  current_init_expr_->push_back(MakeUnique<RefNullExpr>(type, loc));
+  return Result::Ok;
+}
+
+Result BinaryReaderIR::OnInitExprRefFunc(Index index, Index func_index) {
+  Location loc = GetLocation();
+  current_init_expr_->push_back(
+      MakeUnique<RefFuncExpr>(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<EventModuleField>(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 (file)
index 0000000..18c1558
--- /dev/null
@@ -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 (file)
index 0000000..5cebbe9
--- /dev/null
@@ -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 <cinttypes>
+
+#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<size_t>(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<int32_t>(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<int>(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 (file)
index 0000000..70dcbae
--- /dev/null
@@ -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 (file)
index 0000000..f72dbf1
--- /dev/null
@@ -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 (file)
index 0000000..64e7b42
--- /dev/null
@@ -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 <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdio>
+#include <cstring>
+#include <vector>
+
+#if HAVE_STRCASECMP
+#include <strings.h>
+#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<size_t>(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<BinarySection> section_types_;
+  bool section_found_ = false;
+  std::string module_name_;
+
+  std::unique_ptr<FileStream> 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<size_t>(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 = "<stdin>";
+      }
+      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 "<illegal_symbol_index>";
+  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<FileStream> 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<int32_t>(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<SymbolBinding>(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<SymbolVisibility>(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 (file)
index 0000000..b2874da
--- /dev/null
@@ -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 <map>
+#include <string>
+
+#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<Index, std::string> 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<Reloc> code_relocations;
+  std::vector<Reloc> data_relocations;
+  ObjdumpNames function_names;
+  ObjdumpNames global_names;
+  ObjdumpNames section_names;
+  ObjdumpNames event_names;
+  ObjdumpNames segment_names;
+  ObjdumpNames table_names;
+  std::vector<ObjdumpSymbol> 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 (file)
index 0000000..3908660
--- /dev/null
@@ -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 <cassert>
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+
+#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 <typename T>
+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 <typename T>
+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 <typename T>
+std::pair<const T*, size_t> OpcodeInfo::GetDataArray() const {
+  if (data_.empty()) {
+    return std::pair<const T*, size_t>(nullptr, 0);
+  }
+
+  assert(data_.size() % sizeof(T) == 0);
+  return std::make_pair(reinterpret_cast<const T*>(data_.data()),
+                        data_.size() / sizeof(T));
+}
+
+template <typename T>
+const T* OpcodeInfo::GetData(size_t expected_size) const {
+  auto pair = GetDataArray<T>();
+  assert(pair.second == expected_size);
+  return pair.first;
+}
+
+template <typename T, typename F>
+void OpcodeInfo::WriteArray(Stream& stream, F&& write_func) {
+  auto pair = GetDataArray<T>();
+  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<uint32_t>(), *GetData<uint32_t>());
+      break;
+
+    case Kind::Uint64:
+      stream.Writef(" %" PRIu64 " (0x%" PRIx64 ")", *GetData<uint64_t>(),
+                    *GetData<uint64_t>());
+      break;
+
+    case Kind::Index:
+      stream.Writef(" %" PRIindex, *GetData<Index>());
+      break;
+
+    case Kind::Float32: {
+      stream.Writef(" %g", *GetData<float>());
+      char buffer[WABT_MAX_FLOAT_HEX + 1];
+      WriteFloatHex(buffer, sizeof(buffer), *GetData<uint32_t>());
+      stream.Writef(" (%s)", buffer);
+      break;
+    }
+
+    case Kind::Float64: {
+      stream.Writef(" %g", *GetData<double>());
+      char buffer[WABT_MAX_DOUBLE_HEX + 1];
+      WriteDoubleHex(buffer, sizeof(buffer), *GetData<uint64_t>());
+      stream.Writef(" (%s)", buffer);
+      break;
+    }
+
+    case Kind::Uint32Uint32:
+      WriteArray<uint32_t>(
+          stream, [&stream](uint32_t value) { stream.Writef("%u", value); });
+      break;
+
+    case Kind::BlockSig: {
+      auto type = *GetData<Type>();
+      if (type.IsIndex()) {
+        stream.Writef(" type:%d", type.GetIndex());
+      } else if (type != Type::Void) {
+        stream.Writef(" %s", type.GetName());
+      }
+      break;
+    }
+
+    case Kind::BrTable: {
+      WriteArray<Index>(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 <typename... Args>
+  Result Emplace(Args&&... args);
+
+  OpcodeInfoCounts* opcode_counts_;
+  Opcode current_opcode_;
+};
+
+template <typename... Args>
+Result BinaryReaderOpcnt::Emplace(Args&&... args) {
+  auto pair = opcode_counts_->emplace(
+      std::piecewise_construct, std::make_tuple(std::forward<Args>(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 (file)
index 0000000..cfdd570
--- /dev/null
@@ -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 <map>
+#include <vector>
+
+#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 <typename T>
+  OpcodeInfo(Opcode, Kind, T* data, size_t count = 1);
+  template <typename T>
+  OpcodeInfo(Opcode, Kind, T* data, size_t count, T extra);
+
+  Opcode opcode() const { return opcode_; }
+
+  void Write(Stream&);
+
+ private:
+  template <typename T>
+  std::pair<const T*, size_t> GetDataArray() const;
+  template <typename T>
+  const T* GetData(size_t expected_size = 1) const;
+
+  template <typename T, typename F>
+  void WriteArray(Stream& stream, F&& write_func);
+
+  Opcode opcode_;
+  Kind kind_;
+  std::vector<uint8_t> 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<OpcodeInfo, size_t> 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 (file)
index 0000000..d770afa
--- /dev/null
@@ -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 <cassert>
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+#include <vector>
+
+#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 <alloca.h>
+#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 <typename T, T BinaryReader::*member>
+  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 <typename T>
+  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<Index> 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<Limits> memories;
+
+  using ReadEndRestoreGuard =
+      ValueRestoreGuard<size_t, &BinaryReader::read_end_>;
+};
+
+BinaryReader::BinaryReader(const void* data,
+                           size_t size,
+                           BinaryReaderDelegate* delegate,
+                           const ReadBinaryOptions& options)
+    : read_end_(size),
+      state_(static_cast<const uint8_t*>(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<uint8_t> 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 <typename T>
+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>(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>(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<ExternalKind>(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<const char*>(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<const uint8_t*>(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<int>(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<NameSectionSubsection>(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(&section_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<RelocType>(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<LinkingEntryType>(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<SymbolType>(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<ComdatType>(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(&section_name, "section name"));
+  CALLBACK(BeginCustomSection, section_index, section_size, section_name);
+  ValueRestoreGuard<bool, &BinaryReader::reading_custom_section_> 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(&param_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<ExternalKind>(kind), module_name,
+             field_name);
+    switch (static_cast<ExternalKind>(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<ExternalKind>(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<int>(BinarySection::Last) + 1] = {false};
+
+  for (; state_.offset < state_.size; ++section_index) {
+    uint8_t section_code;
+    Offset section_size;
+    CHECK_RESULT(ReadU8(&section_code, "section code"));
+    CHECK_RESULT(ReadOffset(&section_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<BinarySection>(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<unsigned int>(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<unsigned int>(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 (file)
index 0000000..19643aa
--- /dev/null
@@ -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 <stddef.h>
+#include <stdint.h>
+
+#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<TypeMut>;
+
+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 (file)
index 0000000..13e7112
--- /dev/null
@@ -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 <cassert>
+#include <cinttypes>
+
+#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<size_t>(command.type)]);
+  WriteString(s_command_names[static_cast<size_t>(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<uint8_t>(lane));
+            break;
+
+          case Type::I16:
+            json_stream_->Writef("\"%u\"", const_.v128_lane<uint16_t>(lane));
+            break;
+
+          case Type::I32:
+            json_stream_->Writef("\"%u\"", const_.v128_lane<uint32_t>(lane));
+            break;
+
+          case Type::I64:
+            json_stream_->Writef("\"%" PRIu64 "\"",
+                                 const_.v128_lane<uint64_t>(lane));
+            break;
+
+          case Type::F32:
+            WriteF32(const_.v128_lane<uint32_t>(lane),
+                     const_.expected_nan(lane));
+            break;
+
+          case Type::F64:
+            WriteF64(const_.v128_lane<uint64_t>(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<InvokeAction>(&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<TextScriptModule>(&script_module)->module);
+      break;
+
+    case ScriptModuleType::Binary:
+      module_stream_factory_(filename)->WriteData(
+          cast<BinaryScriptModule>(&script_module)->data, "");
+      break;
+
+    case ScriptModuleType::Quoted:
+      module_stream_factory_(filename)->WriteData(
+          cast<QuotedScriptModule>(&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<ModuleCommand>(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<ActionCommand>(command)->action;
+        WriteLocation(action.loc);
+        WriteSeparator();
+        WriteAction(action);
+        WriteSeparator();
+        WriteKey("expected");
+        WriteActionResultType(action);
+        break;
+      }
+
+      case CommandType::Register: {
+        auto* register_command = cast<RegisterCommand>(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<AssertMalformedCommand>(command);
+        WriteInvalidModule(*assert_malformed_command->module,
+                           assert_malformed_command->text);
+        num_modules_++;
+        break;
+      }
+
+      case CommandType::AssertInvalid: {
+        auto* assert_invalid_command = cast<AssertInvalidCommand>(command);
+        WriteInvalidModule(*assert_invalid_command->module,
+                           assert_invalid_command->text);
+        num_modules_++;
+        break;
+      }
+
+      case CommandType::AssertUnlinkable: {
+        auto* assert_unlinkable_command =
+            cast<AssertUnlinkableCommand>(command);
+        WriteInvalidModule(*assert_unlinkable_command->module,
+                           assert_unlinkable_command->text);
+        num_modules_++;
+        break;
+      }
+
+      case CommandType::AssertUninstantiable: {
+        auto* assert_uninstantiable_command =
+            cast<AssertUninstantiableCommand>(command);
+        WriteInvalidModule(*assert_uninstantiable_command->module,
+                           assert_uninstantiable_command->text);
+        num_modules_++;
+        break;
+      }
+
+      case CommandType::AssertReturn: {
+        auto* assert_return_command = cast<AssertReturnCommand>(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<AssertTrapCommand>(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<AssertExhaustionCommand>(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<FilenameMemoryStreamPair>* out_module_streams,
+    Stream* log_stream) {
+  WriteBinarySpecStreamFactory module_stream_factory =
+      [&](string_view filename) {
+        out_module_streams->emplace_back(filename,
+                                         MakeUnique<MemoryStream>(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 (file)
index 0000000..197d6f2
--- /dev/null
@@ -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 <functional>
+#include <utility>
+#include <vector>
+
+#include "src/binary-writer.h"
+#include "src/common.h"
+#include "src/ir.h"
+
+namespace wabt {
+
+struct FilenameMemoryStreamPair {
+  FilenameMemoryStreamPair(string_view filename,
+                           std::unique_ptr<MemoryStream> stream)
+      : filename(filename), stream(std::move(stream)) {}
+  std::string filename;
+  std::unique_ptr<MemoryStream> stream;
+};
+
+typedef std::function<Stream*(string_view filename)>
+    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<FilenameMemoryStreamPair>* 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 (file)
index 0000000..c744aca
--- /dev/null
@@ -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 <cassert>
+#include <cmath>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+#include <set>
+#include <vector>
+
+#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<Reloc> 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<SymbolVisibility>(flags() & WABT_SYMBOL_MASK_VISIBILITY);
+  }
+  SymbolBinding binding() const {
+    return static_cast<SymbolBinding>(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<Symbol> symbols_;
+
+  std::vector<Index> functions_;
+  std::vector<Index> tables_;
+  std::vector<Index> globals_;
+
+  std::set<string_view> 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 <typename T>
+  Result AddSymbol(std::vector<Index>* 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<Index>& 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<Index> exported_funcs;
+    std::set<Index> exported_globals;
+    std::set<Index> exported_events;
+    std::set<Index> 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<Symbol>& 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 <typename T>
+  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 <typename T>
+  void WriteNames(const std::vector<T*>& elems, NameSectionSubsection type);
+
+  Stream* stream_;
+  const WriteBinaryOptions& options_;
+  const Module* module_;
+
+  SymbolTable symtab_;
+  std::vector<RelocSection> 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<unsigned>(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 <typename T>
+void BinaryWriter::WriteLoadStoreExpr(const Func* func,
+                                      const Expr* expr,
+                                      const char* desc) {
+  auto* typed_expr = cast<T>(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<AtomicLoadExpr>(func, expr, "memory offset");
+      break;
+    case ExprType::AtomicRmw:
+      WriteLoadStoreExpr<AtomicRmwExpr>(func, expr, "memory offset");
+      break;
+    case ExprType::AtomicRmwCmpxchg:
+      WriteLoadStoreExpr<AtomicRmwCmpxchgExpr>(func, expr, "memory offset");
+      break;
+    case ExprType::AtomicStore:
+      WriteLoadStoreExpr<AtomicStoreExpr>(func, expr, "memory offset");
+      break;
+    case ExprType::AtomicWait:
+      WriteLoadStoreExpr<AtomicWaitExpr>(func, expr, "memory offset");
+      break;
+    case ExprType::AtomicFence: {
+      auto* fence_expr = cast<AtomicFenceExpr>(expr);
+      WriteOpcode(stream_, Opcode::AtomicFence);
+      WriteU32Leb128(stream_, fence_expr->consistency_model,
+                     "consistency model");
+      break;
+    }
+    case ExprType::AtomicNotify:
+      WriteLoadStoreExpr<AtomicNotifyExpr>(func, expr, "memory offset");
+      break;
+    case ExprType::Binary:
+      WriteOpcode(stream_, cast<BinaryExpr>(expr)->opcode);
+      break;
+    case ExprType::Block:
+      WriteOpcode(stream_, Opcode::Block);
+      WriteBlockDecl(cast<BlockExpr>(expr)->block.decl);
+      WriteExprList(func, cast<BlockExpr>(expr)->block.exprs);
+      WriteOpcode(stream_, Opcode::End);
+      break;
+    case ExprType::Br:
+      WriteOpcode(stream_, Opcode::Br);
+      WriteU32Leb128(stream_, GetLabelVarDepth(&cast<BrExpr>(expr)->var),
+                     "break depth");
+      break;
+    case ExprType::BrIf:
+      WriteOpcode(stream_, Opcode::BrIf);
+      WriteU32Leb128(stream_, GetLabelVarDepth(&cast<BrIfExpr>(expr)->var),
+                     "break depth");
+      break;
+    case ExprType::BrTable: {
+      auto* br_table_expr = cast<BrTableExpr>(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<CallExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::Call);
+      WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB);
+      break;
+    }
+    case ExprType::ReturnCall: {
+      Index index = module_->GetFuncIndex(cast<ReturnCallExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::ReturnCall);
+      WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB);
+      break;
+    }
+    case ExprType::CallIndirect:{
+      Index sig_index =
+        module_->GetFuncTypeIndex(cast<CallIndirectExpr>(expr)->decl);
+      Index table_index =
+        module_->GetTableIndex(cast<CallIndirectExpr>(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<ReturnCallIndirectExpr>(expr)->decl);
+      Index table_index =
+          module_->GetTableIndex(cast<ReturnCallIndirectExpr>(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<CompareExpr>(expr)->opcode);
+      break;
+    case ExprType::Const: {
+      const Const& const_ = cast<ConstExpr>(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<ConvertExpr>(expr)->opcode);
+      break;
+    case ExprType::Drop:
+      WriteOpcode(stream_, Opcode::Drop);
+      break;
+    case ExprType::GlobalGet: {
+      Index index = module_->GetGlobalIndex(cast<GlobalGetExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::GlobalGet);
+      WriteU32Leb128WithReloc(index, "global index", RelocType::GlobalIndexLEB);
+      break;
+    }
+    case ExprType::GlobalSet: {
+      Index index = module_->GetGlobalIndex(cast<GlobalSetExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::GlobalSet);
+      WriteU32Leb128WithReloc(index, "global index", RelocType::GlobalIndexLEB);
+      break;
+    }
+    case ExprType::If: {
+      auto* if_expr = cast<IfExpr>(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<LoadExpr>(func, expr, "load offset");
+      break;
+    case ExprType::LocalGet: {
+      Index index = GetLocalIndex(func, cast<LocalGetExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::LocalGet);
+      WriteU32Leb128(stream_, index, "local index");
+      break;
+    }
+    case ExprType::LocalSet: {
+      Index index = GetLocalIndex(func, cast<LocalSetExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::LocalSet);
+      WriteU32Leb128(stream_, index, "local index");
+      break;
+    }
+    case ExprType::LocalTee: {
+      Index index = GetLocalIndex(func, cast<LocalTeeExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::LocalTee);
+      WriteU32Leb128(stream_, index, "local index");
+      break;
+    }
+    case ExprType::Loop:
+      WriteOpcode(stream_, Opcode::Loop);
+      WriteBlockDecl(cast<LoopExpr>(expr)->block.decl);
+      WriteExprList(func, cast<LoopExpr>(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<DataDropExpr>(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<MemoryInitExpr>(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<TableCopyExpr>(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<ElemDropExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::ElemDrop);
+      WriteU32Leb128(stream_, index, "elem.drop segment");
+      break;
+    }
+    case ExprType::TableInit: {
+      auto* init_expr = cast<TableInitExpr>(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<TableGetExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::TableGet);
+      WriteTableNumberWithReloc(index, "table.get table index");
+      break;
+    }
+    case ExprType::TableSet: {
+      Index index =
+          module_->GetTableIndex(cast<TableSetExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::TableSet);
+      WriteTableNumberWithReloc(index, "table.set table index");
+      break;
+    }
+    case ExprType::TableGrow: {
+      Index index =
+          module_->GetTableIndex(cast<TableGrowExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::TableGrow);
+      WriteTableNumberWithReloc(index, "table.grow table index");
+      break;
+    }
+    case ExprType::TableSize: {
+      Index index =
+          module_->GetTableIndex(cast<TableSizeExpr>(expr)->var);
+      WriteOpcode(stream_, Opcode::TableSize);
+      WriteTableNumberWithReloc(index, "table.size table index");
+      break;
+    }
+    case ExprType::TableFill: {
+      Index index =
+          module_->GetTableIndex(cast<TableFillExpr>(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<RefFuncExpr>(expr)->var);
+      WriteU32Leb128WithReloc(index, "function index", RelocType::FuncIndexLEB);
+      break;
+    }
+    case ExprType::RefNull: {
+      WriteOpcode(stream_, Opcode::RefNull);
+      WriteType(stream_, cast<RefNullExpr>(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<RethrowExpr>(expr)->var),
+                     "rethrow depth");
+      break;
+    case ExprType::Return:
+      WriteOpcode(stream_, Opcode::Return);
+      break;
+    case ExprType::Select: {
+      auto* select_expr = cast<SelectExpr>(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<StoreExpr>(func, expr, "store offset");
+      break;
+    case ExprType::Throw:
+      WriteOpcode(stream_, Opcode::Throw);
+      WriteU32Leb128(stream_, GetEventVarDepth(&cast<ThrowExpr>(expr)->var),
+                     "throw event");
+      break;
+    case ExprType::Try: {
+      auto* try_expr = cast<TryExpr>(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<UnaryExpr>(expr)->opcode);
+      break;
+    case ExprType::Ternary:
+      WriteOpcode(stream_, cast<TernaryExpr>(expr)->opcode);
+      break;
+    case ExprType::SimdLaneOp: {
+      const Opcode opcode = cast<SimdLaneOpExpr>(expr)->opcode;
+      WriteOpcode(stream_, opcode);
+      stream_->WriteU8(static_cast<uint8_t>(cast<SimdLaneOpExpr>(expr)->val),
+                       "Simd Lane literal");
+      break;
+    }
+    case ExprType::SimdShuffleOp: {
+      const Opcode opcode = cast<SimdShuffleOpExpr>(expr)->opcode;
+      WriteOpcode(stream_, opcode);
+      stream_->WriteU128(cast<SimdShuffleOpExpr>(expr)->val,
+                         "Simd Lane[16] literal");
+      break;
+    }
+    case ExprType::LoadSplat:
+      WriteLoadStoreExpr<LoadSplatExpr>(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<Reloc>& 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<Symbol>& 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 <typename T>
+void BinaryWriter::WriteNames(const std::vector<T*>& 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<FuncType>(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<StructType>(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<ArrayType>(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<FuncImport>(import)->func.decl),
+              "import signature index");
+          break;
+
+        case ExternalKind::Table:
+          WriteTable(&cast<TableImport>(import)->table);
+          break;
+
+        case ExternalKind::Memory:
+          WriteMemory(&cast<MemoryImport>(import)->memory);
+          break;
+
+        case ExternalKind::Global:
+          WriteGlobalHeader(&cast<GlobalImport>(import)->global);
+          break;
+
+        case ExternalKind::Event:
+          WriteEventType(&cast<EventImport>(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<std::string> 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<Func>(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<TypeEntry>(module_->types, NameSectionSubsection::Type);
+    WriteNames<Table>(module_->tables, NameSectionSubsection::Table);
+    WriteNames<Memory>(module_->memories, NameSectionSubsection::Memory);
+    WriteNames<Global>(module_->globals, NameSectionSubsection::Global);
+    WriteNames<ElemSegment>(module_->elem_segments,
+                            NameSectionSubsection::ElemSegment);
+    WriteNames<DataSegment>(module_->data_segments,
+                            NameSectionSubsection::DataSegment);
+
+    EndSection();
+  }
+
+  if (options_.relocatable) {
+    WriteLinkingSection();
+    for (RelocSection& section : reloc_sections_) {
+      WriteRelocSection(&section);
+    }
+  }
+
+  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 (file)
index 0000000..4304a0a
--- /dev/null
@@ -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 (file)
index 0000000..60b20cb
--- /dev/null
@@ -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 (file)
index 0000000..d9877f9
--- /dev/null
@@ -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 (file)
index 0000000..f52682d
--- /dev/null
@@ -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 <algorithm>
+#include <vector>
+
+#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 (file)
index 0000000..0779527
--- /dev/null
@@ -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 <functional>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#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<std::string, Binding> {
+ public:
+  typedef std::function<void(const value_type&, const value_type&)>
+      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<const value_type*> 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 (file)
index 0000000..d1129b2
--- /dev/null
@@ -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 <cctype>
+#include <cinttypes>
+#include <map>
+#include <set>
+
+#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 <int>
+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<std::string> SymbolSet;
+  typedef std::map<std::string, std::string> SymbolMap;
+  typedef std::pair<Index, Type> StackTypePair;
+  typedef std::map<StackTypePair, std::string> 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 <typename T, typename U, typename... Args>
+  void Write(T&& t, U&& u, Args&&... args) {
+    Write(std::forward<T>(t));
+    Write(std::forward<U>(u));
+    Write(std::forward<Args>(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<std::string>& index_to_name);
+  void WriteLocals(const std::vector<std::string>& 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<Label> label_stack_;
+};
+
+static const char kImplicitFuncLabel[] = "$Bfunc";
+
+#define SECTION_NAME(x) s_header_##x
+#include "src/prebuilt/wasm2c.include.h"
+#undef SECTION_NAME
+
+#define SECTION_NAME(x) s_source_##x
+#include "src/prebuilt/wasm2c.include.c"
+#undef SECTION_NAME
+
+size_t CWriter::MarkTypeStack() const {
+  return type_stack_.size();
+}
+
+void CWriter::ResetTypeStack(size_t mark) {
+  assert(mark <= type_stack_.size());
+  type_stack_.erase(type_stack_.begin() + mark, type_stack_.end());
+}
+
+Type CWriter::StackType(Index index) const {
+  assert(index < type_stack_.size());
+  return *(type_stack_.rbegin() + index);
+}
+
+void CWriter::PushType(Type type) {
+  type_stack_.push_back(type);
+}
+
+void CWriter::PushTypes(const TypeVector& types) {
+  type_stack_.insert(type_stack_.end(), types.begin(), types.end());
+}
+
+void CWriter::DropTypes(size_t count) {
+  assert(count <= type_stack_.size());
+  type_stack_.erase(type_stack_.end() - count, type_stack_.end());
+}
+
+void CWriter::PushLabel(LabelType label_type,
+                        const std::string& name,
+                        const FuncSignature& sig,
+                        bool used) {
+  // TODO(binji): Add multi-value support.
+  if ((label_type != LabelType::Func && sig.GetNumParams() != 0) ||
+      sig.GetNumResults() > 1) {
+    UNIMPLEMENTED("multi value support");
+  }
+
+  label_stack_.emplace_back(label_type, name, sig.result_types,
+                            type_stack_.size(), used);
+}
+
+const Label* CWriter::FindLabel(const Var& var) {
+  Label* label = nullptr;
+
+  if (var.is_index()) {
+    // We've generated names for all labels, so we should only be using an
+    // index when branching to the implicit function label, which can't be
+    // named.
+    assert(var.index() + 1 == label_stack_.size());
+    label = &label_stack_[0];
+  } else {
+    assert(var.is_name());
+    for (Index i = label_stack_.size(); i > 0; --i) {
+      label = &label_stack_[i - 1];
+      if (label->name == var.name())
+        break;
+    }
+  }
+
+  assert(label);
+  label->used = true;
+  return label;
+}
+
+bool CWriter::IsTopLabelUsed() const {
+  assert(!label_stack_.empty());
+  return label_stack_.back().used;
+}
+
+void CWriter::PopLabel() {
+  label_stack_.pop_back();
+}
+
+// static
+std::string CWriter::AddressOf(const std::string& s) {
+  return "(&" + s + ")";
+}
+
+// static
+std::string CWriter::Deref(const std::string& s) {
+  return "(*" + s + ")";
+}
+
+// static
+char CWriter::MangleType(Type type) {
+  switch (type) {
+    case Type::I32: return 'i';
+    case Type::I64: return 'j';
+    case Type::F32: return 'f';
+    case Type::F64: return 'd';
+    default: WABT_UNREACHABLE;
+  }
+}
+
+// static
+std::string CWriter::MangleTypes(const TypeVector& types) {
+  if (types.empty())
+    return std::string("v");
+
+  std::string result;
+  for (auto type : types) {
+    result += MangleType(type);
+  }
+  return result;
+}
+
+// static
+std::string CWriter::MangleName(string_view name) {
+  const char kPrefix = 'Z';
+  std::string result = "Z_";
+
+  if (!name.empty()) {
+    for (char c : name) {
+      if ((isalnum(c) && c != kPrefix) || c == '_') {
+        result += c;
+      } else {
+        result += kPrefix;
+        result += StringPrintf("%02X", static_cast<uint8_t>(c));
+      }
+    }
+  }
+
+  return result;
+}
+
+// static
+std::string CWriter::MangleFuncName(string_view name,
+                                    const TypeVector& param_types,
+                                    const TypeVector& result_types) {
+  std::string sig = MangleTypes(result_types) + MangleTypes(param_types);
+  return MangleName(name) + MangleName(sig);
+}
+
+// static
+std::string CWriter::MangleGlobalName(string_view name, Type type) {
+  std::string sig(1, MangleType(type));
+  return MangleName(name) + MangleName(sig);
+}
+
+// static
+std::string CWriter::ExportName(string_view mangled_name) {
+  return "WASM_RT_ADD_PREFIX(" + mangled_name.to_string() + ")";
+}
+
+// static
+std::string CWriter::LegalizeName(string_view name) {
+  if (name.empty())
+    return "_";
+
+  std::string result;
+  result = isalpha(name[0]) ? name[0] : '_';
+  for (size_t i = 1; i < name.size(); ++i)
+    result += isalnum(name[i]) ? name[i] : '_';
+
+  // In addition to containing valid characters for C, we must also avoid
+  // colliding with things C cares about, such as reserved words (e.g. "void")
+  // or a function name like main() (which a compiler will  complain about if we
+  // define it with another type). To avoid such problems, prefix.
+  result = "w2c_" + result;
+
+  return result;
+}
+
+std::string CWriter::DefineName(SymbolSet* set, string_view name) {
+  std::string legal = LegalizeName(name);
+  if (set->find(legal) != set->end()) {
+    std::string base = legal + "_";
+    size_t count = 0;
+    do {
+      legal = base + std::to_string(count++);
+    } while (set->find(legal) != set->end());
+  }
+  set->insert(legal);
+  return legal;
+}
+
+string_view StripLeadingDollar(string_view name) {
+  if (!name.empty() && name[0] == '$') {
+    name.remove_prefix(1);
+  }
+  return name;
+}
+
+std::string CWriter::DefineImportName(const std::string& name,
+                                      string_view module,
+                                      string_view mangled_field_name) {
+  std::string mangled = MangleName(module) + mangled_field_name.to_string();
+  import_syms_.insert(name);
+  global_syms_.insert(mangled);
+  global_sym_map_.insert(SymbolMap::value_type(name, mangled));
+  return "(*" + mangled + ")";
+}
+
+std::string CWriter::DefineGlobalScopeName(const std::string& name) {
+  std::string unique = DefineName(&global_syms_, StripLeadingDollar(name));
+  global_sym_map_.insert(SymbolMap::value_type(name, unique));
+  return unique;
+}
+
+std::string CWriter::DefineLocalScopeName(const std::string& name) {
+  std::string unique = DefineName(&local_syms_, StripLeadingDollar(name));
+  local_sym_map_.insert(SymbolMap::value_type(name, unique));
+  return unique;
+}
+
+std::string CWriter::DefineStackVarName(Index index,
+                                        Type type,
+                                        string_view name) {
+  std::string unique = DefineName(&local_syms_, name);
+  StackTypePair stp = {index, type};
+  stack_var_sym_map_.insert(StackVarSymbolMap::value_type(stp, unique));
+  return unique;
+}
+
+void CWriter::Indent(int size) {
+  indent_ += size;
+}
+
+void CWriter::Dedent(int size) {
+  indent_ -= size;
+  assert(indent_ >= 0);
+}
+
+void CWriter::WriteIndent() {
+  static char s_indent[] =
+      "                                                                       "
+      "                                                                       ";
+  static size_t s_indent_len = sizeof(s_indent) - 1;
+  size_t to_write = indent_;
+  while (to_write >= s_indent_len) {
+    stream_->WriteData(s_indent, s_indent_len);
+    to_write -= s_indent_len;
+  }
+  if (to_write > 0) {
+    stream_->WriteData(s_indent, to_write);
+  }
+}
+
+void CWriter::WriteData(const void* src, size_t size) {
+  if (should_write_indent_next_) {
+    WriteIndent();
+    should_write_indent_next_ = false;
+  }
+  stream_->WriteData(src, size);
+}
+
+void WABT_PRINTF_FORMAT(2, 3) CWriter::Writef(const char* format, ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  WriteData(buffer, length);
+}
+
+void CWriter::Write(Newline) {
+  Write("\n");
+  should_write_indent_next_ = true;
+}
+
+void CWriter::Write(OpenBrace) {
+  Write("{");
+  Indent();
+  Write(Newline());
+}
+
+void CWriter::Write(CloseBrace) {
+  Dedent();
+  Write("}");
+}
+
+void CWriter::Write(Index index) {
+  Writef("%" PRIindex, index);
+}
+
+void CWriter::Write(string_view s) {
+  WriteData(s.data(), s.size());
+}
+
+void CWriter::Write(const LocalName& name) {
+  assert(local_sym_map_.count(name.name) == 1);
+  Write(local_sym_map_[name.name]);
+}
+
+std::string CWriter::GetGlobalName(const std::string& name) const {
+  assert(global_sym_map_.count(name) == 1);
+  auto iter = global_sym_map_.find(name);
+  assert(iter != global_sym_map_.end());
+  return iter->second;
+}
+
+void CWriter::Write(const GlobalName& name) {
+  Write(GetGlobalName(name.name));
+}
+
+void CWriter::Write(const ExternalPtr& name) {
+  bool is_import = import_syms_.count(name.name) != 0;
+  if (is_import) {
+    Write(GetGlobalName(name.name));
+  } else {
+    Write(AddressOf(GetGlobalName(name.name)));
+  }
+}
+
+void CWriter::Write(const ExternalRef& name) {
+  bool is_import = import_syms_.count(name.name) != 0;
+  if (is_import) {
+    Write(Deref(GetGlobalName(name.name)));
+  } else {
+    Write(GetGlobalName(name.name));
+  }
+}
+
+void CWriter::Write(const Var& var) {
+  assert(var.is_name());
+  Write(LocalName(var.name()));
+}
+
+void CWriter::Write(const GotoLabel& goto_label) {
+  const Label* label = FindLabel(goto_label.var);
+  if (label->HasValue()) {
+    assert(label->sig.size() == 1);
+    assert(type_stack_.size() >= label->type_stack_size);
+    Index dst = type_stack_.size() - label->type_stack_size - 1;
+    if (dst != 0)
+      Write(StackVar(dst, label->sig[0]), " = ", StackVar(0), "; ");
+  }
+
+  if (goto_label.var.is_name()) {
+    Write("goto ", goto_label.var, ";");
+  } else {
+    // We've generated names for all labels, so we should only be using an
+    // index when branching to the implicit function label, which can't be
+    // named.
+    Write("goto ", Var(kImplicitFuncLabel), ";");
+  }
+}
+
+void CWriter::Write(const LabelDecl& label) {
+  if (IsTopLabelUsed())
+    Write(label.name, ":;", Newline());
+}
+
+void CWriter::Write(const GlobalVar& var) {
+  assert(var.var.is_name());
+  Write(ExternalRef(var.var.name()));
+}
+
+void CWriter::Write(const StackVar& sv) {
+  Index index = type_stack_.size() - 1 - sv.index;
+  Type type = sv.type;
+  if (type == Type::Any) {
+    assert(index < type_stack_.size());
+    type = type_stack_[index];
+  }
+
+  StackTypePair stp = {index, type};
+  auto iter = stack_var_sym_map_.find(stp);
+  if (iter == stack_var_sym_map_.end()) {
+    std::string name = MangleType(type) + std::to_string(index);
+    Write(DefineStackVarName(index, type, name));
+  } else {
+    Write(iter->second);
+  }
+}
+
+void CWriter::Write(Type type) {
+  switch (type) {
+    case Type::I32: Write("u32"); break;
+    case Type::I64: Write("u64"); break;
+    case Type::F32: Write("f32"); break;
+    case Type::F64: Write("f64"); break;
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(TypeEnum type) {
+  switch (type.type) {
+    case Type::I32: Write("WASM_RT_I32"); break;
+    case Type::I64: Write("WASM_RT_I64"); break;
+    case Type::F32: Write("WASM_RT_F32"); break;
+    case Type::F64: Write("WASM_RT_F64"); break;
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(SignedType type) {
+  switch (type.type) {
+    case Type::I32: Write("s32"); break;
+    case Type::I64: Write("s64"); break;
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(const ResultType& rt) {
+  if (!rt.types.empty()) {
+    Write(rt.types[0]);
+  } else {
+    Write("void");
+  }
+}
+
+void CWriter::Write(const Const& const_) {
+  switch (const_.type()) {
+    case Type::I32:
+      Writef("%uu", static_cast<int32_t>(const_.u32()));
+      break;
+
+    case Type::I64:
+      Writef("%" PRIu64 "ull", static_cast<int64_t>(const_.u64()));
+      break;
+
+    case Type::F32: {
+      uint32_t f32_bits = const_.f32_bits();
+      // TODO(binji): Share with similar float info in interp.cc and literal.cc
+      if ((f32_bits & 0x7f800000u) == 0x7f800000u) {
+        const char* sign = (f32_bits & 0x80000000) ? "-" : "";
+        uint32_t significand = f32_bits & 0x7fffffu;
+        if (significand == 0) {
+          // Infinity.
+          Writef("%sINFINITY", sign);
+        } else {
+          // Nan.
+          Writef("f32_reinterpret_i32(0x%08x) /* %snan:0x%06x */", f32_bits,
+                 sign, significand);
+        }
+      } else if (f32_bits == 0x80000000) {
+        // Negative zero. Special-cased so it isn't written as -0 below.
+        Writef("-0.f");
+      } else {
+        Writef("%.9g", Bitcast<float>(f32_bits));
+      }
+      break;
+    }
+
+    case Type::F64: {
+      uint64_t f64_bits = const_.f64_bits();
+      // TODO(binji): Share with similar float info in interp.cc and literal.cc
+      if ((f64_bits & 0x7ff0000000000000ull) == 0x7ff0000000000000ull) {
+        const char* sign = (f64_bits & 0x8000000000000000ull) ? "-" : "";
+        uint64_t significand = f64_bits & 0xfffffffffffffull;
+        if (significand == 0) {
+          // Infinity.
+          Writef("%sINFINITY", sign);
+        } else {
+          // Nan.
+          Writef("f64_reinterpret_i64(0x%016" PRIx64 ") /* %snan:0x%013" PRIx64
+                 " */",
+                 f64_bits, sign, significand);
+        }
+      } else if (f64_bits == 0x8000000000000000ull) {
+        // Negative zero. Special-cased so it isn't written as -0 below.
+        Writef("-0.0");
+      } else {
+        Writef("%.17g", Bitcast<double>(f64_bits));
+      }
+      break;
+    }
+
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::WriteInitExpr(const ExprList& expr_list) {
+  if (expr_list.empty())
+    return;
+
+  assert(expr_list.size() == 1);
+  const Expr* expr = &expr_list.front();
+  switch (expr_list.front().type()) {
+    case ExprType::Const:
+      Write(cast<ConstExpr>(expr)->const_);
+      break;
+
+    case ExprType::GlobalGet:
+      Write(GlobalVar(cast<GlobalGetExpr>(expr)->var));
+      break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+std::string CWriter::GenerateHeaderGuard() const {
+  std::string result;
+  for (char c : header_name_) {
+    if (isalnum(c) || c == '_') {
+      result += toupper(c);
+    } else {
+      result += '_';
+    }
+  }
+  result += "_GENERATED_";
+  return result;
+}
+
+void CWriter::WriteSourceTop() {
+  Write(s_source_includes);
+  Write(Newline(), "#include \"", header_name_, "\"", Newline());
+  Write(s_source_declarations);
+}
+
+void CWriter::WriteFuncTypes() {
+  Write(Newline());
+  Writef("static u32 func_types[%" PRIzd "];", module_->types.size());
+  Write(Newline(), Newline());
+  Write("static void init_func_types(void) {", Newline());
+  Index func_type_index = 0;
+  for (TypeEntry* type : module_->types) {
+    FuncType* func_type = cast<FuncType>(type);
+    Index num_params = func_type->GetNumParams();
+    Index num_results = func_type->GetNumResults();
+    Write("  func_types[", func_type_index, "] = wasm_rt_register_func_type(",
+          num_params, ", ", num_results);
+    for (Index i = 0; i < num_params; ++i) {
+      Write(", ", TypeEnum(func_type->GetParamType(i)));
+    }
+
+    for (Index i = 0; i < num_results; ++i) {
+      Write(", ", TypeEnum(func_type->GetResultType(i)));
+    }
+
+    Write(");", Newline());
+    ++func_type_index;
+  }
+  Write("}", Newline());
+}
+
+void CWriter::WriteImports() {
+  if (module_->imports.empty())
+    return;
+
+  Write(Newline());
+
+  // TODO(binji): Write imports ordered by type.
+  for (const Import* import : module_->imports) {
+    Write("/* import: '", import->module_name, "' '", import->field_name,
+          "' */", Newline());
+    Write("extern ");
+    switch (import->kind()) {
+      case ExternalKind::Func: {
+        const Func& func = cast<FuncImport>(import)->func;
+        WriteFuncDeclaration(
+            func.decl,
+            DefineImportName(
+                func.name, import->module_name,
+                MangleFuncName(import->field_name, func.decl.sig.param_types,
+                               func.decl.sig.result_types)));
+        Write(";");
+        break;
+      }
+
+      case ExternalKind::Global: {
+        const Global& global = cast<GlobalImport>(import)->global;
+        WriteGlobal(global,
+                    DefineImportName(
+                        global.name, import->module_name,
+                        MangleGlobalName(import->field_name, global.type)));
+        Write(";");
+        break;
+      }
+
+      case ExternalKind::Memory: {
+        const Memory& memory = cast<MemoryImport>(import)->memory;
+        WriteMemory(DefineImportName(memory.name, import->module_name,
+                                     MangleName(import->field_name)));
+        break;
+      }
+
+      case ExternalKind::Table: {
+        const Table& table = cast<TableImport>(import)->table;
+        WriteTable(DefineImportName(table.name, import->module_name,
+                                    MangleName(import->field_name)));
+        break;
+      }
+
+      default:
+        WABT_UNREACHABLE;
+    }
+
+    Write(Newline());
+  }
+}
+
+void CWriter::WriteFuncDeclarations() {
+  if (module_->funcs.size() == module_->num_func_imports)
+    return;
+
+  Write(Newline());
+
+  Index func_index = 0;
+  for (const Func* func : module_->funcs) {
+    bool is_import = func_index < module_->num_func_imports;
+    if (!is_import) {
+      Write("static ");
+      WriteFuncDeclaration(func->decl, DefineGlobalScopeName(func->name));
+      Write(";", Newline());
+    }
+    ++func_index;
+  }
+}
+
+void CWriter::WriteFuncDeclaration(const FuncDeclaration& decl,
+                                   const std::string& name) {
+  Write(ResultType(decl.sig.result_types), " ", name, "(");
+  if (decl.GetNumParams() == 0) {
+    Write("void");
+  } else {
+    for (Index i = 0; i < decl.GetNumParams(); ++i) {
+      if (i != 0)
+        Write(", ");
+      Write(decl.GetParamType(i));
+    }
+  }
+  Write(")");
+}
+
+void CWriter::WriteGlobals() {
+  Index global_index = 0;
+  if (module_->globals.size() != module_->num_global_imports) {
+    Write(Newline());
+
+    for (const Global* global : module_->globals) {
+      bool is_import = global_index < module_->num_global_imports;
+      if (!is_import) {
+        Write("static ");
+        WriteGlobal(*global, DefineGlobalScopeName(global->name));
+        Write(";", Newline());
+      }
+      ++global_index;
+    }
+  }
+
+  Write(Newline(), "static void init_globals(void) ", OpenBrace());
+  global_index = 0;
+  for (const Global* global : module_->globals) {
+    bool is_import = global_index < module_->num_global_imports;
+    if (!is_import) {
+      assert(!global->init_expr.empty());
+      Write(GlobalName(global->name), " = ");
+      WriteInitExpr(global->init_expr);
+      Write(";", Newline());
+    }
+    ++global_index;
+  }
+  Write(CloseBrace(), Newline());
+}
+
+void CWriter::WriteGlobal(const Global& global, const std::string& name) {
+  Write(global.type, " ", name);
+}
+
+void CWriter::WriteMemories() {
+  if (module_->memories.size() == module_->num_memory_imports)
+    return;
+
+  Write(Newline());
+
+  assert(module_->memories.size() <= 1);
+  Index memory_index = 0;
+  for (const Memory* memory : module_->memories) {
+    bool is_import = memory_index < module_->num_memory_imports;
+    if (!is_import) {
+      Write("static ");
+      WriteMemory(DefineGlobalScopeName(memory->name));
+      Write(Newline());
+    }
+    ++memory_index;
+  }
+}
+
+void CWriter::WriteMemory(const std::string& name) {
+  Write("wasm_rt_memory_t ", name, ";");
+}
+
+void CWriter::WriteTables() {
+  if (module_->tables.size() == module_->num_table_imports)
+    return;
+
+  Write(Newline());
+
+  assert(module_->tables.size() <= 1);
+  Index table_index = 0;
+  for (const Table* table : module_->tables) {
+    bool is_import = table_index < module_->num_table_imports;
+    if (!is_import) {
+      Write("static ");
+      WriteTable(DefineGlobalScopeName(table->name));
+      Write(Newline());
+    }
+    ++table_index;
+  }
+}
+
+void CWriter::WriteTable(const std::string& name) {
+  Write("wasm_rt_table_t ", name, ";");
+}
+
+void CWriter::WriteDataInitializers() {
+  const Memory* memory = nullptr;
+  Index data_segment_index = 0;
+
+  if (!module_->memories.empty()) {
+    if (module_->data_segments.empty()) {
+      Write(Newline());
+    } else {
+      for (const DataSegment* data_segment : module_->data_segments) {
+        Write(Newline(), "static const u8 data_segment_data_",
+              data_segment_index, "[] = ", OpenBrace());
+        size_t i = 0;
+        for (uint8_t x : data_segment->data) {
+          Writef("0x%02x, ", x);
+          if ((++i % 12) == 0)
+            Write(Newline());
+        }
+        if (i > 0)
+          Write(Newline());
+        Write(CloseBrace(), ";", Newline());
+        ++data_segment_index;
+      }
+    }
+
+    memory = module_->memories[0];
+  }
+
+  Write(Newline(), "static void init_memory(void) ", OpenBrace());
+  if (memory && module_->num_memory_imports == 0) {
+    uint32_t max =
+        memory->page_limits.has_max ? memory->page_limits.max : 65536;
+    Write("wasm_rt_allocate_memory(", ExternalPtr(memory->name), ", ",
+          memory->page_limits.initial, ", ", max, ");", Newline());
+  }
+  data_segment_index = 0;
+  for (const DataSegment* data_segment : module_->data_segments) {
+    Write("LOAD_DATA(", ExternalRef(memory->name), ", ");
+    WriteInitExpr(data_segment->offset);
+    Write(", data_segment_data_", data_segment_index, ", ",
+          data_segment->data.size(), ");", Newline());
+    ++data_segment_index;
+  }
+
+  Write(CloseBrace(), Newline());
+}
+
+void CWriter::WriteElemInitializers() {
+  const Table* table = module_->tables.empty() ? nullptr : module_->tables[0];
+
+  Write(Newline(), "static void init_table(void) ", OpenBrace());
+  Write("uint32_t offset;", Newline());
+  if (table && module_->num_table_imports == 0) {
+    uint32_t max =
+        table->elem_limits.has_max ? table->elem_limits.max : UINT32_MAX;
+    Write("wasm_rt_allocate_table(", ExternalPtr(table->name), ", ",
+          table->elem_limits.initial, ", ", max, ");", Newline());
+  }
+  Index elem_segment_index = 0;
+  for (const ElemSegment* elem_segment : module_->elem_segments) {
+    Write("offset = ");
+    WriteInitExpr(elem_segment->offset);
+    Write(";", Newline());
+
+    size_t i = 0;
+    for (const ElemExpr& elem_expr : elem_segment->elem_exprs) {
+      // We don't support the bulk-memory proposal here, so we know that we
+      // don't have any passive segments (where ref.null can be used).
+      assert(elem_expr.kind == ElemExprKind::RefFunc);
+      const Func* func = module_->GetFunc(elem_expr.var);
+      Index func_type_index = module_->GetFuncTypeIndex(func->decl.type_var);
+
+      Write(ExternalRef(table->name), ".data[offset + ", i,
+            "] = (wasm_rt_elem_t){func_types[", func_type_index,
+            "], (wasm_rt_anyfunc_t)", ExternalPtr(func->name), "};", Newline());
+      ++i;
+    }
+    ++elem_segment_index;
+  }
+
+  Write(CloseBrace(), Newline());
+}
+
+void CWriter::WriteInitExports() {
+  Write(Newline(), "static void init_exports(void) ", OpenBrace());
+  WriteExports(WriteExportsKind::Initializers);
+  Write(CloseBrace(), Newline());
+}
+
+void CWriter::WriteExports(WriteExportsKind kind) {
+  if (module_->exports.empty())
+    return;
+
+  if (kind != WriteExportsKind::Initializers) {
+    Write(Newline());
+  }
+
+  for (const Export* export_ : module_->exports) {
+    Write("/* export: '", export_->name, "' */", Newline());
+    if (kind == WriteExportsKind::Declarations) {
+      Write("extern ");
+    }
+
+    std::string mangled_name;
+    std::string internal_name;
+
+    switch (export_->kind) {
+      case ExternalKind::Func: {
+        const Func* func = module_->GetFunc(export_->var);
+        mangled_name =
+            ExportName(MangleFuncName(export_->name, func->decl.sig.param_types,
+                                      func->decl.sig.result_types));
+        internal_name = func->name;
+        if (kind != WriteExportsKind::Initializers) {
+          WriteFuncDeclaration(func->decl, Deref(mangled_name));
+          Write(";");
+        }
+        break;
+      }
+
+      case ExternalKind::Global: {
+        const Global* global = module_->GetGlobal(export_->var);
+        mangled_name =
+            ExportName(MangleGlobalName(export_->name, global->type));
+        internal_name = global->name;
+        if (kind != WriteExportsKind::Initializers) {
+          WriteGlobal(*global, Deref(mangled_name));
+          Write(";");
+        }
+        break;
+      }
+
+      case ExternalKind::Memory: {
+        const Memory* memory = module_->GetMemory(export_->var);
+        mangled_name = ExportName(MangleName(export_->name));
+        internal_name = memory->name;
+        if (kind != WriteExportsKind::Initializers) {
+          WriteMemory(Deref(mangled_name));
+        }
+        break;
+      }
+
+      case ExternalKind::Table: {
+        const Table* table = module_->GetTable(export_->var);
+        mangled_name = ExportName(MangleName(export_->name));
+        internal_name = table->name;
+        if (kind != WriteExportsKind::Initializers) {
+          WriteTable(Deref(mangled_name));
+        }
+        break;
+      }
+
+      default:
+        WABT_UNREACHABLE;
+    }
+
+    if (kind == WriteExportsKind::Initializers) {
+      Write(mangled_name, " = ", ExternalPtr(internal_name), ";");
+    }
+
+    Write(Newline());
+  }
+}
+
+void CWriter::WriteInit() {
+  Write(Newline(), "void WASM_RT_ADD_PREFIX(init)(void) ", OpenBrace());
+  Write("init_func_types();", Newline());
+  Write("init_globals();", Newline());
+  Write("init_memory();", Newline());
+  Write("init_table();", Newline());
+  Write("init_exports();", Newline());
+  for (Var* var : module_->starts) {
+    Write(ExternalRef(module_->GetFunc(*var)->name), "();", Newline());
+  }
+  Write(CloseBrace(), Newline());
+}
+
+void CWriter::WriteFuncs() {
+  Index func_index = 0;
+  for (const Func* func : module_->funcs) {
+    bool is_import = func_index < module_->num_func_imports;
+    if (!is_import)
+      Write(Newline(), *func, Newline());
+    ++func_index;
+  }
+}
+
+void CWriter::Write(const Func& func) {
+  func_ = &func;
+  // Copy symbols from global symbol table so we don't shadow them.
+  local_syms_ = global_syms_;
+  local_sym_map_.clear();
+  stack_var_sym_map_.clear();
+
+  Write("static ", ResultType(func.decl.sig.result_types), " ",
+        GlobalName(func.name), "(");
+  WriteParamsAndLocals();
+  Write("FUNC_PROLOGUE;", Newline());
+
+  stream_ = &func_stream_;
+  stream_->ClearOffset();
+
+  std::string label = DefineLocalScopeName(kImplicitFuncLabel);
+  ResetTypeStack(0);
+  std::string empty;  // Must not be temporary, since address is taken by Label.
+  PushLabel(LabelType::Func, empty, func.decl.sig);
+  Write(func.exprs, LabelDecl(label));
+  PopLabel();
+  ResetTypeStack(0);
+  PushTypes(func.decl.sig.result_types);
+  Write("FUNC_EPILOGUE;", Newline());
+
+  if (!func.decl.sig.result_types.empty()) {
+    // Return the top of the stack implicitly.
+    Write("return ", StackVar(0), ";", Newline());
+  }
+
+  stream_ = c_stream_;
+
+  WriteStackVarDeclarations();
+
+  std::unique_ptr<OutputBuffer> buf = func_stream_.ReleaseOutputBuffer();
+  stream_->WriteData(buf->data.data(), buf->data.size());
+
+  Write(CloseBrace());
+
+  func_stream_.Clear();
+  func_ = nullptr;
+}
+
+void CWriter::WriteParamsAndLocals() {
+  std::vector<std::string> index_to_name;
+  MakeTypeBindingReverseMapping(func_->GetNumParamsAndLocals(), func_->bindings,
+                                &index_to_name);
+  WriteParams(index_to_name);
+  WriteLocals(index_to_name);
+}
+
+void CWriter::WriteParams(const std::vector<std::string>& index_to_name) {
+  if (func_->GetNumParams() == 0) {
+    Write("void");
+  } else {
+    Indent(4);
+    for (Index i = 0; i < func_->GetNumParams(); ++i) {
+      if (i != 0) {
+        Write(", ");
+        if ((i % 8) == 0)
+          Write(Newline());
+      }
+      Write(func_->GetParamType(i), " ",
+            DefineLocalScopeName(index_to_name[i]));
+    }
+    Dedent(4);
+  }
+  Write(") ", OpenBrace());
+}
+
+void CWriter::WriteLocals(const std::vector<std::string>& index_to_name) {
+  Index num_params = func_->GetNumParams();
+  for (Type type : {Type::I32, Type::I64, Type::F32, Type::F64}) {
+    Index local_index = 0;
+    size_t count = 0;
+    for (Type local_type : func_->local_types) {
+      if (local_type == type) {
+        if (count == 0) {
+          Write(type, " ");
+          Indent(4);
+        } else {
+          Write(", ");
+          if ((count % 8) == 0)
+            Write(Newline());
+        }
+
+        Write(DefineLocalScopeName(index_to_name[num_params + local_index]),
+              " = 0");
+        ++count;
+      }
+      ++local_index;
+    }
+    if (count != 0) {
+      Dedent(4);
+      Write(";", Newline());
+    }
+  }
+}
+
+void CWriter::WriteStackVarDeclarations() {
+  for (Type type : {Type::I32, Type::I64, Type::F32, Type::F64}) {
+    size_t count = 0;
+    for (const auto& pair : stack_var_sym_map_) {
+      Type stp_type = pair.first.second;
+      const std::string& name = pair.second;
+
+      if (stp_type == type) {
+        if (count == 0) {
+          Write(type, " ");
+          Indent(4);
+        } else {
+          Write(", ");
+          if ((count % 8) == 0)
+            Write(Newline());
+        }
+
+        Write(name);
+        ++count;
+      }
+    }
+    if (count != 0) {
+      Dedent(4);
+      Write(";", Newline());
+    }
+  }
+}
+
+void CWriter::Write(const ExprList& exprs) {
+  for (const Expr& expr : exprs) {
+    switch (expr.type()) {
+      case ExprType::Binary:
+        Write(*cast<BinaryExpr>(&expr));
+        break;
+
+      case ExprType::Block: {
+        const Block& block = cast<BlockExpr>(&expr)->block;
+        std::string label = DefineLocalScopeName(block.label);
+        size_t mark = MarkTypeStack();
+        PushLabel(LabelType::Block, block.label, block.decl.sig);
+        Write(block.exprs, LabelDecl(label));
+        ResetTypeStack(mark);
+        PopLabel();
+        PushTypes(block.decl.sig.result_types);
+        break;
+      }
+
+      case ExprType::Br:
+        Write(GotoLabel(cast<BrExpr>(&expr)->var), Newline());
+        // Stop processing this ExprList, since the following are unreachable.
+        return;
+
+      case ExprType::BrIf:
+        Write("if (", StackVar(0), ") {");
+        DropTypes(1);
+        Write(GotoLabel(cast<BrIfExpr>(&expr)->var), "}", Newline());
+        break;
+
+      case ExprType::BrTable: {
+        const auto* bt_expr = cast<BrTableExpr>(&expr);
+        Write("switch (", StackVar(0), ") ", OpenBrace());
+        DropTypes(1);
+        Index i = 0;
+        for (const Var& var : bt_expr->targets) {
+          Write("case ", i++, ": ", GotoLabel(var), Newline());
+        }
+        Write("default: ");
+        Write(GotoLabel(bt_expr->default_target), Newline(), CloseBrace(),
+              Newline());
+        // Stop processing this ExprList, since the following are unreachable.
+        return;
+      }
+
+      case ExprType::Call: {
+        const Var& var = cast<CallExpr>(&expr)->var;
+        const Func& func = *module_->GetFunc(var);
+        Index num_params = func.GetNumParams();
+        Index num_results = func.GetNumResults();
+        assert(type_stack_.size() >= num_params);
+        if (num_results > 0) {
+          assert(num_results == 1);
+          Write(StackVar(num_params - 1, func.GetResultType(0)), " = ");
+        }
+
+        Write(GlobalVar(var), "(");
+        for (Index i = 0; i < num_params; ++i) {
+          if (i != 0) {
+            Write(", ");
+          }
+          Write(StackVar(num_params - i - 1));
+        }
+        Write(");", Newline());
+        DropTypes(num_params);
+        PushTypes(func.decl.sig.result_types);
+        break;
+      }
+
+      case ExprType::CallIndirect: {
+        const FuncDeclaration& decl = cast<CallIndirectExpr>(&expr)->decl;
+        Index num_params = decl.GetNumParams();
+        Index num_results = decl.GetNumResults();
+        assert(type_stack_.size() > num_params);
+        if (num_results > 0) {
+          assert(num_results == 1);
+          Write(StackVar(num_params, decl.GetResultType(0)), " = ");
+        }
+
+        assert(module_->tables.size() == 1);
+        const Table* table = module_->tables[0];
+
+        assert(decl.has_func_type);
+        Index func_type_index = module_->GetFuncTypeIndex(decl.type_var);
+
+        Write("CALL_INDIRECT(", ExternalRef(table->name), ", ");
+        WriteFuncDeclaration(decl, "(*)");
+        Write(", ", func_type_index, ", ", StackVar(0));
+        for (Index i = 0; i < num_params; ++i) {
+          Write(", ", StackVar(num_params - i));
+        }
+        Write(");", Newline());
+        DropTypes(num_params + 1);
+        PushTypes(decl.sig.result_types);
+        break;
+      }
+
+      case ExprType::Compare:
+        Write(*cast<CompareExpr>(&expr));
+        break;
+
+      case ExprType::Const: {
+        const Const& const_ = cast<ConstExpr>(&expr)->const_;
+        PushType(const_.type());
+        Write(StackVar(0), " = ", const_, ";", Newline());
+        break;
+      }
+
+      case ExprType::Convert:
+        Write(*cast<ConvertExpr>(&expr));
+        break;
+
+      case ExprType::Drop:
+        DropTypes(1);
+        break;
+
+      case ExprType::GlobalGet: {
+        const Var& var = cast<GlobalGetExpr>(&expr)->var;
+        PushType(module_->GetGlobal(var)->type);
+        Write(StackVar(0), " = ", GlobalVar(var), ";", Newline());
+        break;
+      }
+
+      case ExprType::GlobalSet: {
+        const Var& var = cast<GlobalSetExpr>(&expr)->var;
+        Write(GlobalVar(var), " = ", StackVar(0), ";", Newline());
+        DropTypes(1);
+        break;
+      }
+
+      case ExprType::If: {
+        const IfExpr& if_ = *cast<IfExpr>(&expr);
+        Write("if (", StackVar(0), ") ", OpenBrace());
+        DropTypes(1);
+        std::string label = DefineLocalScopeName(if_.true_.label);
+        size_t mark = MarkTypeStack();
+        PushLabel(LabelType::If, if_.true_.label, if_.true_.decl.sig);
+        Write(if_.true_.exprs, CloseBrace());
+        if (!if_.false_.empty()) {
+          ResetTypeStack(mark);
+          Write(" else ", OpenBrace(), if_.false_, CloseBrace());
+        }
+        ResetTypeStack(mark);
+        Write(Newline(), LabelDecl(label));
+        PopLabel();
+        PushTypes(if_.true_.decl.sig.result_types);
+        break;
+      }
+
+      case ExprType::Load:
+        Write(*cast<LoadExpr>(&expr));
+        break;
+
+      case ExprType::LocalGet: {
+        const Var& var = cast<LocalGetExpr>(&expr)->var;
+        PushType(func_->GetLocalType(var));
+        Write(StackVar(0), " = ", var, ";", Newline());
+        break;
+      }
+
+      case ExprType::LocalSet: {
+        const Var& var = cast<LocalSetExpr>(&expr)->var;
+        Write(var, " = ", StackVar(0), ";", Newline());
+        DropTypes(1);
+        break;
+      }
+
+      case ExprType::LocalTee: {
+        const Var& var = cast<LocalTeeExpr>(&expr)->var;
+        Write(var, " = ", StackVar(0), ";", Newline());
+        break;
+      }
+
+      case ExprType::Loop: {
+        const Block& block = cast<LoopExpr>(&expr)->block;
+        if (!block.exprs.empty()) {
+          Write(DefineLocalScopeName(block.label), ": ");
+          Indent();
+          size_t mark = MarkTypeStack();
+          PushLabel(LabelType::Loop, block.label, block.decl.sig);
+          Write(Newline(), block.exprs);
+          ResetTypeStack(mark);
+          PopLabel();
+          PushTypes(block.decl.sig.result_types);
+          Dedent();
+        }
+        break;
+      }
+
+      case ExprType::MemoryCopy:
+      case ExprType::DataDrop:
+      case ExprType::MemoryInit:
+      case ExprType::MemoryFill:
+      case ExprType::TableCopy:
+      case ExprType::ElemDrop:
+      case ExprType::TableInit:
+      case ExprType::TableGet:
+      case ExprType::TableSet:
+      case ExprType::TableGrow:
+      case ExprType::TableSize:
+      case ExprType::TableFill:
+      case ExprType::RefFunc:
+      case ExprType::RefNull:
+      case ExprType::RefIsNull:
+        UNIMPLEMENTED("...");
+        break;
+
+      case ExprType::MemoryGrow: {
+        assert(module_->memories.size() == 1);
+        Memory* memory = module_->memories[0];
+
+        Write(StackVar(0), " = wasm_rt_grow_memory(", ExternalPtr(memory->name),
+              ", ", StackVar(0), ");", Newline());
+        break;
+      }
+
+      case ExprType::MemorySize: {
+        assert(module_->memories.size() == 1);
+        Memory* memory = module_->memories[0];
+
+        PushType(Type::I32);
+        Write(StackVar(0), " = ", ExternalRef(memory->name), ".pages;",
+              Newline());
+        break;
+      }
+
+      case ExprType::Nop:
+        break;
+
+      case ExprType::Return:
+        // Goto the function label instead; this way we can do shared function
+        // cleanup code in one place.
+        Write(GotoLabel(Var(label_stack_.size() - 1)), Newline());
+        // Stop processing this ExprList, since the following are unreachable.
+        return;
+
+      case ExprType::Select: {
+        Type type = StackType(1);
+        Write(StackVar(2), " = ", StackVar(0), " ? ", StackVar(2), " : ",
+              StackVar(1), ";", Newline());
+        DropTypes(3);
+        PushType(type);
+        break;
+      }
+
+      case ExprType::Store:
+        Write(*cast<StoreExpr>(&expr));
+        break;
+
+      case ExprType::Unary:
+        Write(*cast<UnaryExpr>(&expr));
+        break;
+
+      case ExprType::Ternary:
+        Write(*cast<TernaryExpr>(&expr));
+        break;
+
+      case ExprType::SimdLaneOp: {
+        Write(*cast<SimdLaneOpExpr>(&expr));
+        break;
+      }
+
+      case ExprType::SimdShuffleOp: {
+        Write(*cast<SimdShuffleOpExpr>(&expr));
+        break;
+      }
+
+      case ExprType::LoadSplat:
+        Write(*cast<LoadSplatExpr>(&expr));
+        break;
+
+      case ExprType::Unreachable:
+        Write("UNREACHABLE;", Newline());
+        return;
+
+      case ExprType::AtomicLoad:
+      case ExprType::AtomicRmw:
+      case ExprType::AtomicRmwCmpxchg:
+      case ExprType::AtomicStore:
+      case ExprType::AtomicWait:
+      case ExprType::AtomicFence:
+      case ExprType::AtomicNotify:
+      case ExprType::Rethrow:
+      case ExprType::ReturnCall:
+      case ExprType::ReturnCallIndirect:
+      case ExprType::Throw:
+      case ExprType::Try:
+        UNIMPLEMENTED("...");
+        break;
+    }
+  }
+}
+
+void CWriter::WriteSimpleUnaryExpr(Opcode opcode, const char* op) {
+  Type result_type = opcode.GetResultType();
+  Write(StackVar(0, result_type), " = ", op, "(", StackVar(0), ");", Newline());
+  DropTypes(1);
+  PushType(opcode.GetResultType());
+}
+
+void CWriter::WriteInfixBinaryExpr(Opcode opcode,
+                                   const char* op,
+                                   AssignOp assign_op) {
+  Type result_type = opcode.GetResultType();
+  Write(StackVar(1, result_type));
+  if (assign_op == AssignOp::Allowed) {
+    Write(" ", op, "= ", StackVar(0));
+  } else {
+    Write(" = ", StackVar(1), " ", op, " ", StackVar(0));
+  }
+  Write(";", Newline());
+  DropTypes(2);
+  PushType(result_type);
+}
+
+void CWriter::WritePrefixBinaryExpr(Opcode opcode, const char* op) {
+  Type result_type = opcode.GetResultType();
+  Write(StackVar(1, result_type), " = ", op, "(", StackVar(1), ", ",
+        StackVar(0), ");", Newline());
+  DropTypes(2);
+  PushType(result_type);
+}
+
+void CWriter::WriteSignedBinaryExpr(Opcode opcode, const char* op) {
+  Type result_type = opcode.GetResultType();
+  Type type = opcode.GetParamType1();
+  assert(opcode.GetParamType2() == type);
+  Write(StackVar(1, result_type), " = (", type, ")((", SignedType(type), ")",
+        StackVar(1), " ", op, " (", SignedType(type), ")", StackVar(0), ");",
+        Newline());
+  DropTypes(2);
+  PushType(result_type);
+}
+
+void CWriter::Write(const BinaryExpr& expr) {
+  switch (expr.opcode) {
+    case Opcode::I32Add:
+    case Opcode::I64Add:
+    case Opcode::F32Add:
+    case Opcode::F64Add:
+      WriteInfixBinaryExpr(expr.opcode, "+");
+      break;
+
+    case Opcode::I32Sub:
+    case Opcode::I64Sub:
+    case Opcode::F32Sub:
+    case Opcode::F64Sub:
+      WriteInfixBinaryExpr(expr.opcode, "-");
+      break;
+
+    case Opcode::I32Mul:
+    case Opcode::I64Mul:
+    case Opcode::F32Mul:
+    case Opcode::F64Mul:
+      WriteInfixBinaryExpr(expr.opcode, "*");
+      break;
+
+    case Opcode::I32DivS:
+      WritePrefixBinaryExpr(expr.opcode, "I32_DIV_S");
+      break;
+
+    case Opcode::I64DivS:
+      WritePrefixBinaryExpr(expr.opcode, "I64_DIV_S");
+      break;
+
+    case Opcode::I32DivU:
+    case Opcode::I64DivU:
+      WritePrefixBinaryExpr(expr.opcode, "DIV_U");
+      break;
+
+    case Opcode::F32Div:
+    case Opcode::F64Div:
+      WriteInfixBinaryExpr(expr.opcode, "/");
+      break;
+
+    case Opcode::I32RemS:
+      WritePrefixBinaryExpr(expr.opcode, "I32_REM_S");
+      break;
+
+    case Opcode::I64RemS:
+      WritePrefixBinaryExpr(expr.opcode, "I64_REM_S");
+      break;
+
+    case Opcode::I32RemU:
+    case Opcode::I64RemU:
+      WritePrefixBinaryExpr(expr.opcode, "REM_U");
+      break;
+
+    case Opcode::I32And:
+    case Opcode::I64And:
+      WriteInfixBinaryExpr(expr.opcode, "&");
+      break;
+
+    case Opcode::I32Or:
+    case Opcode::I64Or:
+      WriteInfixBinaryExpr(expr.opcode, "|");
+      break;
+
+    case Opcode::I32Xor:
+    case Opcode::I64Xor:
+      WriteInfixBinaryExpr(expr.opcode, "^");
+      break;
+
+    case Opcode::I32Shl:
+    case Opcode::I64Shl:
+      Write(StackVar(1), " <<= (", StackVar(0), " & ",
+            GetShiftMask(expr.opcode.GetResultType()), ");", Newline());
+      DropTypes(1);
+      break;
+
+    case Opcode::I32ShrS:
+    case Opcode::I64ShrS: {
+      Type type = expr.opcode.GetResultType();
+      Write(StackVar(1), " = (", type, ")((", SignedType(type), ")",
+            StackVar(1), " >> (", StackVar(0), " & ", GetShiftMask(type), "));",
+            Newline());
+      DropTypes(1);
+      break;
+    }
+
+    case Opcode::I32ShrU:
+    case Opcode::I64ShrU:
+      Write(StackVar(1), " >>= (", StackVar(0), " & ",
+            GetShiftMask(expr.opcode.GetResultType()), ");", Newline());
+      DropTypes(1);
+      break;
+
+    case Opcode::I32Rotl:
+      WritePrefixBinaryExpr(expr.opcode, "I32_ROTL");
+      break;
+
+    case Opcode::I64Rotl:
+      WritePrefixBinaryExpr(expr.opcode, "I64_ROTL");
+      break;
+
+    case Opcode::I32Rotr:
+      WritePrefixBinaryExpr(expr.opcode, "I32_ROTR");
+      break;
+
+    case Opcode::I64Rotr:
+      WritePrefixBinaryExpr(expr.opcode, "I64_ROTR");
+      break;
+
+    case Opcode::F32Min:
+    case Opcode::F64Min:
+      WritePrefixBinaryExpr(expr.opcode, "FMIN");
+      break;
+
+    case Opcode::F32Max:
+    case Opcode::F64Max:
+      WritePrefixBinaryExpr(expr.opcode, "FMAX");
+      break;
+
+    case Opcode::F32Copysign:
+      WritePrefixBinaryExpr(expr.opcode, "copysignf");
+      break;
+
+    case Opcode::F64Copysign:
+      WritePrefixBinaryExpr(expr.opcode, "copysign");
+      break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(const CompareExpr& expr) {
+  switch (expr.opcode) {
+    case Opcode::I32Eq:
+    case Opcode::I64Eq:
+    case Opcode::F32Eq:
+    case Opcode::F64Eq:
+      WriteInfixBinaryExpr(expr.opcode, "==", AssignOp::Disallowed);
+      break;
+
+    case Opcode::I32Ne:
+    case Opcode::I64Ne:
+    case Opcode::F32Ne:
+    case Opcode::F64Ne:
+      WriteInfixBinaryExpr(expr.opcode, "!=", AssignOp::Disallowed);
+      break;
+
+    case Opcode::I32LtS:
+    case Opcode::I64LtS:
+      WriteSignedBinaryExpr(expr.opcode, "<");
+      break;
+
+    case Opcode::I32LtU:
+    case Opcode::I64LtU:
+    case Opcode::F32Lt:
+    case Opcode::F64Lt:
+      WriteInfixBinaryExpr(expr.opcode, "<", AssignOp::Disallowed);
+      break;
+
+    case Opcode::I32LeS:
+    case Opcode::I64LeS:
+      WriteSignedBinaryExpr(expr.opcode, "<=");
+      break;
+
+    case Opcode::I32LeU:
+    case Opcode::I64LeU:
+    case Opcode::F32Le:
+    case Opcode::F64Le:
+      WriteInfixBinaryExpr(expr.opcode, "<=", AssignOp::Disallowed);
+      break;
+
+    case Opcode::I32GtS:
+    case Opcode::I64GtS:
+      WriteSignedBinaryExpr(expr.opcode, ">");
+      break;
+
+    case Opcode::I32GtU:
+    case Opcode::I64GtU:
+    case Opcode::F32Gt:
+    case Opcode::F64Gt:
+      WriteInfixBinaryExpr(expr.opcode, ">", AssignOp::Disallowed);
+      break;
+
+    case Opcode::I32GeS:
+    case Opcode::I64GeS:
+      WriteSignedBinaryExpr(expr.opcode, ">=");
+      break;
+
+    case Opcode::I32GeU:
+    case Opcode::I64GeU:
+    case Opcode::F32Ge:
+    case Opcode::F64Ge:
+      WriteInfixBinaryExpr(expr.opcode, ">=", AssignOp::Disallowed);
+      break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(const ConvertExpr& expr) {
+  switch (expr.opcode) {
+    case Opcode::I32Eqz:
+    case Opcode::I64Eqz:
+      WriteSimpleUnaryExpr(expr.opcode, "!");
+      break;
+
+    case Opcode::I64ExtendI32S:
+      WriteSimpleUnaryExpr(expr.opcode, "(u64)(s64)(s32)");
+      break;
+
+    case Opcode::I64ExtendI32U:
+      WriteSimpleUnaryExpr(expr.opcode, "(u64)");
+      break;
+
+    case Opcode::I32WrapI64:
+      WriteSimpleUnaryExpr(expr.opcode, "(u32)");
+      break;
+
+    case Opcode::I32TruncF32S:
+      WriteSimpleUnaryExpr(expr.opcode, "I32_TRUNC_S_F32");
+      break;
+
+    case Opcode::I64TruncF32S:
+      WriteSimpleUnaryExpr(expr.opcode, "I64_TRUNC_S_F32");
+      break;
+
+    case Opcode::I32TruncF64S:
+      WriteSimpleUnaryExpr(expr.opcode, "I32_TRUNC_S_F64");
+      break;
+
+    case Opcode::I64TruncF64S:
+      WriteSimpleUnaryExpr(expr.opcode, "I64_TRUNC_S_F64");
+      break;
+
+    case Opcode::I32TruncF32U:
+      WriteSimpleUnaryExpr(expr.opcode, "I32_TRUNC_U_F32");
+      break;
+
+    case Opcode::I64TruncF32U:
+      WriteSimpleUnaryExpr(expr.opcode, "I64_TRUNC_U_F32");
+      break;
+
+    case Opcode::I32TruncF64U:
+      WriteSimpleUnaryExpr(expr.opcode, "I32_TRUNC_U_F64");
+      break;
+
+    case Opcode::I64TruncF64U:
+      WriteSimpleUnaryExpr(expr.opcode, "I64_TRUNC_U_F64");
+      break;
+
+    case Opcode::I32TruncSatF32S:
+    case Opcode::I64TruncSatF32S:
+    case Opcode::I32TruncSatF64S:
+    case Opcode::I64TruncSatF64S:
+    case Opcode::I32TruncSatF32U:
+    case Opcode::I64TruncSatF32U:
+    case Opcode::I32TruncSatF64U:
+    case Opcode::I64TruncSatF64U:
+      UNIMPLEMENTED(expr.opcode.GetName());
+      break;
+
+    case Opcode::F32ConvertI32S:
+      WriteSimpleUnaryExpr(expr.opcode, "(f32)(s32)");
+      break;
+
+    case Opcode::F32ConvertI64S:
+      WriteSimpleUnaryExpr(expr.opcode, "(f32)(s64)");
+      break;
+
+    case Opcode::F32ConvertI32U:
+    case Opcode::F32DemoteF64:
+      WriteSimpleUnaryExpr(expr.opcode, "(f32)");
+      break;
+
+    case Opcode::F32ConvertI64U:
+      // TODO(binji): This needs to be handled specially (see
+      // wabt_convert_uint64_to_float).
+      WriteSimpleUnaryExpr(expr.opcode, "(f32)");
+      break;
+
+    case Opcode::F64ConvertI32S:
+      WriteSimpleUnaryExpr(expr.opcode, "(f64)(s32)");
+      break;
+
+    case Opcode::F64ConvertI64S:
+      WriteSimpleUnaryExpr(expr.opcode, "(f64)(s64)");
+      break;
+
+    case Opcode::F64ConvertI32U:
+    case Opcode::F64PromoteF32:
+      WriteSimpleUnaryExpr(expr.opcode, "(f64)");
+      break;
+
+    case Opcode::F64ConvertI64U:
+      // TODO(binji): This needs to be handled specially (see
+      // wabt_convert_uint64_to_double).
+      WriteSimpleUnaryExpr(expr.opcode, "(f64)");
+      break;
+
+    case Opcode::F32ReinterpretI32:
+      WriteSimpleUnaryExpr(expr.opcode, "f32_reinterpret_i32");
+      break;
+
+    case Opcode::I32ReinterpretF32:
+      WriteSimpleUnaryExpr(expr.opcode, "i32_reinterpret_f32");
+      break;
+
+    case Opcode::F64ReinterpretI64:
+      WriteSimpleUnaryExpr(expr.opcode, "f64_reinterpret_i64");
+      break;
+
+    case Opcode::I64ReinterpretF64:
+      WriteSimpleUnaryExpr(expr.opcode, "i64_reinterpret_f64");
+      break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(const LoadExpr& expr) {
+  const char* func = nullptr;
+  switch (expr.opcode) {
+    case Opcode::I32Load: func = "i32_load"; break;
+    case Opcode::I64Load: func = "i64_load"; break;
+    case Opcode::F32Load: func = "f32_load"; break;
+    case Opcode::F64Load: func = "f64_load"; break;
+    case Opcode::I32Load8S: func = "i32_load8_s"; break;
+    case Opcode::I64Load8S: func = "i64_load8_s"; break;
+    case Opcode::I32Load8U: func = "i32_load8_u"; break;
+    case Opcode::I64Load8U: func = "i64_load8_u"; break;
+    case Opcode::I32Load16S: func = "i32_load16_s"; break;
+    case Opcode::I64Load16S: func = "i64_load16_s"; break;
+    case Opcode::I32Load16U: func = "i32_load16_u"; break;
+    case Opcode::I64Load16U: func = "i64_load16_u"; break;
+    case Opcode::I64Load32S: func = "i64_load32_s"; break;
+    case Opcode::I64Load32U: func = "i64_load32_u"; break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+
+  assert(module_->memories.size() == 1);
+  Memory* memory = module_->memories[0];
+
+  Type result_type = expr.opcode.GetResultType();
+  Write(StackVar(0, result_type), " = ", func, "(", ExternalPtr(memory->name),
+        ", (u64)(", StackVar(0), ")");
+  if (expr.offset != 0)
+    Write(" + ", expr.offset, "u");
+  Write(");", Newline());
+  DropTypes(1);
+  PushType(result_type);
+}
+
+void CWriter::Write(const StoreExpr& expr) {
+  const char* func = nullptr;
+  switch (expr.opcode) {
+    case Opcode::I32Store: func = "i32_store"; break;
+    case Opcode::I64Store: func = "i64_store"; break;
+    case Opcode::F32Store: func = "f32_store"; break;
+    case Opcode::F64Store: func = "f64_store"; break;
+    case Opcode::I32Store8: func = "i32_store8"; break;
+    case Opcode::I64Store8: func = "i64_store8"; break;
+    case Opcode::I32Store16: func = "i32_store16"; break;
+    case Opcode::I64Store16: func = "i64_store16"; break;
+    case Opcode::I64Store32: func = "i64_store32"; break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+
+  assert(module_->memories.size() == 1);
+  Memory* memory = module_->memories[0];
+
+  Write(func, "(", ExternalPtr(memory->name), ", (u64)(", StackVar(1), ")");
+  if (expr.offset != 0)
+    Write(" + ", expr.offset);
+  Write(", ", StackVar(0), ");", Newline());
+  DropTypes(2);
+}
+
+void CWriter::Write(const UnaryExpr& expr) {
+  switch (expr.opcode) {
+    case Opcode::I32Clz:
+      WriteSimpleUnaryExpr(expr.opcode, "I32_CLZ");
+      break;
+
+    case Opcode::I64Clz:
+      WriteSimpleUnaryExpr(expr.opcode, "I64_CLZ");
+      break;
+
+    case Opcode::I32Ctz:
+      WriteSimpleUnaryExpr(expr.opcode, "I32_CTZ");
+      break;
+
+    case Opcode::I64Ctz:
+      WriteSimpleUnaryExpr(expr.opcode, "I64_CTZ");
+      break;
+
+    case Opcode::I32Popcnt:
+      WriteSimpleUnaryExpr(expr.opcode, "I32_POPCNT");
+      break;
+
+    case Opcode::I64Popcnt:
+      WriteSimpleUnaryExpr(expr.opcode, "I64_POPCNT");
+      break;
+
+    case Opcode::F32Neg:
+    case Opcode::F64Neg:
+      WriteSimpleUnaryExpr(expr.opcode, "-");
+      break;
+
+    case Opcode::F32Abs:
+      WriteSimpleUnaryExpr(expr.opcode, "fabsf");
+      break;
+
+    case Opcode::F64Abs:
+      WriteSimpleUnaryExpr(expr.opcode, "fabs");
+      break;
+
+    case Opcode::F32Sqrt:
+      WriteSimpleUnaryExpr(expr.opcode, "sqrtf");
+      break;
+
+    case Opcode::F64Sqrt:
+      WriteSimpleUnaryExpr(expr.opcode, "sqrt");
+      break;
+
+    case Opcode::F32Ceil:
+      WriteSimpleUnaryExpr(expr.opcode, "ceilf");
+      break;
+
+    case Opcode::F64Ceil:
+      WriteSimpleUnaryExpr(expr.opcode, "ceil");
+      break;
+
+    case Opcode::F32Floor:
+      WriteSimpleUnaryExpr(expr.opcode, "floorf");
+      break;
+
+    case Opcode::F64Floor:
+      WriteSimpleUnaryExpr(expr.opcode, "floor");
+      break;
+
+    case Opcode::F32Trunc:
+      WriteSimpleUnaryExpr(expr.opcode, "truncf");
+      break;
+
+    case Opcode::F64Trunc:
+      WriteSimpleUnaryExpr(expr.opcode, "trunc");
+      break;
+
+    case Opcode::F32Nearest:
+      WriteSimpleUnaryExpr(expr.opcode, "nearbyintf");
+      break;
+
+    case Opcode::F64Nearest:
+      WriteSimpleUnaryExpr(expr.opcode, "nearbyint");
+      break;
+
+    case Opcode::I32Extend8S:
+    case Opcode::I32Extend16S:
+    case Opcode::I64Extend8S:
+    case Opcode::I64Extend16S:
+    case Opcode::I64Extend32S:
+      UNIMPLEMENTED(expr.opcode.GetName());
+      break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(const TernaryExpr& expr) {
+  switch (expr.opcode) {
+    case Opcode::V128BitSelect: {
+      Type result_type = expr.opcode.GetResultType();
+      Write(StackVar(2, result_type), " = ", "v128.bitselect", "(", StackVar(0),
+            ", ", StackVar(1), ", ", StackVar(2), ");", Newline());
+      DropTypes(3);
+      PushType(result_type);
+      break;
+    }
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+void CWriter::Write(const SimdLaneOpExpr& expr) {
+  Type result_type = expr.opcode.GetResultType();
+
+  switch (expr.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: {
+      Write(StackVar(0, result_type), " = ", expr.opcode.GetName(), "(",
+            StackVar(0), ", lane Imm: ", expr.val, ");", Newline());
+      DropTypes(1);
+      break;
+    }
+    case Opcode::I8X16ReplaceLane:
+    case Opcode::I16X8ReplaceLane:
+    case Opcode::I32X4ReplaceLane:
+    case Opcode::I64X2ReplaceLane:
+    case Opcode::F32X4ReplaceLane:
+    case Opcode::F64X2ReplaceLane: {
+      Write(StackVar(1, result_type), " = ", expr.opcode.GetName(), "(",
+            StackVar(0), ", ", StackVar(1), ", lane Imm: ", expr.val, ");",
+            Newline());
+      DropTypes(2);
+      break;
+    }
+    default:
+      WABT_UNREACHABLE;
+  }
+
+  PushType(result_type);
+}
+
+void CWriter::Write(const SimdShuffleOpExpr& expr) {
+  Type result_type = expr.opcode.GetResultType();
+  Write(StackVar(1, result_type), " = ", expr.opcode.GetName(), "(",
+        StackVar(1), " ", StackVar(0), ", lane Imm: $0x%08x %08x %08x %08x",
+        expr.val.u32(0), expr.val.u32(1), expr.val.u32(2), expr.val.u32(3), ")",
+        Newline());
+  DropTypes(2);
+  PushType(result_type);
+}
+
+void CWriter::Write(const LoadSplatExpr& expr) {
+  assert(module_->memories.size() == 1);
+  Memory* memory = module_->memories[0];
+
+  Type result_type = expr.opcode.GetResultType();
+  Write(StackVar(0, result_type), " = ", expr.opcode.GetName(), "(",
+        ExternalPtr(memory->name), ", (u64)(", StackVar(0));
+  if (expr.offset != 0)
+    Write(" + ", expr.offset);
+  Write("));", Newline());
+  DropTypes(1);
+  PushType(result_type);
+}
+
+void CWriter::WriteCHeader() {
+  stream_ = h_stream_;
+  std::string guard = GenerateHeaderGuard();
+  Write("#ifndef ", guard, Newline());
+  Write("#define ", guard, Newline());
+  Write(s_header_top);
+  WriteImports();
+  WriteExports(WriteExportsKind::Declarations);
+  Write(s_header_bottom);
+  Write(Newline(), "#endif  /* ", guard, " */", Newline());
+}
+
+void CWriter::WriteCSource() {
+  stream_ = c_stream_;
+  WriteSourceTop();
+  WriteFuncTypes();
+  WriteFuncDeclarations();
+  WriteGlobals();
+  WriteMemories();
+  WriteTables();
+  WriteFuncs();
+  WriteDataInitializers();
+  WriteElemInitializers();
+  WriteExports(WriteExportsKind::Definitions);
+  WriteInitExports();
+  WriteInit();
+}
+
+Result CWriter::WriteModule(const Module& module) {
+  WABT_USE(options_);
+  module_ = &module;
+  WriteCHeader();
+  WriteCSource();
+  return result_;
+}
+
+}  // end anonymous namespace
+
+Result WriteC(Stream* c_stream,
+              Stream* h_stream,
+              const char* header_name,
+              const Module* module,
+              const WriteCOptions& options) {
+  CWriter c_writer(c_stream, h_stream, header_name, options);
+  return c_writer.WriteModule(*module);
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/c-writer.h
new file mode 100644 (file)
index 0000000..8b3b44d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_C_WRITER_H_
+#define WABT_C_WRITER_H_
+
+#include "src/common.h"
+
+namespace wabt {
+
+struct Module;
+class Stream;
+
+struct WriteCOptions {};
+
+Result WriteC(Stream* c_stream,
+              Stream* h_stream,
+              const char* header_name,
+              const Module*,
+              const WriteCOptions&);
+
+}  // namespace wabt
+
+#endif /* WABT_C_WRITER_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/cast.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/cast.h
new file mode 100644 (file)
index 0000000..7275415
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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_CAST_H_
+#define WABT_CAST_H_
+
+#include <memory>
+#include <type_traits>
+
+#include "src/common.h"
+
+// Modeled after LLVM's dynamic casts:
+// http://llvm.org/docs/ProgrammersManual.html#the-isa-cast-and-dyn-cast-templates
+//
+// Use isa<T>(foo) to check whether foo is a T*:
+//
+//     if (isa<Minivan>(car)) {
+//        ...
+//     }
+//
+// Use cast<T>(foo) when you know that foo is a T* -- it will assert that the
+// type matches:
+//
+//     switch (car.type) {
+//       case CarType::Minivan: {
+//         auto minivan = cast<Minivan>(car);
+//         ...
+//       }
+//     }
+//
+// Use dyn_cast<T>(foo) as a combination if isa and cast, it will return
+// nullptr if the type doesn't match:
+//
+//     if (auto minivan = dyn_cast<Minivan>(car)) {
+//       ...
+//     }
+//
+//
+// To use these classes in a type hierarchy, you must implement classof:
+//
+//     enum CarType { Minivan, ... };
+//     struct Car { CarType type; ... };
+//     struct Minivan : Car {
+//       static bool classof(const Car* car) { return car->type == Minivan; }
+//       ...
+//     };
+//
+
+namespace wabt {
+
+template <typename Derived, typename Base>
+bool isa(const Base* base) {
+  WABT_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
+  return Derived::classof(base);
+}
+
+template <typename Derived, typename Base>
+const Derived* cast(const Base* base) {
+  assert(isa<Derived>(base));
+  return static_cast<const Derived*>(base);
+};
+
+template <typename Derived, typename Base>
+Derived* cast(Base* base) {
+  assert(isa<Derived>(base));
+  return static_cast<Derived*>(base);
+};
+
+template <typename Derived, typename Base>
+const Derived* dyn_cast(const Base* base) {
+  return isa<Derived>(base) ? static_cast<const Derived*>(base) : nullptr;
+};
+
+template <typename Derived, typename Base>
+Derived* dyn_cast(Base* base) {
+  return isa<Derived>(base) ? static_cast<Derived*>(base) : nullptr;
+};
+
+// Cast functionality for unique_ptr. isa and dyn_cast are not included because
+// they won't always pass ownership back to the caller.
+
+template <typename Derived, typename Base>
+std::unique_ptr<const Derived> cast(std::unique_ptr<const Base>&& base) {
+  assert(isa<Derived>(base.get()));
+  return std::unique_ptr<Derived>(static_cast<const Derived*>(base.release()));
+};
+
+template <typename Derived, typename Base>
+std::unique_ptr<Derived> cast(std::unique_ptr<Base>&& base) {
+  assert(isa<Derived>(base.get()));
+  return std::unique_ptr<Derived>(static_cast<Derived*>(base.release()));
+};
+
+}  // namespace wabt
+
+#endif  // WABT_CAST_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/circular-array.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/circular-array.h
new file mode 100644 (file)
index 0000000..afdead7
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * 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_CIRCULAR_ARRAY_H_
+#define WABT_CIRCULAR_ARRAY_H_
+
+#include <array>
+#include <cassert>
+#include <cstddef>
+#include <type_traits>
+
+namespace wabt {
+
+// TODO(karlschimpf) Complete the API
+// Note: Capacity must be a power of 2.
+template <class T, size_t kCapacity>
+class CircularArray {
+ public:
+  typedef T value_type;
+  typedef value_type& reference;
+  typedef const value_type& const_reference;
+  typedef size_t size_type;
+  typedef ptrdiff_t difference_type;
+
+  CircularArray() {
+    static_assert(kCapacity && ((kCapacity & (kCapacity - 1)) == 0),
+                  "Capacity must be a power of 2.");
+  }
+
+  CircularArray(const CircularArray&) = default;
+  CircularArray& operator=(const CircularArray&) = default;
+
+  CircularArray(CircularArray&&) = default;
+  CircularArray& operator=(CircularArray&&) = default;
+
+  ~CircularArray() { clear(); }
+
+  reference at(size_type index) {
+    assert(index < size_);
+    return (*this)[index];
+  }
+
+  const_reference at(size_type index) const {
+    assert(index < size_);
+    return (*this)[index];
+  }
+
+  reference operator[](size_type index) { return contents_[position(index)]; }
+
+  const_reference operator[](size_type index) const {
+    return contents_[position(index)];
+  }
+
+  reference back() { return at(size_ - 1); }
+
+  const_reference back() const { return at(size_ - 1); }
+
+  bool empty() const { return size_ == 0; }
+
+  reference front() { return at(0); }
+
+  const_reference front() const { return at(0); }
+
+  size_type max_size() const { return kCapacity; }
+
+  void pop_back() {
+    assert(size_ > 0);
+    SetElement(back());
+    --size_;
+  }
+
+  void pop_front() {
+    assert(size_ > 0);
+    SetElement(front());
+    front_ = (front_ + 1) & kMask;
+    --size_;
+  }
+
+  void push_back(const value_type& value) {
+    assert(size_ < kCapacity);
+    SetElement(at(size_++), value);
+  }
+
+  size_type size() const { return size_; }
+
+  void clear() {
+    while (!empty()) {
+      pop_back();
+    }
+  }
+
+ private:
+  static const size_type kMask = kCapacity - 1;
+
+  size_t position(size_t index) const { return (front_ + index) & kMask; }
+
+  template <typename... Args>
+  void SetElement(reference element, Args&&... args) {
+    element.~T();
+    new (&element) T(std::forward<Args>(args)...);
+  }
+
+  std::array<T, kCapacity> contents_;
+  size_type size_ = 0;
+  size_type front_ = 0;
+};
+
+}  // namespace wabt
+
+#endif  // WABT_CIRCULAR_ARRAY_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.cc
new file mode 100644 (file)
index 0000000..8fdc5d0
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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/color.h"
+
+#include <cstdlib>
+
+#include "src/common.h"
+
+#if _WIN32
+#include <io.h>
+#include <windows.h>
+#elif HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+namespace wabt {
+
+Color::Color(FILE* file, bool enabled) : file_(file) {
+  enabled_ = enabled && SupportsColor(file_);
+}
+
+// static
+bool Color::SupportsColor(FILE* file) {
+  char* force = getenv("FORCE_COLOR");
+  if (force) {
+    return atoi(force) != 0;
+  }
+
+#if _WIN32
+
+  {
+#if HAVE_WIN32_VT100
+    HANDLE handle;
+    if (file == stdout) {
+      handle = GetStdHandle(STD_OUTPUT_HANDLE);
+    } else if (file == stderr) {
+      handle = GetStdHandle(STD_ERROR_HANDLE);
+    } else {
+      return false;
+    }
+    DWORD mode;
+    if (!_isatty(_fileno(file)) || !GetConsoleMode(handle, &mode) ||
+        !SetConsoleMode(handle, mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) {
+      return false;
+    }
+    return true;
+#else
+    // TODO(binji): Support older Windows by using SetConsoleTextAttribute?
+    return false;
+#endif
+  }
+
+#elif HAVE_UNISTD_H
+
+  return isatty(fileno(file));
+
+#else
+
+  return false;
+
+#endif
+}
+
+void Color::WriteCode(const char* code) const {
+  if (enabled_) {
+    fputs(code, file_);
+  }
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/color.h
new file mode 100644 (file)
index 0000000..8af57f3
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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_COLOR_H_
+#define WABT_COLOR_H_
+
+#include <cstdio>
+
+namespace wabt {
+
+#define WABT_FOREACH_COLOR_CODE(V) \
+  V(Default, "\x1b[0m")            \
+  V(Bold, "\x1b[1m")               \
+  V(NoBold, "\x1b[22m")            \
+  V(Black, "\x1b[30m")             \
+  V(Red, "\x1b[31m")               \
+  V(Green, "\x1b[32m")             \
+  V(Yellow, "\x1b[33m")            \
+  V(Blue, "\x1b[34m")              \
+  V(Magenta, "\x1b[35m")           \
+  V(Cyan, "\x1b[36m")              \
+  V(White, "\x1b[37m")
+
+class Color {
+ public:
+  Color() : file_(nullptr), enabled_(false) {}
+  Color(FILE*, bool enabled = true);
+
+// Write the given color to the file, if enabled.
+#define WABT_COLOR(Name, code) \
+  void Name() const { WriteCode(Name##Code()); }
+  WABT_FOREACH_COLOR_CODE(WABT_COLOR)
+#undef WABT_COLOR
+
+// Get the color code as a string, if enabled.
+#define WABT_COLOR(Name, code) \
+  const char* Maybe##Name##Code() const { return enabled_ ? Name##Code() : ""; }
+  WABT_FOREACH_COLOR_CODE(WABT_COLOR)
+#undef WABT_COLOR
+
+// Get the color code as a string.
+#define WABT_COLOR(Name, code) \
+  static const char* Name##Code() { return code; }
+  WABT_FOREACH_COLOR_CODE(WABT_COLOR)
+#undef WABT_COLOR
+
+ private:
+  static bool SupportsColor(FILE*);
+  void WriteCode(const char*) const;
+
+  FILE* file_;
+  bool enabled_;
+};
+
+#undef WABT_FOREACH_COLOR_CODE
+
+}  // namespace wabt
+
+#endif  //  WABT_COLOR_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.cc
new file mode 100644 (file)
index 0000000..e8dd149
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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/common.h"
+
+#include <cassert>
+#include <climits>
+#include <cstdint>
+#include <cstdio>
+#include <cstring>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#if COMPILER_IS_MSVC
+#include <fcntl.h>
+#include <io.h>
+#include <stdlib.h>
+#define PATH_MAX _MAX_PATH
+#define stat _stat
+#define S_IFREG _S_IFREG
+#endif
+
+namespace wabt {
+
+Reloc::Reloc(RelocType type, Offset offset, Index index, int32_t addend)
+    : type(type), offset(offset), index(index), addend(addend) {}
+
+const char* g_kind_name[] = {"func", "table", "memory", "global", "event"};
+WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_kind_name) == kExternalKindCount);
+
+const char* g_reloc_type_name[] = {
+    "R_WASM_FUNCTION_INDEX_LEB",   "R_WASM_TABLE_INDEX_SLEB",
+    "R_WASM_TABLE_INDEX_I32",      "R_WASM_MEMORY_ADDR_LEB",
+    "R_WASM_MEMORY_ADDR_SLEB",     "R_WASM_MEMORY_ADDR_I32",
+    "R_WASM_TYPE_INDEX_LEB",       "R_WASM_GLOBAL_INDEX_LEB",
+    "R_WASM_FUNCTION_OFFSET_I32",  "R_WASM_SECTION_OFFSET_I32",
+    "R_WASM_EVENT_INDEX_LEB",      "R_WASM_MEMORY_ADDR_REL_SLEB",
+    "R_WASM_TABLE_INDEX_REL_SLEB", "R_WASM_GLOBAL_INDEX_I32",
+    "R_WASM_MEMORY_ADDR_LEB64",    "R_WASM_MEMORY_ADDR_SLEB64",
+    "R_WASM_MEMORY_ADDR_I64",      "R_WASM_MEMORY_ADDR_REL_SLEB64",
+    "R_WASM_TABLE_INDEX_SLEB64",   "R_WASM_TABLE_INDEX_I64",
+    "R_WASM_TABLE_NUMBER_LEB",     "R_WASM_MEMORY_ADDR_TLS_SLEB",
+    "R_WASM_MEMORY_ADDR_TLS_I32",
+};
+WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(g_reloc_type_name) == kRelocTypeCount);
+
+static Result ReadStdin(std::vector<uint8_t>* out_data) {
+  out_data->resize(0);
+  uint8_t buffer[4096];
+  while (true) {
+    size_t bytes_read = fread(buffer, 1, sizeof(buffer), stdin);
+    if (bytes_read == 0) {
+      if (ferror(stdin)) {
+        fprintf(stderr, "error reading from stdin: %s\n", strerror(errno));
+        return Result::Error;
+      }
+      return Result::Ok;
+    }
+    size_t old_size = out_data->size();
+    out_data->resize(old_size + bytes_read);
+    memcpy(out_data->data() + old_size, buffer, bytes_read);
+  }
+}
+
+Result ReadFile(string_view filename, std::vector<uint8_t>* out_data) {
+  std::string filename_str = filename.to_string();
+  const char* filename_cstr = filename_str.c_str();
+
+  if (filename == "-") {
+    return ReadStdin(out_data);
+  }
+
+  struct stat statbuf;
+  if (stat(filename_cstr, &statbuf) < 0) {
+    fprintf(stderr, "%s: %s\n", filename_cstr, strerror(errno));
+    return Result::Error;
+  }
+
+  if (!(statbuf.st_mode & S_IFREG)) {
+    fprintf(stderr, "%s: not a regular file\n", filename_cstr);
+    return Result::Error;
+  }
+
+  FILE* infile = fopen(filename_cstr, "rb");
+  if (!infile) {
+    fprintf(stderr, "%s: %s\n", filename_cstr, strerror(errno));
+    return Result::Error;
+  }
+
+  if (fseek(infile, 0, SEEK_END) < 0) {
+    perror("fseek to end failed");
+    fclose(infile);
+    return Result::Error;
+  }
+
+  long size = ftell(infile);
+  if (size < 0) {
+    perror("ftell failed");
+    fclose(infile);
+    return Result::Error;
+  }
+
+  if (fseek(infile, 0, SEEK_SET) < 0) {
+    perror("fseek to beginning failed");
+    fclose(infile);
+    return Result::Error;
+  }
+
+  out_data->resize(size);
+  if (size != 0 && fread(out_data->data(), size, 1, infile) != 1) {
+    fprintf(stderr, "%s: fread failed: %s\n", filename_cstr, strerror(errno));
+    fclose(infile);
+    return Result::Error;
+  }
+
+  fclose(infile);
+  return Result::Ok;
+}
+
+void InitStdio() {
+#if COMPILER_IS_MSVC
+  int result = _setmode(_fileno(stdout), _O_BINARY);
+  if (result == -1) {
+    perror("Cannot set mode binary to stdout");
+  }
+  result = _setmode(_fileno(stderr), _O_BINARY);
+  if (result == -1) {
+    perror("Cannot set mode binary to stderr");
+  }
+#endif
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/common.h
new file mode 100644 (file)
index 0000000..1c0a57e
--- /dev/null
@@ -0,0 +1,475 @@
+/*
+ * 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_COMMON_H_
+#define WABT_COMMON_H_
+
+#include <algorithm>
+#include <cassert>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "config.h"
+
+#include "src/make-unique.h"
+#include "src/result.h"
+#include "src/string-view.h"
+#include "src/type.h"
+
+#define WABT_FATAL(...) fprintf(stderr, __VA_ARGS__), exit(1)
+#define WABT_ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+#define WABT_USE(x) static_cast<void>(x)
+
+#define WABT_PAGE_SIZE 0x10000 /* 64k */
+#define WABT_MAX_PAGES 0x10000 /* # of pages that fit in 32-bit address space \
+                                */
+#define WABT_BYTES_TO_PAGES(x) ((x) >> 16)
+#define WABT_ALIGN_UP_TO_PAGE(x) \
+  (((x) + WABT_PAGE_SIZE - 1) & ~(WABT_PAGE_SIZE - 1))
+
+#define PRIstringview "%.*s"
+#define WABT_PRINTF_STRING_VIEW_ARG(x) \
+  static_cast<int>((x).length()), (x).data()
+
+#define PRItypecode "%s%#x"
+#define WABT_PRINTF_TYPE_CODE(x) \
+  (static_cast<int32_t>(x) < 0 ? "-" : ""), std::abs(static_cast<int32_t>(x))
+
+#define WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE 128
+#define WABT_SNPRINTF_ALLOCA(buffer, len, format)                          \
+  va_list args;                                                            \
+  va_list args_copy;                                                       \
+  va_start(args, format);                                                  \
+  va_copy(args_copy, args);                                                \
+  char fixed_buf[WABT_DEFAULT_SNPRINTF_ALLOCA_BUFSIZE];                    \
+  char* buffer = fixed_buf;                                                \
+  size_t len = wabt_vsnprintf(fixed_buf, sizeof(fixed_buf), format, args); \
+  (void)len;                                                               \
+  va_end(args);                                                            \
+  va_end(args_copy)
+
+#define WABT_ENUM_COUNT(name) \
+  (static_cast<int>(name::Last) - static_cast<int>(name::First) + 1)
+
+#define WABT_DISALLOW_COPY_AND_ASSIGN(type) \
+  type(const type&) = delete;               \
+  type& operator=(const type&) = delete;
+
+#if WITH_EXCEPTIONS
+#define WABT_TRY try {
+#define WABT_CATCH_BAD_ALLOC \
+  }                          \
+  catch (std::bad_alloc&) {  \
+  }
+#define WABT_CATCH_BAD_ALLOC_AND_EXIT           \
+  }                                             \
+  catch (std::bad_alloc&) {                     \
+    WABT_FATAL("Memory allocation failure.\n"); \
+  }
+#else
+#define WABT_TRY
+#define WABT_CATCH_BAD_ALLOC
+#define WABT_CATCH_BAD_ALLOC_AND_EXIT
+#endif
+
+#define PRIindex "u"
+#define PRIaddress PRIu64
+#define PRIoffset PRIzx
+
+namespace wabt {
+#if WABT_BIG_ENDIAN
+  inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
+    memcpy(static_cast<char*>(dst) + (dsize) - (len) - (doff),
+      static_cast<const char*>(src) + (ssize) - (len) - (soff),
+      (len));
+  }
+#else
+  inline void MemcpyEndianAware(void *dst, const void *src, size_t dsize, size_t ssize, size_t doff, size_t soff, size_t len) {
+    memcpy(static_cast<char*>(dst) + (doff),
+      static_cast<const char*>(src) + (soff),
+      (len));
+  }
+#endif
+}
+
+struct v128 {
+  v128() = default;
+  v128(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) {
+    set_u32(0, x0);
+    set_u32(1, x1);
+    set_u32(2, x2);
+    set_u32(3, x3);
+  }
+
+  bool operator==(const v128& other) const {
+    return std::equal(std::begin(v), std::end(v), std::begin(other.v));
+  }
+  bool operator!=(const v128& other) const { return !(*this == other); }
+
+  uint8_t u8(int lane) const { return To<uint8_t>(lane); }
+  uint16_t u16(int lane) const { return To<uint16_t>(lane); }
+  uint32_t u32(int lane) const { return To<uint32_t>(lane); }
+  uint64_t u64(int lane) const { return To<uint64_t>(lane); }
+  uint32_t f32_bits(int lane) const { return To<uint32_t>(lane); }
+  uint64_t f64_bits(int lane) const { return To<uint64_t>(lane); }
+
+  void set_u8(int lane, uint8_t x) { return From<uint8_t>(lane, x); }
+  void set_u16(int lane, uint16_t x) { return From<uint16_t>(lane, x); }
+  void set_u32(int lane, uint32_t x) { return From<uint32_t>(lane, x); }
+  void set_u64(int lane, uint64_t x) { return From<uint64_t>(lane, x); }
+  void set_f32_bits(int lane, uint32_t x) { return From<uint32_t>(lane, x); }
+  void set_f64_bits(int lane, uint64_t x) { return From<uint64_t>(lane, x); }
+
+  bool is_zero() const {
+    return std::all_of(std::begin(v), std::end(v),
+                       [](uint8_t x) { return x == 0; });
+  }
+  void set_zero() { std::fill(std::begin(v), std::end(v), 0); }
+
+  template <typename T>
+  T To(int lane) const {
+    static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
+    assert((lane + 1) * sizeof(T) <= sizeof(v));
+    T result;
+    wabt::MemcpyEndianAware(&result, v, sizeof(result), sizeof(v), 0, lane * sizeof(T), sizeof(result));
+    return result;
+  }
+
+  template <typename T>
+  void From(int lane, T data) {
+    static_assert(sizeof(T) <= sizeof(v), "Invalid cast!");
+    assert((lane + 1) * sizeof(T) <= sizeof(v));
+    wabt::MemcpyEndianAware(v, &data, sizeof(v), sizeof(data), lane * sizeof(T), 0, sizeof(data));
+  }
+
+  uint8_t v[16];
+};
+
+namespace wabt {
+
+typedef uint32_t Index;    // An index into one of the many index spaces.
+typedef uint64_t Address;  // An address or size in linear memory.
+typedef size_t Offset;     // An offset into a host's file or memory buffer.
+
+static const Address kInvalidAddress = ~0;
+static const Index kInvalidIndex = ~0;
+static const Offset kInvalidOffset = ~0;
+
+template <typename Dst, typename Src>
+Dst WABT_VECTORCALL Bitcast(Src&& value) {
+  static_assert(sizeof(Src) == sizeof(Dst), "Bitcast sizes must match.");
+  Dst result;
+  memcpy(&result, &value, sizeof(result));
+  return result;
+}
+
+template <typename T>
+void ZeroMemory(T& v) {
+  WABT_STATIC_ASSERT(std::is_pod<T>::value);
+  memset(&v, 0, sizeof(v));
+}
+
+// Placement construct
+template <typename T, typename... Args>
+void Construct(T& placement, Args&&... args) {
+  new (&placement) T(std::forward<Args>(args)...);
+}
+
+// Placement destruct
+template <typename T>
+void Destruct(T& placement) {
+  placement.~T();
+}
+
+inline std::string WABT_PRINTF_FORMAT(1, 2)
+    StringPrintf(const char* format, ...) {
+  va_list args;
+  va_list args_copy;
+  va_start(args, format);
+  va_copy(args_copy, args);
+  size_t len = wabt_vsnprintf(nullptr, 0, format, args) + 1;  // For \0.
+  std::vector<char> buffer(len);
+  va_end(args);
+  wabt_vsnprintf(buffer.data(), len, format, args_copy);
+  va_end(args_copy);
+  return std::string(buffer.data(), len - 1);
+}
+
+enum class LabelType {
+  Func,
+  Block,
+  Loop,
+  If,
+  Else,
+  Try,
+  Catch,
+  Unwind,
+
+  First = Func,
+  Last = Unwind,
+};
+static const int kLabelTypeCount = WABT_ENUM_COUNT(LabelType);
+
+struct Location {
+  enum class Type {
+    Text,
+    Binary,
+  };
+
+  Location() : line(0), first_column(0), last_column(0) {}
+  Location(string_view filename, int line, int first_column, int last_column)
+      : filename(filename),
+        line(line),
+        first_column(first_column),
+        last_column(last_column) {}
+  explicit Location(size_t offset) : offset(offset) {}
+
+  string_view filename;
+  union {
+    // For text files.
+    struct {
+      int line;
+      int first_column;
+      int last_column;
+    };
+    // For binary files.
+    struct {
+      size_t offset;
+    };
+  };
+};
+
+enum class SegmentKind {
+  Active,
+  Passive,
+  Declared,
+};
+
+// Used in test asserts for special expected values "nan:canonical" and
+// "nan:arithmetic"
+enum class ExpectedNan {
+  None,
+  Canonical,
+  Arithmetic,
+};
+
+// Matches binary format, do not change.
+enum SegmentFlags : uint8_t {
+  SegFlagsNone = 0,
+  SegPassive = 1,        // bit 0: Is passive
+  SegExplicitIndex = 2,  // bit 1: Has explict index (Implies table 0 if absent)
+  SegDeclared = 3,       // Only used for declared segments
+  SegUseElemExprs = 4,   // bit 2: Is elemexpr (Or else index sequence)
+
+  SegFlagMax = (SegUseElemExprs << 1) - 1,  // All bits set.
+};
+
+enum class RelocType {
+  FuncIndexLEB = 0,       // e.g. Immediate of call instruction
+  TableIndexSLEB = 1,     // e.g. Loading address of function
+  TableIndexI32 = 2,      // e.g. Function address in DATA
+  MemoryAddressLEB = 3,   // e.g. Memory address in load/store offset immediate
+  MemoryAddressSLEB = 4,  // e.g. Memory address in i32.const
+  MemoryAddressI32 = 5,   // e.g. Memory address in DATA
+  TypeIndexLEB = 6,       // e.g. Immediate type in call_indirect
+  GlobalIndexLEB = 7,     // e.g. Immediate of get_global inst
+  FunctionOffsetI32 = 8,  // e.g. Code offset in DWARF metadata
+  SectionOffsetI32 = 9,   // e.g. Section offset in DWARF metadata
+  EventIndexLEB = 10,     // Used in throw instructions
+  MemoryAddressRelSLEB = 11,  // In PIC code, addr relative to __memory_base
+  TableIndexRelSLEB = 12,   // In PIC code, table index relative to __table_base
+  GlobalIndexI32 = 13,      // e.g. Global index in data (e.g. DWARF)
+  MemoryAddressLEB64 = 14,  // Memory64: Like MemoryAddressLEB
+  MemoryAddressSLEB64 = 15,     // Memory64: Like MemoryAddressSLEB
+  MemoryAddressI64 = 16,        // Memory64: Like MemoryAddressI32
+  MemoryAddressRelSLEB64 = 17,  // Memory64: Like MemoryAddressRelSLEB
+  TableIndexSLEB64 = 18,        // Memory64: Like TableIndexSLEB
+  TableIndexI64 = 19,           // Memory64: Like TableIndexI32
+  TableNumberLEB = 20,          // e.g. Immediate of table.get
+  MemoryAddressTLSSLEB = 21,    // Address relative to __tls_base
+  MemoryAddressTLSI32 = 22,     // Address relative to __tls_base
+
+  First = FuncIndexLEB,
+  Last = MemoryAddressTLSI32,
+};
+static const int kRelocTypeCount = WABT_ENUM_COUNT(RelocType);
+
+struct Reloc {
+  Reloc(RelocType, size_t offset, Index index, int32_t addend = 0);
+
+  RelocType type;
+  size_t offset;
+  Index index;
+  int32_t addend;
+};
+
+enum class LinkingEntryType {
+  SegmentInfo = 5,
+  InitFunctions = 6,
+  ComdatInfo = 7,
+  SymbolTable = 8,
+};
+
+enum class SymbolType {
+  Function = 0,
+  Data = 1,
+  Global = 2,
+  Section = 3,
+  Event = 4,
+  Table = 5,
+};
+
+enum class ComdatType {
+  Data = 0x0,
+  Function = 0x1,
+};
+
+#define WABT_SYMBOL_MASK_VISIBILITY 0x4
+#define WABT_SYMBOL_MASK_BINDING 0x3
+#define WABT_SYMBOL_FLAG_UNDEFINED 0x10
+#define WABT_SYMBOL_FLAG_EXPORTED 0x20
+#define WABT_SYMBOL_FLAG_EXPLICIT_NAME 0x40
+#define WABT_SYMBOL_FLAG_NO_STRIP 0x80
+#define WABT_SYMBOL_FLAG_MAX 0xff
+
+enum class SymbolVisibility {
+  Default = 0,
+  Hidden = 4,
+};
+
+enum class SymbolBinding {
+  Global = 0,
+  Weak = 1,
+  Local = 2,
+};
+
+/* matches binary format, do not change */
+enum class ExternalKind {
+  Func = 0,
+  Table = 1,
+  Memory = 2,
+  Global = 3,
+  Event = 4,
+
+  First = Func,
+  Last = Event,
+};
+static const int kExternalKindCount = WABT_ENUM_COUNT(ExternalKind);
+
+struct Limits {
+  Limits() = default;
+  explicit Limits(uint64_t initial) : initial(initial) {}
+  Limits(uint64_t initial, uint64_t max)
+      : initial(initial), max(max), has_max(true) {}
+  Limits(uint64_t initial, uint64_t max, bool is_shared)
+      : initial(initial), max(max), has_max(true), is_shared(is_shared) {}
+  Limits(uint64_t initial, uint64_t max, bool is_shared, bool is_64)
+      : initial(initial),
+        max(max),
+        has_max(true),
+        is_shared(is_shared),
+        is_64(is_64) {}
+
+  uint64_t initial = 0;
+  uint64_t max = 0;
+  bool has_max = false;
+  bool is_shared = false;
+  bool is_64 = false;
+};
+
+enum { WABT_USE_NATURAL_ALIGNMENT = 0xFFFFFFFFFFFFFFFF };
+
+Result ReadFile(string_view filename, std::vector<uint8_t>* out_data);
+
+void InitStdio();
+
+/* external kind */
+
+extern const char* g_kind_name[];
+
+static WABT_INLINE const char* GetKindName(ExternalKind kind) {
+  return static_cast<int>(kind) < kExternalKindCount
+    ? g_kind_name[static_cast<size_t>(kind)]
+    : "<error_kind>";
+}
+
+/* reloc */
+
+extern const char* g_reloc_type_name[];
+
+static WABT_INLINE const char* GetRelocTypeName(RelocType reloc) {
+  return static_cast<int>(reloc) < kRelocTypeCount
+    ? g_reloc_type_name[static_cast<size_t>(reloc)]
+    : "<error_reloc_type>";
+}
+
+/* symbol */
+
+static WABT_INLINE const char* GetSymbolTypeName(SymbolType type) {
+  switch (type) {
+    case SymbolType::Function:
+      return "func";
+    case SymbolType::Global:
+      return "global";
+    case SymbolType::Data:
+      return "data";
+    case SymbolType::Section:
+      return "section";
+    case SymbolType::Event:
+      return "event";
+    case SymbolType::Table:
+      return "table";
+    default:
+      return "<error_symbol_type>";
+  }
+}
+
+template <typename T>
+void ConvertBackslashToSlash(T begin, T end) {
+  std::replace(begin, end, '\\', '/');
+}
+
+inline void ConvertBackslashToSlash(char* s, size_t length) {
+  ConvertBackslashToSlash(s, s + length);
+}
+
+inline void ConvertBackslashToSlash(char* s) {
+  ConvertBackslashToSlash(s, strlen(s));
+}
+
+inline void ConvertBackslashToSlash(std::string* s) {
+  ConvertBackslashToSlash(s->begin(), s->end());
+}
+
+inline void SwapBytesSized(void *addr, size_t size) {
+  auto bytes = static_cast<uint8_t*>(addr);
+  for (size_t i = 0; i < size / 2; i++) {
+    std::swap(bytes[i], bytes[size-1-i]);
+  }
+}
+
+}  // namespace wabt
+
+#endif  // WABT_COMMON_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.cc
new file mode 100644 (file)
index 0000000..9347c86
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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 "config.h"
+
+#include <cstdarg>
+#include <cstdio>
+
+#if COMPILER_IS_MSVC && _M_X64
+#include <emmintrin.h>
+#elif COMPILER_IS_MSVC && _M_IX86
+#include <float.h>
+#endif
+
+/* c99-style vsnprintf for MSVC < 2015. See http://stackoverflow.com/a/8712996
+ using _snprintf or vsnprintf will not-properly null-terminate, and will return
+ -1 instead of the number of characters needed on overflow. */
+#if COMPILER_IS_MSVC
+int wabt_vsnprintf(char* str, size_t size, const char* format, va_list ap) {
+  int result = -1;
+  if (size != 0) {
+    result = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
+  }
+  if (result == -1) {
+    result = _vscprintf(format, ap);
+  }
+  return result;
+}
+
+#if !HAVE_SNPRINTF
+int wabt_snprintf(char* str, size_t size, const char* format, ...) {
+  va_list args;
+  va_start(args, format);
+  int result = wabt_vsnprintf(str, size, format, args);
+  va_end(args);
+  return result;
+}
+#endif
+#endif
+
+#if COMPILER_IS_MSVC && _M_IX86
+// Allow the following functions to change the floating-point environment (e.g.
+// update to 64-bit precision in the mantissa). This is only needed for x87
+// floats, which are only used on MSVC 32-bit.
+#pragma fenv_access (on)
+namespace {
+
+typedef unsigned int FPControl;
+
+FPControl Set64BitPrecisionControl() {
+  FPControl old_ctrl = _control87(0, 0);
+  _control87(_PC_64, _MCW_PC);
+  return old_ctrl;
+}
+
+void ResetPrecisionControl(FPControl old_ctrl) {
+  _control87(old_ctrl, _MCW_PC);
+}
+
+}  // end of anonymous namespace
+#endif
+
+double wabt_convert_uint64_to_double(uint64_t x) {
+#if COMPILER_IS_MSVC && _M_X64
+  // MSVC on x64 generates uint64 -> float conversions but doesn't do
+  // round-to-nearest-ties-to-even, which is required by WebAssembly.
+  __m128d result = _mm_setzero_pd();
+  if (x & 0x8000000000000000ULL) {
+    result = _mm_cvtsi64_sd(result, (x >> 1) | (x & 1));
+    result = _mm_add_sd(result, result);
+  } else {
+    result = _mm_cvtsi64_sd(result, x);
+  }
+  return _mm_cvtsd_f64(result);
+#elif COMPILER_IS_MSVC && _M_IX86
+  // MSVC on x86 converts from i64 -> double -> float, which causes incorrect
+  // rounding. Using the x87 float stack instead preserves the correct
+  // rounding.
+  FPControl old_ctrl = Set64BitPrecisionControl();
+  static const double c = 18446744073709551616.0;
+  double result;
+  __asm fild x;
+  if (x & 0x8000000000000000ULL) {
+    __asm fadd c;
+  }
+  __asm fstp result;
+  ResetPrecisionControl(old_ctrl);
+  return result;
+#else
+  return static_cast<double>(x);
+#endif
+}
+
+float wabt_convert_uint64_to_float(uint64_t x) {
+#if COMPILER_IS_MSVC && _M_X64
+  // MSVC on x64 generates uint64 -> float conversions but doesn't do
+  // round-to-nearest-ties-to-even, which is required by WebAssembly.
+  __m128 result = _mm_setzero_ps();
+  if (x & 0x8000000000000000ULL) {
+    result = _mm_cvtsi64_ss(result, (x >> 1) | (x & 1));
+    result = _mm_add_ss(result, result);
+  } else {
+    result = _mm_cvtsi64_ss(result, x);
+  }
+  return _mm_cvtss_f32(result);
+#elif COMPILER_IS_MSVC && _M_IX86
+  // MSVC on x86 converts from i64 -> double -> float, which causes incorrect
+  // rounding. Using the x87 float stack instead preserves the correct
+  // rounding.
+  FPControl old_ctrl = Set64BitPrecisionControl();
+  static const float c = 18446744073709551616.0f;
+  float result;
+  __asm fild x;
+  if (x & 0x8000000000000000ULL) {
+    __asm fadd c;
+  }
+  __asm fstp result;
+  ResetPrecisionControl(old_ctrl);
+  return result;
+#else
+  return static_cast<float>(x);
+#endif
+}
+
+double wabt_convert_int64_to_double(int64_t x) {
+#if COMPILER_IS_MSVC && _M_IX86
+  double result;
+  __asm fild x;
+  __asm fstp result;
+  return result;
+#else
+  return static_cast<double>(x);
+#endif
+}
+
+float wabt_convert_int64_to_float(int64_t x) {
+#if COMPILER_IS_MSVC && _M_IX86
+  float result;
+  __asm fild x;
+  __asm fstp result;
+  return result;
+#else
+  return static_cast<float>(x);
+#endif
+}
+
+#if COMPILER_IS_MSVC && _M_IX86
+#pragma fenv_access (off)
+#endif
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.h.in b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/config.h.in
new file mode 100644 (file)
index 0000000..9ba9ad7
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * 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_CONFIG_H_
+#define WABT_CONFIG_H_
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#cmakedefine CMAKE_PROJECT_VERSION "${CMAKE_PROJECT_VERSION}"
+
+/* TODO(binji): nice way to define these with WABT_ prefix? */
+
+/* Whether <alloca.h> is available */
+#cmakedefine01 HAVE_ALLOCA_H
+
+/* Whether <unistd.h> is available */
+#cmakedefine01 HAVE_UNISTD_H
+
+/* Whether snprintf is defined by stdio.h */
+#cmakedefine01 HAVE_SNPRINTF
+
+/* Whether ssize_t is defined by stddef.h */
+#cmakedefine01 HAVE_SSIZE_T
+
+/* Whether strcasecmp is defined by strings.h */
+#cmakedefine01 HAVE_STRCASECMP
+
+/* Whether ENABLE_VIRTUAL_TERMINAL_PROCESSING is defined by windows.h */
+#cmakedefine01 HAVE_WIN32_VT100
+
+#cmakedefine01 COMPILER_IS_CLANG
+#cmakedefine01 COMPILER_IS_GNU
+#cmakedefine01 COMPILER_IS_MSVC
+
+#cmakedefine01 WITH_EXCEPTIONS
+
+#define SIZEOF_SIZE_T @SIZEOF_SIZE_T@
+
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#elif COMPILER_IS_MSVC
+#include <malloc.h>
+#define alloca _alloca
+#elif defined(__MINGW32__)
+#include <malloc.h>
+#endif
+
+#if COMPILER_IS_CLANG || COMPILER_IS_GNU
+
+#define WABT_UNUSED __attribute__((unused))
+#define WABT_WARN_UNUSED __attribute__((warn_unused_result))
+#define WABT_INLINE inline
+#define WABT_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#define WABT_LIKELY(x) __builtin_expect(!!(x), 1)
+
+#define WABT_VECTORCALL
+
+#if __MINGW32__
+// mingw defaults to printf format specifier being ms_printf (which doesn't
+// understand 'llu', etc.) We always want gnu_printf, and force mingw to always
+// use mingw_printf, mingw_vprintf, etc.
+#define WABT_PRINTF_FORMAT(format_arg, first_arg) \
+  __attribute__((format(gnu_printf, (format_arg), (first_arg))))
+#else
+#define WABT_PRINTF_FORMAT(format_arg, first_arg) \
+  __attribute__((format(printf, (format_arg), (first_arg))))
+#endif
+
+#ifdef __cplusplus
+#if __cplusplus >= 201103L
+#define WABT_STATIC_ASSERT(x) static_assert((x), #x)
+#else
+#define WABT_STATIC_ASSERT__(x, c) \
+  static int static_assert_##c[(x ? 0 : -1)] WABT_UNUSED
+#define WABT_STATIC_ASSERT_(x, c) WABT_STATIC_ASSERT__(x, c)
+#define WABT_STATIC_ASSERT(x) WABT_STATIC_ASSERT_(x, __COUNTER__)
+#endif
+#else
+#define WABT_STATIC_ASSERT(x) _Static_assert((x), #x)
+#endif
+
+#elif COMPILER_IS_MSVC
+
+#include <intrin.h>
+#include <string.h>
+
+#define WABT_UNUSED
+#define WABT_WARN_UNUSED
+#define WABT_INLINE __inline
+#define WABT_STATIC_ASSERT(x) _STATIC_ASSERT(x)
+#define WABT_UNLIKELY(x) (x)
+#define WABT_LIKELY(x) (x)
+#define WABT_PRINTF_FORMAT(format_arg, first_arg)
+
+#define WABT_VECTORCALL __vectorcall
+
+#else
+
+#error unknown compiler
+
+#endif
+
+#define WABT_UNREACHABLE abort()
+
+#ifdef __cplusplus
+
+namespace wabt {
+
+#if COMPILER_IS_CLANG || COMPILER_IS_GNU
+
+inline int Clz(unsigned x) { return x ? __builtin_clz(x) : sizeof(x) * 8; }
+inline int Clz(unsigned long x) { return x ? __builtin_clzl(x) : sizeof(x) * 8; }
+inline int Clz(unsigned long long x) { return x ? __builtin_clzll(x) : sizeof(x) * 8; }
+
+inline int Ctz(unsigned x) { return x ? __builtin_ctz(x) : sizeof(x) * 8; }
+inline int Ctz(unsigned long x) { return x ? __builtin_ctzl(x) : sizeof(x) * 8; }
+inline int Ctz(unsigned long long x) { return x ? __builtin_ctzll(x) : sizeof(x) * 8; }
+
+inline int Popcount(unsigned x) { return __builtin_popcount(x); }
+inline int Popcount(unsigned long x) { return __builtin_popcountl(x); }
+inline int Popcount(unsigned long long x) { return __builtin_popcountll(x); }
+
+#elif COMPILER_IS_MSVC
+
+#if _M_IX86
+inline unsigned long LowDword(unsigned __int64 value) {
+  return (unsigned long)value;
+}
+
+inline unsigned long HighDword(unsigned __int64 value) {
+  unsigned long high;
+  memcpy(&high, (unsigned char*)&value + sizeof(high), sizeof(high));
+  return high;
+}
+#endif
+
+inline int Clz(unsigned long mask) {
+  if (mask == 0)
+    return 32;
+
+  unsigned long index;
+  _BitScanReverse(&index, mask);
+  return sizeof(unsigned long) * 8 - (index + 1);
+}
+
+inline int Clz(unsigned int mask) {
+  return Clz((unsigned long)mask);
+}
+
+inline int Clz(unsigned __int64 mask) {
+#if _M_X64
+  if (mask == 0)
+    return 64;
+
+  unsigned long index;
+  _BitScanReverse64(&index, mask);
+  return sizeof(unsigned __int64) * 8 - (index + 1);
+#elif _M_IX86
+  int result = Clz(HighDword(mask));
+  if (result == 32)
+    result += Clz(LowDword(mask));
+
+  return result;
+#else
+#error unexpected architecture
+#endif
+}
+
+inline int Ctz(unsigned long mask) {
+  if (mask == 0)
+    return 32;
+
+  unsigned long index;
+  _BitScanForward(&index, mask);
+  return index;
+}
+
+inline int Ctz(unsigned int mask) {
+  return Ctz((unsigned long)mask);
+}
+
+inline int Ctz(unsigned __int64 mask) {
+#if _M_X64
+  if (mask == 0)
+    return 64;
+
+  unsigned long index;
+  _BitScanForward64(&index, mask);
+  return index;
+#elif _M_IX86
+  int result = Ctz(LowDword(mask));
+  if (result == 32)
+    result += Ctz(HighDword(mask));
+
+  return result;
+#else
+#error unexpected architecture
+#endif
+}
+
+inline int Popcount(unsigned long value) {
+  return __popcnt(value);
+}
+
+inline int Popcount(unsigned int value) {
+  return Popcount((unsigned long)value);
+}
+
+inline int Popcount(unsigned __int64 value) {
+#if _M_X64
+  return __popcnt64(value);
+#elif _M_IX86
+  return Popcount(HighDword(value)) + Popcount(LowDword(value));
+#else
+#error unexpected architecture
+#endif
+}
+
+#else
+
+#error unknown compiler
+
+#endif
+
+}  // namespace wabt
+
+#if COMPILER_IS_MSVC
+
+/* print format specifier for size_t */
+#if SIZEOF_SIZE_T == 4
+#define PRIzd "d"
+#define PRIzx "x"
+#elif SIZEOF_SIZE_T == 8
+#define PRIzd "I64d"
+#define PRIzx "I64x"
+#else
+#error "weird sizeof size_t"
+#endif
+
+#elif COMPILER_IS_CLANG || COMPILER_IS_GNU
+
+/* print format specifier for size_t */
+#define PRIzd "zd"
+#define PRIzx "zx"
+
+#else
+
+#error unknown compiler
+
+#endif
+
+#if HAVE_SNPRINTF
+#define wabt_snprintf snprintf
+#elif COMPILER_IS_MSVC
+/* can't just use _snprintf because it doesn't always null terminate */
+#include <cstdarg>
+int wabt_snprintf(char* str, size_t size, const char* format, ...);
+#else
+#error no snprintf
+#endif
+
+#if COMPILER_IS_MSVC
+/* can't just use vsnprintf because it doesn't always null terminate */
+int wabt_vsnprintf(char* str, size_t size, const char* format, va_list ap);
+#else
+#define wabt_vsnprintf vsnprintf
+#endif
+
+#if !HAVE_SSIZE_T
+#if COMPILER_IS_MSVC
+/* define ssize_t identically to how LLVM does, to avoid conflicts if including both */
+#if defined(_WIN64)
+typedef signed __int64 ssize_t;
+#else
+typedef signed int ssize_t;
+#endif /* _WIN64 */
+#else
+typedef long ssize_t;
+#endif
+#endif
+
+#if !HAVE_STRCASECMP
+#if COMPILER_IS_MSVC
+#define strcasecmp _stricmp
+#else
+#error no strcasecmp
+#endif
+#endif
+
+double wabt_convert_uint64_to_double(uint64_t x);
+float wabt_convert_uint64_to_float(uint64_t x);
+double wabt_convert_int64_to_double(int64_t x);
+float wabt_convert_int64_to_float(int64_t x);
+
+#endif  // __cplusplus
+
+#endif /* WABT_CONFIG_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ast.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ast.h
new file mode 100644 (file)
index 0000000..a808055
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * 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_DECOMPILER_AST_H_
+#define WABT_DECOMPILER_AST_H_
+
+#include "src/cast.h"
+#include "src/generate-names.h"
+#include "src/ir.h"
+#include "src/ir-util.h"
+
+#include <map>
+
+namespace wabt {
+
+enum class NodeType {
+  Uninitialized,
+  FlushToVars,
+  FlushedVar,
+  Statements,
+  EndReturn,
+  Decl,
+  DeclInit,
+  Expr
+};
+
+// The AST we're going to convert the standard IR into.
+struct Node {
+  NodeType ntype;
+  ExprType etype;  // Only if ntype == Expr.
+  const Expr* e;
+  std::vector<Node> children;
+  // Node specific annotations.
+  union {
+    struct { Index var_start, var_count; };  // FlushedVar/FlushToVars
+    const Var* var;  // Decl/DeclInit.
+    LabelType lt;  // br/br_if target.
+  } u;
+
+  Node() : ntype(NodeType::Uninitialized), etype(ExprType::Nop), e(nullptr) {
+  }
+  Node(NodeType ntype, ExprType etype, const Expr* e, const Var* v)
+    : ntype(ntype), etype(etype), e(e) {
+    u.var = v;
+  }
+
+  // This value should really never be copied, only moved.
+  Node(const Node& rhs) = delete;
+  Node& operator=(const Node& rhs) = delete;
+
+  Node(Node&& rhs) { *this = std::move(rhs); }
+  Node& operator=(Node&& rhs) {
+    ntype = rhs.ntype;
+    // Reset ntype to avoid moved from values still being used.
+    rhs.ntype = NodeType::Uninitialized;
+    etype = rhs.etype;
+    rhs.etype = ExprType::Nop;
+    e = rhs.e;
+    std::swap(children, rhs.children);
+    u = rhs.u;
+    return *this;
+  }
+};
+
+struct AST {
+  AST(ModuleContext& mc, const Func *f) : mc(mc), f(f) {
+    if (f) {
+      mc.BeginFunc(*f);
+      for (Index i = 0; i < f->GetNumParams(); i++) {
+        auto name = "$" + IndexToAlphaName(i);
+        vars_defined.insert({ name, { 0, false }});
+      }
+    }
+  }
+
+  ~AST() {
+    if (f) mc.EndFunc();
+  }
+
+  // Create a new node, take nargs existing nodes on the exp stack as children.
+  Node& InsertNode(NodeType ntype, ExprType etype, const Expr* e, Index nargs) {
+    assert(exp_stack.size() >= nargs);
+    Node n { ntype, etype, e, nullptr };
+    n.children.reserve(nargs);
+    std::move(exp_stack.end() - nargs, exp_stack.end(),
+              std::back_inserter(n.children));
+    exp_stack.erase(exp_stack.end() - nargs, exp_stack.end());
+    exp_stack.push_back(std::move(n));
+    return exp_stack.back();
+  }
+
+  template<ExprType T> void PreDecl(const VarExpr<T>& ve) {
+    predecls.emplace_back(NodeType::Decl, ExprType::Nop, nullptr, &ve.var);
+  }
+
+  template<ExprType T> void Get(const VarExpr<T>& ve, bool local) {
+    if (local) {
+      auto ret = vars_defined.insert({ ve.var.name(), { cur_block_id, false }});
+      if (ret.second) {
+        // Use before def, may happen since locals are guaranteed 0.
+        PreDecl(ve);
+      } else if (blocks_closed[ret.first->second.block_id]) {
+        // This is a use of a variable that was defined in a block that has
+        // already ended. This happens rarely, but we should cater for this
+        // case by lifting it to the top scope.
+        PreDecl(ve);
+      }
+    }
+    InsertNode(NodeType::Expr, T, &ve, 0);
+  }
+
+  template<ExprType T> void Set(const VarExpr<T>& ve, bool local) {
+    // Seen this var before?
+    if (local &&
+        vars_defined.insert({ ve.var.name(), { cur_block_id, false }}).second) {
+      if (value_stack_depth == 1) {
+        // Top level, declare it here.
+        InsertNode(NodeType::DeclInit, ExprType::Nop, nullptr, 1).u.var =
+            &ve.var;
+        return;
+      } else {
+        // Inside exp, better leave it as assignment exp and lift the decl out.
+        PreDecl(ve);
+      }
+    }
+    InsertNode(NodeType::Expr, T, &ve, 1);
+  }
+
+  template<ExprType T> void Block(const BlockExprBase<T>& be, LabelType label) {
+    mc.BeginBlock(label, be.block);
+    Construct(be.block.exprs, be.block.decl.GetNumResults(), be.block.decl.GetNumParams(), false);
+    mc.EndBlock();
+    InsertNode(NodeType::Expr, T, &be, 1);
+  }
+
+  void Construct(const Expr& e) {
+    auto arity = mc.GetExprArity(e);
+    switch (e.type()) {
+      case ExprType::LocalGet: {
+        Get(*cast<LocalGetExpr>(&e), true);
+        return;
+      }
+      case ExprType::GlobalGet: {
+        Get(*cast<GlobalGetExpr>(&e), false);
+        return;
+      }
+      case ExprType::LocalSet: {
+        Set(*cast<LocalSetExpr>(&e), true);
+        return;
+      }
+      case ExprType::GlobalSet: {
+        Set(*cast<GlobalSetExpr>(&e), false);
+        return;
+      }
+      case ExprType::LocalTee: {
+        auto& lt = *cast<LocalTeeExpr>(&e);
+        Set(lt, true);
+        if (value_stack_depth == 1) {  // Tee is the only thing on there.
+          Get(lt, true);  // Now Set + Get instead.
+        } else {
+          // Things are above us on the stack so the Tee can't be eliminated.
+          // The Set makes this work as a Tee when consumed by a parent.
+        }
+        return;
+      }
+      case ExprType::If: {
+        auto ife = cast<IfExpr>(&e);
+        value_stack_depth--;  // Condition.
+        mc.BeginBlock(LabelType::Block, ife->true_);
+        Construct(ife->true_.exprs, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
+        if (!ife->false_.empty()) {
+          Construct(ife->false_, ife->true_.decl.GetNumResults(), ife->true_.decl.GetNumParams(), false);
+        }
+        mc.EndBlock();
+        value_stack_depth++;  // Put Condition back.
+        InsertNode(NodeType::Expr, ExprType::If, &e, ife->false_.empty() ? 2 : 3);
+        return;
+      }
+      case ExprType::Block: {
+        Block(*cast<BlockExpr>(&e), LabelType::Block);
+        return;
+      }
+      case ExprType::Loop: {
+        Block(*cast<LoopExpr>(&e), LabelType::Loop);
+        return;
+      }
+      case ExprType::Br: {
+        InsertNode(NodeType::Expr, ExprType::Br, &e, 0).u.lt =
+            mc.GetLabel(cast<BrExpr>(&e)->var)->label_type;
+        return;
+      }
+      case ExprType::BrIf: {
+        InsertNode(NodeType::Expr, ExprType::BrIf, &e, 1).u.lt =
+            mc.GetLabel(cast<BrIfExpr>(&e)->var)->label_type;
+        return;
+      }
+      default: {
+        InsertNode(NodeType::Expr, e.type(), &e, arity.nargs);
+        return;
+      }
+    }
+  }
+
+  void Construct(const ExprList& es, Index nresults, Index nparams, bool is_function_body) {
+    block_stack.push_back(cur_block_id);
+    cur_block_id = blocks_closed.size();
+    blocks_closed.push_back(false);
+    auto start = exp_stack.size();
+    int value_stack_depth_start = value_stack_depth - nparams;
+    auto value_stack_in_variables = value_stack_depth;
+    bool unreachable = false;
+    for (auto& e : es) {
+      Construct(e);
+      auto arity = mc.GetExprArity(e);
+      value_stack_depth -= arity.nargs;
+      value_stack_in_variables = std::min(value_stack_in_variables,
+                                          value_stack_depth);
+      unreachable = unreachable || arity.unreachable;
+      assert(unreachable || value_stack_depth >= value_stack_depth_start);
+      value_stack_depth += arity.nreturns;
+      // We maintain the invariant that a value_stack_depth of N is represented
+      // by the last N exp_stack items (each of which returning exactly 1
+      // value), all exp_stack items before it return void ("statements").
+      // In particular for the wasm stack:
+      // - The values between 0 and value_stack_depth_start are part of the
+      //   parent block, and not touched here.
+      // - The values from there up to value_stack_in_variables are variables
+      //   to be used, representing previous statements that flushed the
+      //   stack into variables.
+      // - Values on top of that up to value_stack_depth are exps returning
+      //   a single value.
+      // The code below maintains the above invariants. With this in place
+      // code "falls into place" the way you expect it.
+      if (arity.nreturns != 1) {
+        auto num_vars = value_stack_in_variables - value_stack_depth_start;
+        auto num_vals = value_stack_depth - value_stack_in_variables;
+        auto GenFlushVars = [&](int nargs) {
+          auto& ftv = InsertNode(NodeType::FlushToVars, ExprType::Nop, nullptr,
+                                 nargs);
+          ftv.u.var_start = flushed_vars;
+          ftv.u.var_count = num_vals;
+        };
+        auto MoveStatementsBelowVars = [&](size_t amount) {
+          std::rotate(exp_stack.end() - num_vars - amount,
+                      exp_stack.end() - amount,
+                      exp_stack.end());
+        };
+        auto GenFlushedVars = [&]() {
+          // Re-generate these values as vars.
+          for (int i = 0; i < num_vals; i++) {
+            auto& fv = InsertNode(NodeType::FlushedVar, ExprType::Nop, nullptr,
+                                  0);
+            fv.u.var_start = flushed_vars++;
+            fv.u.var_count = 1;
+          }
+        };
+        if (arity.nreturns == 0 &&
+            value_stack_depth > value_stack_depth_start) {
+          // We have a void item on top of the exp_stack, so we must "lift" the
+          // previous values around it.
+          // We track what part of the stack is in variables to avoid doing
+          // this unnecessarily.
+          if (num_vals > 0) {
+            // We have actual new values that need lifting.
+            // This puts the part of the stack that wasn't already a variable
+            // (before the current void exp) into a FlushToVars.
+            auto void_exp = std::move(exp_stack.back());
+            exp_stack.pop_back();
+            GenFlushVars(num_vals);
+            exp_stack.push_back(std::move(void_exp));
+            // Put this flush statement + void statement before any
+            // existing variables.
+            MoveStatementsBelowVars(2);
+            // Now re-generate these values after the void exp as vars.
+            GenFlushedVars();
+          } else {
+            // We have existing variables that need lifting, but no need to
+            // create them anew.
+            std::rotate(exp_stack.end() - num_vars - 1, exp_stack.end() - 1,
+                        exp_stack.end());
+          }
+          value_stack_in_variables = value_stack_depth;
+        } else if (arity.nreturns > 1) {
+          // Multivalue: we flush the stack also.
+          // Number of other non-variable values that may be present:
+          assert(num_vals >= static_cast<int>(arity.nreturns));
+          // Flush multi-value exp + others.
+          GenFlushVars(num_vals - arity.nreturns + 1);
+          // Put this flush statement before any existing variables.
+          MoveStatementsBelowVars(1);
+          GenFlushedVars();
+          value_stack_in_variables = value_stack_depth;
+        }
+      } else {
+        // Special optimisation: for constant instructions, we can mark these
+        // as if they were variables, so they can be re-ordered for free with
+        // the above code, without needing new variables!
+        // TODO: this would be nice to also do for get_local and maybe others,
+        // though that needs a way to ensure there's no set_local in between
+        // when they get lifted, so complicates matters a bit.
+        if (e.type() == ExprType::Const &&
+            value_stack_in_variables == value_stack_depth - 1) {
+          value_stack_in_variables++;
+        }
+      }
+    }
+    assert(unreachable ||
+           value_stack_depth - value_stack_depth_start ==
+           static_cast<int>(nresults));
+    // Undo any changes to value_stack_depth, since parent takes care of arity
+    // changes.
+    value_stack_depth = value_stack_depth_start;
+    auto end = exp_stack.size();
+    assert(end >= start);
+    if (is_function_body) {
+      if (!exp_stack.empty()) {
+        if (exp_stack.back().etype == ExprType::Return) {
+          if (exp_stack.back().children.empty()) {
+            // Return statement at the end of a void function.
+            exp_stack.pop_back();
+          }
+        } else if (nresults) {
+          // Combine nresults into a return statement, for when this is used as
+          // a function body.
+          // TODO: if this is some other kind of block and >1 value is being
+          // returned, probably need some kind of syntax to make that clearer.
+          InsertNode(NodeType::EndReturn, ExprType::Nop, nullptr, nresults);
+        }
+      }
+      // TODO: these predecls are always at top level, but in the case of
+      // use inside an exp, it be nice to do it in the current block. Can't
+      // do that for predecls that are "out if scope" however.
+      std::move(predecls.begin(), predecls.end(),
+                std::back_inserter(exp_stack));
+      std::rotate(exp_stack.begin(), exp_stack.end() - predecls.size(),
+                  exp_stack.end());
+      predecls.clear();
+    }
+    end = exp_stack.size();
+    assert(end >= start);
+    auto size = end - start;
+    if (size != 1) {
+      InsertNode(NodeType::Statements, ExprType::Nop, nullptr, size);
+    }
+    blocks_closed[cur_block_id] = true;
+    cur_block_id = block_stack.back();
+    block_stack.pop_back();
+  }
+
+  ModuleContext& mc;
+  std::vector<Node> exp_stack;
+  std::vector<Node> predecls;
+  const Func *f;
+  int value_stack_depth = 0;
+  struct Variable { size_t block_id; bool defined; };
+  std::map<std::string, Variable> vars_defined;
+  Index flushed_vars = 0;
+  size_t cur_block_id = 0;
+  std::vector<size_t> block_stack;
+  std::vector<bool> blocks_closed;
+};
+
+}  // namespace wabt
+
+#endif  // WABT_DECOMPILER_AST_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ls.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-ls.h
new file mode 100644 (file)
index 0000000..f622e3f
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright 2019 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_DECOMPILER_LS_H_
+#define WABT_DECOMPILER_LS_H_
+
+#include "src/decompiler-ast.h"
+
+#include <map>
+
+namespace wabt {
+
+// Names starting with "u" are unsigned, the rest are "signed or doesn't matter"
+inline const char *GetDecompTypeName(Type t) {
+  switch (t) {
+    case Type::I8: return "byte";
+    case Type::I8U: return "ubyte";
+    case Type::I16: return "short";
+    case Type::I16U: return "ushort";
+    case Type::I32: return "int";
+    case Type::I32U: return "uint";
+    case Type::I64: return "long";
+    case Type::F32: return "float";
+    case Type::F64: return "double";
+    case Type::V128: return "simd";
+    case Type::Func: return "func";
+    case Type::FuncRef: return "funcref";
+    case Type::ExternRef: return "externref";
+    case Type::Void: return "void";
+    default: return "ILLEGAL";
+  }
+}
+
+inline Type GetMemoryType(Type operand_type, Opcode opc) {
+  // TODO: something something SIMD.
+  // TODO: this loses information of the type it is read into.
+  // That may well not be the biggest deal since that is usually obvious
+  // from context, if not, we should probably represent that as a cast around
+  // the access, since it should not be part of the field type.
+  if (operand_type == Type::I32 || operand_type == Type::I64) {
+    auto name = string_view(opc.GetName());
+    // FIXME: change into a new column in opcode.def instead?
+    auto is_unsigned = name.substr(name.size() - 2) == "_u";
+    switch (opc.GetMemorySize()) {
+      case 1: return is_unsigned ? Type::I8U : Type::I8;
+      case 2: return is_unsigned ? Type::I16U : Type::I16;
+      case 4: return is_unsigned ? Type::I32U : Type::I32;
+    }
+  }
+  return operand_type;
+}
+
+// Track all loads and stores inside a single function, to be able to detect
+// struct layouts we can use to annotate variables with, to make code more
+// readable.
+struct LoadStoreTracking {
+  struct LSAccess {
+    Address byte_size = 0;
+    Type type = Type::Any;
+    Address align = 0;
+    uint32_t idx = 0;
+    bool is_uniform = true;
+  };
+
+  struct LSVar {
+    std::map<uint64_t, LSAccess> accesses;
+    bool struct_layout = true;
+    Type same_type = Type::Any;
+    Address same_align = kInvalidAddress;
+    Opcode last_opc;
+  };
+
+  void Track(const Node& n) {
+    for (auto& c : n.children) Track(c);
+    switch (n.etype) {
+      case ExprType::Load: {
+        auto& le = *cast<LoadExpr>(n.e);
+        LoadStore(le.offset, le.opcode, le.opcode.GetResultType(),
+                  le.align, n.children[0]);
+        break;
+      }
+      case ExprType::Store: {
+        auto& se = *cast<StoreExpr>(n.e);
+        LoadStore(se.offset, se.opcode, se.opcode.GetParamType2(),
+                  se.align, n.children[0]);
+        break;
+      }
+      default:
+        break;
+    }
+  }
+
+  const std::string AddrExpName(const Node& addr_exp) const {
+    // TODO: expand this to more kinds of address expressions.
+    switch (addr_exp.etype) {
+      case ExprType::LocalGet:
+        return cast<LocalGetExpr>(addr_exp.e)->var.name();
+        break;
+      case ExprType::LocalTee:
+        return cast<LocalTeeExpr>(addr_exp.e)->var.name();
+        break;
+      default:
+        return "";
+    }
+  }
+
+  void LoadStore(uint64_t offset, Opcode opc, Type type, Address align,
+                 const Node& addr_exp) {
+    auto byte_size = opc.GetMemorySize();
+    type = GetMemoryType(type, opc);
+    // We want to associate memory ops of a certain offset & size as being
+    // relative to a uniquely identifiable pointer, such as a local.
+    auto name = AddrExpName(addr_exp);
+    if (name.empty()) {
+      return;
+    }
+    auto& var = vars[name];
+    auto& access = var.accesses[offset];
+    // Check if previous access at this offset (if any) is of same size
+    // and type (see Checklayouts below).
+    if (access.byte_size &&
+        ((access.byte_size != byte_size) ||
+         (access.type != type) ||
+         (access.align != align)))
+      access.is_uniform = false;
+    // Also exclude weird alignment accesses from structs.
+    if (!opc.IsNaturallyAligned(align))
+      access.is_uniform = false;
+    access.byte_size = byte_size;
+    access.type = type;
+    access.align = align;
+    // Additionally, check if all accesses are to the same type, so
+    // if layout check fails, we can at least declare it as pointer to
+    // a type.
+    if ((var.same_type == type || var.same_type == Type::Any) &&
+        (var.same_align == align || var.same_align == kInvalidAddress)) {
+      var.same_type = type;
+      var.same_align = align;
+      var.last_opc = opc;
+    } else {
+      var.same_type = Type::Void;
+      var.same_align = kInvalidAddress;
+    }
+  }
+
+  void CheckLayouts() {
+    // Here we check if the set of accesses we have collected form a sequence
+    // we could declare as a struct, meaning they are properly aligned,
+    // contiguous, and have no overlaps between different types and sizes.
+    // We do this because an int access of size 2 at offset 0 followed by
+    // a float access of size 4 at offset 4 can compactly represented as a
+    // struct { short, float }, whereas something that reads from overlapping
+    // or discontinuous offsets would need a more complicated syntax that
+    // involves explicit offsets.
+    // We assume that the bulk of memory accesses are of this very regular kind,
+    // so we choose not to even emit struct layouts for irregular ones,
+    // given that they are rare and confusing, and thus do not benefit from
+    // being represented as if they were structs.
+    for (auto& var : vars) {
+      if (var.second.accesses.size() == 1) {
+        // If we have just one access, this is better represented as a pointer
+        // than a struct.
+        var.second.struct_layout = false;
+        continue;
+      }
+      uint64_t cur_offset = 0;
+      uint32_t idx = 0;
+      for (auto& access : var.second.accesses) {
+        access.second.idx = idx++;
+        if (!access.second.is_uniform) {
+          var.second.struct_layout = false;
+          break;
+        }
+        // Align to next access: all elements are expected to be aligned to
+        // a memory address thats a multiple of their own size.
+        auto mask = static_cast<uint64_t>(access.second.byte_size - 1);
+        cur_offset = (cur_offset + mask) & ~mask;
+        if (cur_offset != access.first) {
+          var.second.struct_layout = false;
+          break;
+        }
+        cur_offset += access.second.byte_size;
+      }
+    }
+  }
+
+  std::string IdxToName(uint32_t idx) const {
+    return IndexToAlphaName(idx);  // TODO: more descriptive names?
+  }
+
+  std::string GenAlign(Address align, Opcode opc) const {
+    return opc.IsNaturallyAligned(align)
+      ? ""
+      : cat("@", std::to_string(align));
+  }
+
+  std::string GenTypeDecl(const std::string& name) const {
+    auto it = vars.find(name);
+    if (it == vars.end()) {
+      return "";
+    }
+    if (it->second.struct_layout) {
+      std::string s = "{ ";
+      for (auto& access : it->second.accesses) {
+        if (access.second.idx) s += ", ";
+        s += IdxToName(access.second.idx);
+        s += ':';
+        s += GetDecompTypeName(access.second.type);
+      }
+      s += " }";
+      return s;
+    }
+    // We don't have a struct layout, or the struct has just one field,
+    // so maybe we can just declare it as a pointer to one type?
+    if (it->second.same_type != Type::Void) {
+      return cat(GetDecompTypeName(it->second.same_type), "_ptr",
+                 GenAlign(it->second.same_align, it->second.last_opc));
+    }
+    return "";
+  }
+
+  std::string GenAccess(uint64_t offset, const Node& addr_exp) const {
+    auto name = AddrExpName(addr_exp);
+    if (name.empty()) {
+      return "";
+    }
+    auto it = vars.find(name);
+    if (it == vars.end()) {
+      return "";
+    }
+    if (it->second.struct_layout) {
+      auto ait = it->second.accesses.find(offset);
+      assert (ait != it->second.accesses.end());
+      return IdxToName(ait->second.idx);
+    }
+    // Not a struct, see if it is a typed pointer.
+    if (it->second.same_type != Type::Void) {
+      return "*";
+    }
+    return "";
+  }
+
+  void Clear() {
+    vars.clear();
+  }
+
+  std::map<std::string, LSVar> vars;
+};
+
+}  // namespace wabt
+
+#endif  // WABT_DECOMPILER_LS_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-naming.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler-naming.h
new file mode 100644 (file)
index 0000000..5400ef9
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2019 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_DECOMPILER_NAMING_H_
+#define WABT_DECOMPILER_NAMING_H_
+
+#include "src/decompiler-ast.h"
+
+#include <set>
+
+namespace wabt {
+
+inline void RenameToIdentifier(std::string& name, Index i,
+                               BindingHash& bh,
+                               const std::set<string_view>* filter) {
+  // Filter out non-identifier characters, and try to reduce the size of
+  // gigantic C++ signature names.
+  std::string s;
+  size_t nesting = 0;
+  size_t read = 0;
+  size_t word_start = 0;
+  for (auto c : name) {
+    read++;
+    // We most certainly don't want to parse the entirety of C++ signatures,
+    // but these names are sometimes several lines long, so would be great
+    // to trim down. One quick way to do that is to remove anything between
+    // nested (), which usually means the parameter list.
+    if (c == '(') {
+      nesting++;
+    }
+    if (c == ')') {
+      nesting--;
+    }
+    if (nesting) {
+      continue;
+    }
+    if (!isalnum(static_cast<unsigned char>(c))) {
+      c = '_';
+    }
+    if (c == '_') {
+      if (s.empty()) {
+        continue;  // Skip leading.
+      }
+      if (s.back() == '_') {
+        continue;  // Consecutive.
+      }
+    }
+    s += c;
+    if (filter && (c == '_' || read == name.size())) {
+      // We found a "word" inside a snake_case identifier.
+      auto word_end = s.size();
+      if (c == '_') {
+        word_end--;
+      }
+      assert(word_end > word_start);
+      auto word = string_view(s.c_str() + word_start, word_end - word_start);
+      if (filter->find(word) != filter->end()) {
+        s.resize(word_start);
+      }
+      word_start = s.size();
+    }
+  }
+  if (!s.empty() && s.back() == '_') {
+    s.pop_back();  // Trailing.
+  }
+  // If after all this culling, we're still gigantic (STL identifier can
+  // easily be hundreds of chars in size), just cut the identifier
+  // down, it will be disambiguated below, if needed.
+  const size_t max_identifier_length = 100;
+  if (s.size() > max_identifier_length) {
+    s.resize(max_identifier_length);
+  }
+  // Remove original binding first, such that it doesn't match with our
+  // new name.
+  bh.erase(name);
+  // Find a unique name.
+  Index disambiguator = 0;
+  auto base_len = s.size();
+  for (;;) {
+    if (bh.count(s) == 0) {
+      break;
+    }
+    disambiguator++;
+    s.resize(base_len);
+    s += '_';
+    s += std::to_string(disambiguator);
+  }
+  // Replace name in bindings.
+  name = s;
+  bh.emplace(s, Binding(i));
+}
+
+template<typename T>
+void RenameToIdentifiers(std::vector<T*>& things, BindingHash& bh,
+                         const std::set<string_view>* filter) {
+  Index i = 0;
+  for (auto thing : things) {
+    RenameToIdentifier(thing->name, i++, bh, filter);
+  }
+}
+
+enum {
+  // This a bit arbitrary, change at will.
+  min_content_identifier_size = 7,
+  max_content_identifier_size = 30
+};
+
+void RenameToContents(std::vector<DataSegment*>& segs, BindingHash& bh) {
+  std::string s;
+  for (auto seg : segs) {
+    if (seg->name.substr(0, 2) != "d_") {
+      // This segment was named explicitly by a symbol.
+      // FIXME: this is not a great check, a symbol could start with d_.
+      continue;
+    }
+    s = "d_";
+    for (auto c : seg->data) {
+      if (isalnum(c) || c == '_') {
+        s += static_cast<char>(c);
+      }
+      if (s.size() >= max_content_identifier_size) {
+        // We truncate any very long names, since those make for hard to
+        // format output. They can be somewhat long though, since data segment
+        // references tend to not occur that often.
+        break;
+      }
+    }
+    if (s.size() < min_content_identifier_size) {
+      // It is useful to have a minimum, since if there few printable characters
+      // in a data section, that is probably a sign of binary, and those few
+      // characters are not going to be very significant.
+      continue;
+    }
+    // We could do the same disambiguition as RenameToIdentifier and
+    // GenerateNames do, but if we come up with a clashing name here it is
+    // likely a sign of not very meaningful binary data, so it is easier to
+    // just keep the original generated name in that case.
+    if (bh.count(s) != 0) {
+      continue;
+    }
+    // Remove original entry.
+    bh.erase(seg->name);
+    seg->name = s;
+    bh.emplace(s, Binding(static_cast<Index>(&seg - &segs[0])));
+  }
+}
+
+// Function names may contain arbitrary C++ syntax, so we want to
+// filter those to look like identifiers. A function name may be set
+// by a name section (applied in ReadBinaryIr, called before this function)
+// or by an export (applied by GenerateNames, called before this function),
+// to both the Func and func_bindings.
+// Those names then further perculate down the IR in ApplyNames (called after
+// this function).
+// To not have to add too many decompiler-specific code into those systems
+// (using a callback??) we instead rename everything here.
+// Also do data section renaming here.
+void RenameAll(Module& module) {
+  // We also filter common C++ keywords/STL idents that make for huge
+  // identifiers.
+  // FIXME: this can obviously give bad results if the input is not C++..
+  std::set<string_view> filter = {
+    { "const" },
+    { "std" },
+    { "allocator" },
+    { "char" },
+    { "basic" },
+    { "traits" },
+    { "wchar" },
+    { "t" },
+    { "void" },
+    { "int" },
+    { "unsigned" },
+    { "2" },
+    { "cxxabiv1" },
+    { "short" },
+    { "4096ul" },
+  };
+  RenameToIdentifiers(module.funcs, module.func_bindings, &filter);
+  // Also do this for some other kinds of names, but without the keyword
+  // substitution.
+  RenameToIdentifiers(module.globals, module.global_bindings, nullptr);
+  RenameToIdentifiers(module.tables, module.table_bindings, nullptr);
+  RenameToIdentifiers(module.events, module.event_bindings, nullptr);
+  RenameToIdentifiers(module.exports, module.export_bindings, nullptr);
+  RenameToIdentifiers(module.types, module.type_bindings, nullptr);
+  RenameToIdentifiers(module.memories, module.memory_bindings, nullptr);
+  RenameToIdentifiers(module.data_segments, module.data_segment_bindings,
+                      nullptr);
+  RenameToIdentifiers(module.elem_segments, module.elem_segment_bindings,
+                      nullptr);
+  // Special purpose naming for data segments.
+  RenameToContents(module.data_segments, module.data_segment_bindings);
+}
+
+}  // namespace wabt
+
+#endif  // WABT_DECOMPILER_NAMING_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.cc
new file mode 100644 (file)
index 0000000..373d669
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+ * Copyright 2019 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/decompiler.h"
+
+#include "src/decompiler-ast.h"
+#include "src/decompiler-ls.h"
+#include "src/decompiler-naming.h"
+
+#include "src/stream.h"
+
+#define WABT_TRACING 0
+#include "src/tracing.h"
+
+#include <inttypes.h>
+
+namespace wabt {
+
+struct Decompiler {
+  Decompiler(const Module& module, const DecompileOptions& options)
+      : mc(module), options(options) {}
+
+  // Sorted such that "greater precedence" is also the bigger enum val.
+  enum Precedence {
+    // Low precedence.
+    None,      // precedence doesn't matter, since never nested.
+    Assign,    // =
+    OtherBin,  // min
+    Bit,       // & |
+    Equal,     // == != < > >= <=
+    Shift,     // << >>
+    Add,       // + -
+    Multiply,  // * / %
+    If,        // if{}
+    Indexing,  // []
+    Atomic,    // (), a, 1, a()
+    // High precedence.
+  };
+
+  // Anything besides these will get parentheses if used with equal precedence,
+  // for clarity.
+  bool Associative(Precedence p) {
+    return p == Precedence::Add || p == Precedence::Multiply;
+  }
+
+  struct Value {
+    std::vector<std::string> v;
+    // Lazily add bracketing only if the parent requires it.
+    // This is the precedence level of this value, for example, if this
+    // precedence is Add, and the parent is Multiply, bracketing is needed,
+    // but not if it is the reverse.
+    Precedence precedence;
+
+    Value(std::vector<std::string>&& v, Precedence p)
+      : v(v), precedence(p) {}
+
+    size_t width() {
+      size_t w = 0;
+      for (auto &s : v) {
+        w = std::max(w, s.size());
+      }
+      return w;
+    }
+
+    // This value should really never be copied, only moved.
+    Value(Value&& rhs) = default;
+    Value(const Value& rhs) = delete;
+    Value& operator=(Value&& rhs) = default;
+    Value& operator=(const Value& rhs) = delete;
+  };
+
+  std::string to_string(double d) {
+    auto s = std::to_string(d);
+    // Remove redundant trailing '0's that to_string produces.
+    while (s.size() > 2 && s.back() == '0' && s[s.size() - 2] != '.')
+      s.pop_back();
+    return s;
+  }
+
+  std::string Indent(size_t amount) {
+    return std::string(amount, ' ');
+  }
+
+  std::string OpcodeToToken(Opcode opcode) {
+    std::string s = opcode.GetDecomp();
+    std::replace(s.begin(), s.end(), '.', '_');
+    return s;
+  }
+
+  void IndentValue(Value &val, size_t amount, string_view first_indent) {
+    auto indent = Indent(amount);
+    for (auto& stat : val.v) {
+      auto is = (&stat != &val.v[0] || first_indent.empty())
+                    ? string_view(indent)
+                    : first_indent;
+      stat.insert(0, is.data(), is.size());
+    }
+  }
+
+  Value WrapChild(Value &child, string_view prefix, string_view postfix,
+                  Precedence precedence) {
+    auto width = prefix.size() + postfix.size() + child.width();
+    auto &v = child.v;
+    if (width < target_exp_width ||
+        (prefix.size() <= indent_amount && postfix.size() <= indent_amount)) {
+      if (v.size() == 1) {
+        // Fits in a single line.
+        v[0].insert(0, prefix.data(), prefix.size());
+        v[0].append(postfix.data(), postfix.size());
+      } else {
+        // Multiline, but with prefix on same line.
+        IndentValue(child, prefix.size(), prefix);
+        v.back().append(postfix.data(), postfix.size());
+      }
+    } else {
+      // Multiline with prefix on its own line.
+      IndentValue(child, indent_amount, {});
+      v.insert(v.begin(), std::string(prefix));
+      v.back().append(postfix.data(), postfix.size());
+    }
+    child.precedence = precedence;
+    return std::move(child);
+  }
+
+  void BracketIfNeeded(Value &val, Precedence parent_precedence) {
+    if (parent_precedence < val.precedence ||
+        (parent_precedence == val.precedence &&
+         Associative(parent_precedence))) return;
+    val = WrapChild(val, "(", ")", Precedence::Atomic);
+  }
+
+  Value WrapBinary(std::vector<Value>& args, string_view infix,
+                   bool indent_right, Precedence precedence) {
+    assert(args.size() == 2);
+    auto& left = args[0];
+    auto& right = args[1];
+    BracketIfNeeded(left, precedence);
+    BracketIfNeeded(right, precedence);
+    auto width = infix.size() + left.width() + right.width();
+    if (width < target_exp_width && left.v.size() == 1 && right.v.size() == 1) {
+      return Value{{left.v[0] + infix + right.v[0]}, precedence};
+    } else {
+      Value bin { {}, precedence };
+      std::move(left.v.begin(), left.v.end(), std::back_inserter(bin.v));
+      bin.v.back().append(infix.data(), infix.size());
+      if (indent_right) IndentValue(right, indent_amount, {});
+      std::move(right.v.begin(), right.v.end(), std::back_inserter(bin.v));
+      return bin;
+    }
+  }
+
+  Value WrapNAry(std::vector<Value>& args, string_view prefix,
+                 string_view postfix, Precedence precedence) {
+    size_t total_width = 0;
+    size_t max_width = 0;
+    bool multiline = false;
+    for (auto& child : args) {
+      auto w = child.width();
+      max_width = std::max(max_width, w);
+      total_width += w;
+      multiline = multiline || child.v.size() > 1;
+    }
+    if (!multiline &&
+        (total_width + prefix.size() + postfix.size() < target_exp_width ||
+         args.empty())) {
+      // Single line.
+      auto s = std::string(prefix);
+      for (auto& child : args) {
+        if (&child != &args[0])
+          s += ", ";
+        s += child.v[0];
+      }
+      s += postfix;
+      return Value{{std::move(s)}, precedence};
+    } else {
+      // Multi-line.
+      Value ml { {}, precedence };
+      auto ident_with_name = max_width + prefix.size() < target_exp_width;
+      size_t i = 0;
+      for (auto& child : args) {
+        IndentValue(child, ident_with_name ? prefix.size() : indent_amount,
+                    !i && ident_with_name ? prefix : string_view {});
+        if (i < args.size() - 1) child.v.back() += ",";
+        std::move(child.v.begin(), child.v.end(),
+                  std::back_inserter(ml.v));
+        i++;
+      }
+      if (!ident_with_name) ml.v.insert(ml.v.begin(), std::string(prefix));
+      ml.v.back() += postfix;
+      return ml;
+    }
+  }
+
+  string_view VarName(string_view name) {
+    assert(!name.empty());
+    return name[0] == '$' ? name.substr(1) : name;
+  }
+
+  template<ExprType T> Value Get(const VarExpr<T>& ve) {
+    return Value{{std::string(VarName(ve.var.name()))}, Precedence::Atomic};
+  }
+
+  template<ExprType T> Value Set(Value& child, const VarExpr<T>& ve) {
+    return WrapChild(child, VarName(ve.var.name()) + " = ", "", Precedence::Assign);
+  }
+
+  std::string TempVarName(Index n) {
+    // FIXME: this needs much better variable naming. Problem is, the code
+    // in generate-names.cc has allready run, its dictionaries deleted, so it
+    // is not easy to integrate with it.
+    return "t" + std::to_string(n);
+  }
+
+  std::string LocalDecl(const std::string& name, Type t) {
+    auto struc = lst.GenTypeDecl(name);
+    return cat(VarName(name), ":",
+               struc.empty() ? GetDecompTypeName(t) : struc);
+  }
+
+  bool ConstIntVal(const Expr* e, uint64_t &dest) {
+    dest = 0;
+    if (!e || e->type() != ExprType::Const) return false;
+    auto& c = cast<ConstExpr>(e)->const_;
+    if (c.type() != Type::I32 && c.type() != Type::I64) return false;
+    dest = c.type() == Type::I32 ? c.u32() : c.u64();
+    return true;
+  }
+
+  void LoadStore(Value &val, const Node& addr_exp, uint64_t offset,
+                  Opcode opc, Address align, Type op_type) {
+    bool append_type = true;
+    auto access = lst.GenAccess(offset, addr_exp);
+    if (!access.empty()) {
+      if (access == "*") {
+        // The variable was declared as a typed pointer, so this access
+        // doesn't need a type.
+        append_type = false;
+      } else {
+        // We can do this load/store as a struct access.
+        BracketIfNeeded(val, Precedence::Indexing);
+        val.v.back() += "." + access;
+        return;
+      }
+    }
+    // Detect absolute addressing, which we try to turn into references to the
+    // data section when possible.
+    uint64_t abs_base;
+    if (ConstIntVal(addr_exp.e, abs_base)) {
+      // We don't care what part of the absolute address was stored where,
+      // 1[0] and 0[1] are the same.
+      abs_base += offset;
+      // FIXME: make this less expensive with a binary search or whatever.
+      for (auto dat : mc.module.data_segments) {
+        uint64_t dat_base;
+        if (dat->offset.size() == 1 &&
+            ConstIntVal(&dat->offset.front(), dat_base) &&
+            abs_base >= dat_base &&
+            abs_base < dat_base + dat->data.size()) {
+          // We are inside the range of this data segment!
+          // Turn expression into data_name[index]
+          val = Value { { dat->name }, Precedence::Atomic };
+          // The new offset is from the start of the data segment, instead of
+          // whatever it was.. this may be a different value from both the
+          // original const and offset!
+          offset = abs_base - dat_base;
+        }
+      }
+    }
+    // Do the load/store as a generalized indexing operation.
+    // The offset is divisible by the alignment in 99.99% of
+    // cases, but the spec doesn't guarantee it, so we must
+    // have a backup syntax.
+    auto index = offset % align == 0
+                ? std::to_string(offset / align)
+                : cat(std::to_string(offset), "@", std::to_string(align));
+    // Detect the very common case of (base + (index << 2))[0]:int etc.
+    // so we can instead do base[index]:int
+    // TODO: (index << 2) on the left of + occurs also.
+    // TODO: sadly this does not address cases where the shift amount > align.
+    // (which happens for arrays of structs or arrays of long (with align=4)).
+    // TODO: also very common is (v = base + (index << 2))[0]:int
+    if (addr_exp.etype == ExprType::Binary) {
+      auto& pe = *cast<BinaryExpr>(addr_exp.e);
+      auto& shift_exp = addr_exp.children[1];
+      if (pe.opcode == Opcode::I32Add &&
+          shift_exp.etype == ExprType::Binary) {
+        auto& se = *cast<BinaryExpr>(shift_exp.e);
+        auto& const_exp = shift_exp.children[1];
+        if (se.opcode == Opcode::I32Shl &&
+            const_exp.etype == ExprType::Const) {
+          auto& ce = *cast<ConstExpr>(const_exp.e);
+          if (ce.const_.type() == Type::I32 &&
+              (1ULL << ce.const_.u32()) == align) {
+            // Pfew, case detected :( Lets re-write this in Haskell.
+            // TODO: we're decompiling these twice.
+            // The thing to the left of << is going to be part of the index.
+            auto ival = DecompileExpr(shift_exp.children[0], &shift_exp);
+            if (ival.v.size() == 1) {  // Don't bother if huge.
+              if (offset == 0) {
+                index = ival.v[0];
+              } else {
+                BracketIfNeeded(ival, Precedence::Add);
+                index = cat(ival.v[0], " + ", index);
+              }
+              // We're going to use the thing to the left of + as the new
+              // base address:
+              val = DecompileExpr(addr_exp.children[0], &addr_exp);
+            }
+          }
+        }
+      }
+    }
+    BracketIfNeeded(val, Precedence::Indexing);
+    val.v.back() += cat("[", index, "]");
+    if (append_type) {
+      val.v.back() +=
+        cat(":", GetDecompTypeName(GetMemoryType(op_type, opc)),
+            lst.GenAlign(align, opc));
+    }
+    val.precedence = Precedence::Indexing;
+  }
+
+  Value DecompileExpr(const Node& n, const Node* parent) {
+    std::vector<Value> args;
+    for (auto& c : n.children) {
+      args.push_back(DecompileExpr(c, &n));
+    }
+    // First deal with the specialized node types.
+    switch (n.ntype) {
+      case NodeType::FlushToVars: {
+        std::string decls = "let ";
+        for (Index i = 0; i < n.u.var_count; i++) {
+          if (i) decls += ", ";
+          decls += TempVarName(n.u.var_start + i);
+        }
+        decls += " = ";
+        return WrapNAry(args, decls, "", Precedence::Assign);
+      }
+      case NodeType::FlushedVar: {
+        return Value { { TempVarName(n.u.var_start) }, Precedence::Atomic };
+      }
+      case NodeType::Statements: {
+        Value stats { {}, Precedence::None };
+        for (size_t i = 0; i < n.children.size(); i++) {
+          auto& s = args[i].v.back();
+          if (s.back() != '}' && s.back() != ':') s += ';';
+          std::move(args[i].v.begin(), args[i].v.end(),
+                    std::back_inserter(stats.v));
+        }
+        return stats;
+      }
+      case NodeType::EndReturn: {
+        return WrapNAry(args, "return ", "", Precedence::None);
+      }
+      case NodeType::Decl: {
+        cur_ast->vars_defined[n.u.var->name()].defined = true;
+        return Value{
+            {"var " + LocalDecl(std::string(n.u.var->name()),
+                                cur_func->GetLocalType(*n.u.var))},
+            Precedence::None};
+      }
+      case NodeType::DeclInit: {
+        if (cur_ast->vars_defined[n.u.var->name()].defined) {
+          // This has already been pre-declared, output as assign.
+          return WrapChild(args[0], cat(VarName(n.u.var->name()), " = "), "",
+                           Precedence::None);
+        } else {
+          return WrapChild(
+              args[0],
+              cat("var ",
+                  LocalDecl(std::string(n.u.var->name()),
+                            cur_func->GetLocalType(*n.u.var)),
+                  " = "),
+              "", Precedence::None);
+        }
+      }
+      case NodeType::Expr:
+        // We're going to fall thru to the second switch to deal with ExprType.
+        break;
+      case NodeType::Uninitialized:
+        assert(false);
+        break;
+    }
+    // Existing ExprTypes.
+    switch (n.etype) {
+      case ExprType::Const: {
+        auto& c = cast<ConstExpr>(n.e)->const_;
+        switch (c.type()) {
+          case Type::I32:
+            return Value{{std::to_string(static_cast<int32_t>(c.u32()))},
+                         Precedence::Atomic};
+          case Type::I64:
+            return Value{{std::to_string(static_cast<int64_t>(c.u64())) + "L"},
+                         Precedence::Atomic};
+          case Type::F32: {
+            float f = Bitcast<float>(c.f32_bits());
+            return Value{{to_string(f) + "f"}, Precedence::Atomic};
+          }
+          case Type::F64: {
+            double d = Bitcast<double>(c.f64_bits());
+            return Value{{to_string(d)}, Precedence::Atomic};
+          }
+          case Type::V128:
+            return Value{{"V128"}, Precedence::Atomic};  // FIXME
+          default:
+            WABT_UNREACHABLE;
+        }
+      }
+      case ExprType::LocalGet: {
+        return Get(*cast<LocalGetExpr>(n.e));
+      }
+      case ExprType::GlobalGet: {
+        return Get(*cast<GlobalGetExpr>(n.e));
+      }
+      case ExprType::LocalSet: {
+        return Set(args[0], *cast<LocalSetExpr>(n.e));
+      }
+      case ExprType::GlobalSet: {
+        return Set(args[0], *cast<GlobalSetExpr>(n.e));
+      }
+      case ExprType::LocalTee: {
+        auto& te = *cast<LocalTeeExpr>(n.e);
+        return args.empty() ? Get(te) : Set(args[0], te);
+      }
+      case ExprType::Binary: {
+        auto& be = *cast<BinaryExpr>(n.e);
+        auto opcs = OpcodeToToken(be.opcode);
+        // TODO: Is this selection better done on Opcode values directly?
+        // What if new values get added and OtherBin doesn't make sense?
+        auto prec = Precedence::OtherBin;
+        if (opcs == "*" || opcs == "/" || opcs == "%") {
+          prec = Precedence::Multiply;
+        } else if (opcs == "+" || opcs == "-") {
+          prec = Precedence::Add;
+        } else if (opcs == "&" || opcs == "|" || opcs == "^") {
+          prec = Precedence::Bit;
+        } else if (opcs == "<<" || opcs == ">>") {
+          prec = Precedence::Shift;
+        }
+        return WrapBinary(args, cat(" ", opcs, " "), false, prec);
+      }
+      case ExprType::Compare: {
+        auto& ce = *cast<CompareExpr>(n.e);
+         return WrapBinary(args, cat(" ", OpcodeToToken(ce.opcode), " "), false,
+                           Precedence::Equal);
+      }
+      case ExprType::Unary: {
+        auto& ue = *cast<UnaryExpr>(n.e);
+        //BracketIfNeeded(stack.back());
+        // TODO: also version without () depending on precedence.
+        return WrapChild(args[0], OpcodeToToken(ue.opcode) + "(", ")",
+                         Precedence::Atomic);
+      }
+      case ExprType::Load: {
+        auto& le = *cast<LoadExpr>(n.e);
+        LoadStore(args[0], n.children[0], le.offset, le.opcode, le.align,
+                  le.opcode.GetResultType());
+        return std::move(args[0]);
+      }
+      case ExprType::Store: {
+        auto& se = *cast<StoreExpr>(n.e);
+        LoadStore(args[0], n.children[0], se.offset, se.opcode, se.align,
+                  se.opcode.GetParamType2());
+        return WrapBinary(args, " = ", true, Precedence::Assign);
+      }
+      case ExprType::If: {
+        auto ife = cast<IfExpr>(n.e);
+        Value *elsep = nullptr;
+        if (!ife->false_.empty()) {
+          elsep = &args[2];
+        }
+        auto& thenp = args[1];
+        auto& ifs = args[0];
+        bool multiline = ifs.v.size() > 1 || thenp.v.size() > 1;
+        size_t width = ifs.width() + thenp.width();
+        if (elsep) {
+          width += elsep->width();
+          multiline = multiline || elsep->v.size() > 1;
+        }
+        multiline = multiline || width > target_exp_width;
+        if (multiline) {
+          auto if_start = string_view("if (");
+          IndentValue(ifs, if_start.size(), if_start);
+          ifs.v.back() += ") {";
+          IndentValue(thenp, indent_amount, {});
+          std::move(thenp.v.begin(), thenp.v.end(), std::back_inserter(ifs.v));
+          if (elsep) {
+            ifs.v.push_back("} else {");
+            IndentValue(*elsep, indent_amount, {});
+            std::move(elsep->v.begin(), elsep->v.end(), std::back_inserter(ifs.v));
+          }
+          ifs.v.push_back("}");
+          ifs.precedence = Precedence::If;
+          return std::move(ifs);
+        } else {
+          auto s = cat("if (", ifs.v[0], ") { ", thenp.v[0], " }");
+          if (elsep)
+            s += cat(" else { ", elsep->v[0], " }");
+          return Value{{std::move(s)}, Precedence::If};
+        }
+      }
+      case ExprType::Block: {
+        auto& val = args[0];
+        val.v.push_back(
+              cat("label ", VarName(cast<BlockExpr>(n.e)->block.label), ":"));
+        // If this block is part of a larger statement scope, it doesn't
+        // need its own indenting, but if its part of an exp we wrap it in {}.
+        if (parent && parent->ntype != NodeType::Statements
+                   && parent->etype != ExprType::Block
+                   && parent->etype != ExprType::Loop
+                   && (parent->etype != ExprType::If ||
+                       &parent->children[0] == &n)) {
+          IndentValue(val, indent_amount, {});
+          val.v.insert(val.v.begin(), "{");
+          val.v.push_back("}");
+        }
+        val.precedence = Precedence::Atomic;
+        return std::move(val);
+      }
+      case ExprType::Loop: {
+        auto& val = args[0];
+        auto& block = cast<LoopExpr>(n.e)->block;
+        IndentValue(val, indent_amount, {});
+        val.v.insert(val.v.begin(), cat("loop ", VarName(block.label), " {"));
+        val.v.push_back("}");
+        val.precedence = Precedence::Atomic;
+        return std::move(val);
+      }
+      case ExprType::Br: {
+        auto be = cast<BrExpr>(n.e);
+        return Value{{(n.u.lt == LabelType::Loop ? "continue " : "goto ") +
+                      VarName(be->var.name())},
+                     Precedence::None};
+      }
+      case ExprType::BrIf: {
+        auto bie = cast<BrIfExpr>(n.e);
+        auto jmp = n.u.lt == LabelType::Loop ? "continue" : "goto";
+        return WrapChild(args[0], "if (", cat(") ", jmp, " ",
+                                              VarName(bie->var.name())),
+                         Precedence::None);
+      }
+      case ExprType::Return: {
+        return WrapNAry(args, "return ", "", Precedence::None);
+      }
+      case ExprType::Rethrow: {
+        return WrapNAry(args, "rethrow ", "", Precedence::None);
+      }
+      case ExprType::Drop: {
+        // Silent dropping of return values is very common, so currently
+        // don't output this.
+        return std::move(args[0]);
+      }
+      case ExprType::Nop: {
+        return Value{{"nop"}, Precedence::None};
+      }
+      case ExprType::Unreachable: {
+        return Value{{"unreachable"}, Precedence::None};
+      }
+      case ExprType::RefNull: {
+        return Value{{"null"}, Precedence::Atomic};
+      }
+      case ExprType::BrTable: {
+        auto bte = cast<BrTableExpr>(n.e);
+        std::string ts = "br_table[";
+        for (auto &v : bte->targets) {
+          ts += VarName(v.name());
+          ts += ", ";
+        }
+        ts += "..";
+        ts += VarName(bte->default_target.name());
+        ts += "](";
+        return WrapChild(args[0], ts, ")", Precedence::Atomic);
+      }
+      default: {
+        // Everything that looks like a function call.
+        std::string name;
+        auto precedence = Precedence::Atomic;
+        switch (n.etype) {
+          case ExprType::Call:
+            name = cast<CallExpr>(n.e)->var.name();
+            break;
+          case ExprType::ReturnCall:
+            name = "return_call " + cast<ReturnCallExpr>(n.e)->var.name();
+            precedence = Precedence::None;
+            break;
+          case ExprType::Convert:
+            name = std::string(OpcodeToToken(cast<ConvertExpr>(n.e)->opcode));
+            break;
+          case ExprType::Ternary:
+            name = std::string(OpcodeToToken(cast<TernaryExpr>(n.e)->opcode));
+            break;
+          case ExprType::Select:
+            // This one looks like it could be translated to "?:" style ternary,
+            // but the arguments are NOT lazy, and side effects definitely do
+            // occur in the branches. So it has no clear equivalent in C-syntax.
+            // To emphasize that all args are being evaluated in order, we
+            // leave it as a function call.
+            name = "select_if";
+            break;
+          case ExprType::MemoryGrow:
+            name = "memory_grow";
+            break;
+          case ExprType::MemorySize:
+            name = "memory_size";
+            break;
+          case ExprType::MemoryCopy:
+            name = "memory_copy";
+            break;
+          case ExprType::MemoryFill:
+            name = "memory_fill";
+            break;
+          case ExprType::RefIsNull:
+            name = "is_null";
+            break;
+          case ExprType::CallIndirect:
+            name = "call_indirect";
+            break;
+          case ExprType::ReturnCallIndirect:
+            name = "return_call call_indirect";
+            break;
+          default:
+            name = GetExprTypeName(n.etype);
+            break;
+        }
+        return WrapNAry(args, name + "(", ")", precedence);
+      }
+    }
+  }
+
+  bool CheckImportExport(std::string& s,
+                         ExternalKind kind,
+                         Index index,
+                         string_view name) {
+    // Figure out if this thing is imported, exported, or neither.
+    auto is_import = mc.module.IsImport(kind, Var(index));
+    // TODO: is this the best way to check for export?
+    // FIXME: this doesn't work for functions that get renamed in some way,
+    // as the export has the original name..
+    auto xport = mc.module.GetExport(name);
+    auto is_export = xport && xport->kind == kind;
+    if (is_export)
+      s += "export ";
+    if (is_import)
+      s += "import ";
+    return is_import;
+  }
+
+  std::string InitExp(const ExprList &el) {
+    assert(!el.empty());
+    AST ast(mc, nullptr);
+    ast.Construct(el, 1, 0, false);
+    auto val = DecompileExpr(ast.exp_stack[0], nullptr);
+    assert(ast.exp_stack.size() == 1 && val.v.size() == 1);
+    return std::move(val.v[0]);
+  }
+
+  // FIXME: Merge with WatWriter::WriteQuotedData somehow.
+  std::string BinaryToString(const std::vector<uint8_t> &in) {
+    std::string s = "\"";
+    size_t line_start = 0;
+    static const char s_hexdigits[] = "0123456789abcdef";
+    for (auto c : in) {
+      if (c >= ' ' && c <= '~') {
+        s += c;
+      } else {
+        s += '\\';
+        s += s_hexdigits[c >> 4];
+        s += s_hexdigits[c & 0xf];
+      }
+      if (s.size() - line_start > target_exp_width) {
+        if (line_start == 0) {
+          s = "  " + s;
+        }
+        s += "\"\n  ";
+        line_start = s.size();
+        s += "\"";
+      }
+    }
+    s += '\"';
+    return s;
+  }
+
+  std::string Decompile() {
+    std::string s;
+    // Memories.
+    Index memory_index = 0;
+    for (auto m : mc.module.memories) {
+      auto is_import =
+          CheckImportExport(s, ExternalKind::Memory, memory_index, m->name);
+      s += cat("memory ", m->name);
+      if (!is_import) {
+        s += cat("(initial: ", std::to_string(m->page_limits.initial),
+                 ", max: ", std::to_string(m->page_limits.max), ")");
+      }
+      s += ";\n";
+      memory_index++;
+    }
+    if (!mc.module.memories.empty())
+      s += "\n";
+
+    // Globals.
+    Index global_index = 0;
+    for (auto g : mc.module.globals) {
+      auto is_import =
+          CheckImportExport(s, ExternalKind::Global, global_index, g->name);
+      s += cat("global ", g->name, ":", GetDecompTypeName(g->type));
+      if (!is_import) {
+        s += cat(" = ", InitExp(g->init_expr));
+      }
+      s += ";\n";
+      global_index++;
+    }
+    if (!mc.module.globals.empty())
+      s += "\n";
+
+    // Tables.
+    Index table_index = 0;
+    for (auto tab : mc.module.tables) {
+      auto is_import =
+          CheckImportExport(s, ExternalKind::Table, table_index, tab->name);
+      s += cat("table ", tab->name, ":", GetDecompTypeName(tab->elem_type));
+      if (!is_import) {
+        s += cat("(min: ", std::to_string(tab->elem_limits.initial),
+                 ", max: ", std::to_string(tab->elem_limits.max), ")");
+      }
+      s += ";\n";
+      table_index++;
+    }
+    if (!mc.module.tables.empty())
+      s += "\n";
+
+    // Data.
+    for (auto dat : mc.module.data_segments) {
+      s += cat("data ", dat->name, "(offset: ", InitExp(dat->offset), ") = ");
+      auto ds = BinaryToString(dat->data);
+      if (ds.size() > target_exp_width / 2) {
+        s += "\n";
+      }
+      s += ds;
+      s += ";\n";
+    }
+    if (!mc.module.data_segments.empty())
+      s += "\n";
+
+    // Code.
+    Index func_index = 0;
+    for (auto f : mc.module.funcs) {
+      cur_func = f;
+      auto is_import =
+          CheckImportExport(s, ExternalKind::Func, func_index, f->name);
+      AST ast(mc, f);
+      cur_ast = &ast;
+      if (!is_import) {
+        ast.Construct(f->exprs, f->GetNumResults(), 0, true);
+        lst.Track(ast.exp_stack[0]);
+        lst.CheckLayouts();
+      }
+      s += cat("function ", f->name, "(");
+      for (Index i = 0; i < f->GetNumParams(); i++) {
+        if (i)
+          s += ", ";
+        auto t = f->GetParamType(i);
+        auto name = "$" + IndexToAlphaName(i);
+        s += LocalDecl(name, t);
+      }
+      s += ")";
+      if (f->GetNumResults()) {
+        if (f->GetNumResults() == 1) {
+          s += cat(":", GetDecompTypeName(f->GetResultType(0)));
+        } else {
+          s += ":(";
+          for (Index i = 0; i < f->GetNumResults(); i++) {
+            if (i)
+              s += ", ";
+            s += GetDecompTypeName(f->GetResultType(i));
+          }
+          s += ")";
+        }
+      }
+      if (is_import) {
+        s += ";";
+      } else {
+        s += " {\n";
+        auto val = DecompileExpr(ast.exp_stack[0], nullptr);
+        IndentValue(val, indent_amount, {});
+        for (auto& stat : val.v) {
+          s += stat;
+          s += "\n";
+        }
+        s += "}";
+      }
+      s += "\n\n";
+      mc.EndFunc();
+      lst.Clear();
+      func_index++;
+      cur_ast = nullptr;
+      cur_func = nullptr;
+    }
+    return s;
+  }
+
+  ModuleContext mc;
+  const DecompileOptions& options;
+  size_t indent_amount = 2;
+  size_t target_exp_width = 70;
+  const Func* cur_func = nullptr;
+  AST* cur_ast = nullptr;
+  LoadStoreTracking lst;
+};
+
+std::string Decompile(const Module& module, const DecompileOptions& options) {
+  Decompiler decompiler(module, options);
+  return decompiler.Decompile();
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/decompiler.h
new file mode 100644 (file)
index 0000000..89bfe78
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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_DECOMPILER_H_
+#define WABT_DECOMPILER_H_
+
+#include "src/common.h"
+
+namespace wabt {
+
+struct Module;
+class Stream;
+
+struct DecompileOptions {
+};
+
+void RenameAll(Module&);
+
+std::string Decompile(const Module&, const DecompileOptions&);
+
+}  // namespace wabt
+
+#endif /* WABT_DECOMPILER_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-exported.json b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-exported.json
new file mode 100644 (file)
index 0000000..261e8e6
--- /dev/null
@@ -0,0 +1,58 @@
+[
+"_malloc",
+"_wabt_apply_names_module",
+"_wabt_bulk_memory_enabled",
+"_wabt_destroy_errors",
+"_wabt_destroy_features",
+"_wabt_destroy_module",
+"_wabt_destroy_output_buffer",
+"_wabt_destroy_parse_wat_result",
+"_wabt_destroy_read_binary_result",
+"_wabt_destroy_wast_lexer",
+"_wabt_destroy_write_module_result",
+"_wabt_exceptions_enabled",
+"_wabt_format_binary_errors",
+"_wabt_format_text_errors",
+"_wabt_generate_names_module",
+"_wabt_multi_value_enabled",
+"_wabt_mutable_globals_enabled",
+"_wabt_new_errors",
+"_wabt_new_features",
+"_wabt_new_wast_buffer_lexer",
+"_wabt_output_buffer_get_data",
+"_wabt_output_buffer_get_size",
+"_wabt_parse_wast",
+"_wabt_parse_wast_result_get_result",
+"_wabt_parse_wast_result_release_module",
+"_wabt_parse_wat",
+"_wabt_parse_wat_result_get_result",
+"_wabt_parse_wat_result_release_module",
+"_wabt_read_binary",
+"_wabt_read_binary_result_get_result",
+"_wabt_read_binary_result_release_module",
+"_wabt_reference_types_enabled",
+"_wabt_sat_float_to_int_enabled",
+"_wabt_set_bulk_memory_enabled",
+"_wabt_set_exceptions_enabled",
+"_wabt_set_multi_value_enabled",
+"_wabt_set_mutable_globals_enabled",
+"_wabt_set_reference_types_enabled",
+"_wabt_set_sat_float_to_int_enabled",
+"_wabt_set_sign_extension_enabled",
+"_wabt_set_simd_enabled",
+"_wabt_set_tail_call_enabled",
+"_wabt_set_threads_enabled",
+"_wabt_sign_extension_enabled",
+"_wabt_simd_enabled",
+"_wabt_tail_call_enabled",
+"_wabt_threads_enabled",
+"_wabt_validate_module",
+"_wabt_validate_script",
+"_wabt_write_binary_module",
+"_wabt_write_binary_spec_script",
+"_wabt_write_module_result_get_result",
+"_wabt_write_module_result_release_log_output_buffer",
+"_wabt_write_module_result_release_output_buffer",
+"_wabt_write_text_module",
+"_dummy_workaround_for_emscripten_issue_7073"
+]
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-helpers.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/emscripten-helpers.cc
new file mode 100644 (file)
index 0000000..f7c3b45
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * 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_EMSCRIPTEN_HELPERS_H_
+#define WABT_EMSCRIPTEN_HELPERS_H_
+
+#include <cstddef>
+
+#include <algorithm>
+#include <iterator>
+#include <memory>
+#include <utility>
+#include <vector>
+
+#include "src/apply-names.h"
+#include "src/binary-reader-ir.h"
+#include "src/binary-reader.h"
+#include "src/binary-writer-spec.h"
+#include "src/binary-writer.h"
+#include "src/common.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/filenames.h"
+#include "src/generate-names.h"
+#include "src/ir.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-lexer.h"
+#include "src/wast-parser.h"
+#include "src/wat-writer.h"
+
+typedef std::unique_ptr<wabt::OutputBuffer> WabtOutputBufferPtr;
+typedef std::pair<std::string, WabtOutputBufferPtr>
+    WabtFilenameOutputBufferPair;
+
+struct WabtParseWatResult {
+  wabt::Result result;
+  std::unique_ptr<wabt::Module> module;
+};
+
+struct WabtReadBinaryResult {
+  wabt::Result result;
+  std::unique_ptr<wabt::Module> module;
+};
+
+struct WabtWriteModuleResult {
+  wabt::Result result;
+  WabtOutputBufferPtr buffer;
+  WabtOutputBufferPtr log_buffer;
+};
+
+struct WabtWriteScriptResult {
+  wabt::Result result;
+  WabtOutputBufferPtr json_buffer;
+  WabtOutputBufferPtr log_buffer;
+  std::vector<WabtFilenameOutputBufferPair> module_buffers;
+};
+
+struct WabtParseWastResult {
+  wabt::Result result;
+  std::unique_ptr<wabt::Script> script;
+};
+
+extern "C" {
+
+wabt::Features* wabt_new_features(void) {
+  return new wabt::Features();
+}
+
+void wabt_destroy_features(wabt::Features* f) {
+  delete f;
+}
+
+#define WABT_FEATURE(variable, flag, default_, help)                   \
+  bool wabt_##variable##_enabled(wabt::Features* f) {                  \
+    return f->variable##_enabled();                                    \
+  }                                                                    \
+  void wabt_set_##variable##_enabled(wabt::Features* f, int enabled) { \
+    f->set_##variable##_enabled(enabled);                              \
+  }
+#include "src/feature.def"
+#undef WABT_FEATURE
+
+wabt::WastLexer* wabt_new_wast_buffer_lexer(const char* filename,
+                                            const void* data,
+                                            size_t size) {
+  std::unique_ptr<wabt::WastLexer> lexer =
+      wabt::WastLexer::CreateBufferLexer(filename, data, size);
+  return lexer.release();
+}
+
+WabtParseWatResult* wabt_parse_wat(wabt::WastLexer* lexer,
+                                   wabt::Features* features,
+                                   wabt::Errors* errors) {
+  wabt::WastParseOptions options(*features);
+  WabtParseWatResult* result = new WabtParseWatResult();
+  std::unique_ptr<wabt::Module> module;
+  result->result = wabt::ParseWatModule(lexer, &module, errors, &options);
+  result->module = std::move(module);
+  return result;
+}
+
+WabtParseWastResult* wabt_parse_wast(wabt::WastLexer* lexer,
+                                     wabt::Features* features,
+                                     wabt::Errors* errors) {
+  wabt::WastParseOptions options(*features);
+  WabtParseWastResult* result = new WabtParseWastResult();
+  std::unique_ptr<wabt::Script> script;
+  result->result = wabt::ParseWastScript(lexer, &script, errors, &options);
+  result->script = std::move(script);
+  return result;
+}
+
+WabtReadBinaryResult* wabt_read_binary(const void* data,
+                                       size_t size,
+                                       int read_debug_names,
+                                       wabt::Features* features,
+                                       wabt::Errors* errors) {
+  wabt::ReadBinaryOptions options;
+  options.features = *features;
+  options.read_debug_names = read_debug_names;
+
+  WabtReadBinaryResult* result = new WabtReadBinaryResult();
+  wabt::Module* module = new wabt::Module();
+  // TODO(binji): Pass through from wabt_read_binary parameter.
+  const char* filename = "<binary>";
+  result->result =
+      wabt::ReadBinaryIr(filename, data, size, options, errors, module);
+  result->module.reset(module);
+  return result;
+}
+
+wabt::Result::Enum wabt_validate_module(wabt::Module* module,
+                                        wabt::Features* features,
+                                        wabt::Errors* errors) {
+  wabt::ValidateOptions options;
+  options.features = *features;
+  return ValidateModule(module, errors, options);
+}
+
+wabt::Result::Enum wabt_validate_script(wabt::Script* script,
+                                        wabt::Features* features,
+                                        wabt::Errors* errors) {
+  wabt::ValidateOptions options;
+  options.features = *features;
+  return ValidateScript(script, errors, options);
+}
+
+WabtWriteScriptResult* wabt_write_binary_spec_script(
+    wabt::Script* script,
+    const char* source_filename,
+    const char* out_filename,
+    int log,
+    int canonicalize_lebs,
+    int relocatable,
+    int write_debug_names) {
+  wabt::MemoryStream log_stream;
+  wabt::MemoryStream* log_stream_p = log ? &log_stream : nullptr;
+
+  wabt::WriteBinaryOptions options;
+  options.canonicalize_lebs = canonicalize_lebs;
+  options.relocatable = relocatable;
+  options.write_debug_names = write_debug_names;
+
+  std::vector<wabt::FilenameMemoryStreamPair> module_streams;
+  wabt::MemoryStream json_stream(log_stream_p);
+
+  std::string module_filename_noext =
+      wabt::StripExtension(out_filename ? out_filename : source_filename)
+          .to_string();
+
+  WabtWriteScriptResult* result = new WabtWriteScriptResult();
+  result->result = WriteBinarySpecScript(&json_stream, script, source_filename,
+                                         module_filename_noext, options,
+                                         &module_streams, log_stream_p);
+
+  if (result->result == wabt::Result::Ok) {
+    result->json_buffer = json_stream.ReleaseOutputBuffer();
+    result->log_buffer = log ? log_stream.ReleaseOutputBuffer() : nullptr;
+    std::transform(module_streams.begin(), module_streams.end(),
+                   std::back_inserter(result->module_buffers),
+                   [](wabt::FilenameMemoryStreamPair& pair) {
+                     return WabtFilenameOutputBufferPair(
+                         pair.filename, pair.stream->ReleaseOutputBuffer());
+                   });
+  }
+  return result;
+}
+
+wabt::Result::Enum wabt_apply_names_module(wabt::Module* module) {
+  return ApplyNames(module);
+}
+
+wabt::Result::Enum wabt_generate_names_module(wabt::Module* module) {
+  return GenerateNames(module);
+}
+
+WabtWriteModuleResult* wabt_write_binary_module(wabt::Module* module,
+                                                int log,
+                                                int canonicalize_lebs,
+                                                int relocatable,
+                                                int write_debug_names) {
+  wabt::MemoryStream log_stream;
+  wabt::WriteBinaryOptions options;
+  options.canonicalize_lebs = canonicalize_lebs;
+  options.relocatable = relocatable;
+  options.write_debug_names = write_debug_names;
+
+  wabt::MemoryStream stream(log ? &log_stream : nullptr);
+  WabtWriteModuleResult* result = new WabtWriteModuleResult();
+  result->result = WriteBinaryModule(&stream, module, options);
+  if (result->result == wabt::Result::Ok) {
+    result->buffer = stream.ReleaseOutputBuffer();
+    result->log_buffer = log ? log_stream.ReleaseOutputBuffer() : nullptr;
+  }
+  return result;
+}
+
+WabtWriteModuleResult* wabt_write_text_module(wabt::Module* module,
+                                              int fold_exprs,
+                                              int inline_export) {
+  wabt::WriteWatOptions options;
+  options.fold_exprs = fold_exprs;
+  options.inline_export = inline_export;
+
+  wabt::MemoryStream stream;
+  WabtWriteModuleResult* result = new WabtWriteModuleResult();
+  result->result = WriteWat(&stream, module, options);
+  if (result->result == wabt::Result::Ok) {
+    result->buffer = stream.ReleaseOutputBuffer();
+  }
+  return result;
+}
+
+void wabt_destroy_module(wabt::Module* module) {
+  delete module;
+}
+
+void wabt_destroy_wast_lexer(wabt::WastLexer* lexer) {
+  delete lexer;
+}
+
+// Errors
+wabt::Errors* wabt_new_errors(void) {
+  return new wabt::Errors();
+}
+
+wabt::OutputBuffer* wabt_format_text_errors(wabt::Errors* errors,
+                                            wabt::WastLexer* lexer) {
+  auto line_finder = lexer->MakeLineFinder();
+  std::string string_result = FormatErrorsToString(
+      *errors, wabt::Location::Type::Text, line_finder.get());
+
+  wabt::OutputBuffer* result = new wabt::OutputBuffer();
+  std::copy(string_result.begin(), string_result.end(),
+            std::back_inserter(result->data));
+  return result;
+}
+
+wabt::OutputBuffer* wabt_format_binary_errors(wabt::Errors* errors) {
+  std::string string_result =
+      FormatErrorsToString(*errors, wabt::Location::Type::Binary);
+
+  wabt::OutputBuffer* result = new wabt::OutputBuffer();
+  std::copy(string_result.begin(), string_result.end(),
+            std::back_inserter(result->data));
+  return result;
+}
+
+void wabt_destroy_errors(wabt::Errors* errors) {
+  delete errors;
+}
+
+// WabtParseWatResult
+wabt::Result::Enum wabt_parse_wat_result_get_result(
+    WabtParseWatResult* result) {
+  return result->result;
+}
+
+wabt::Module* wabt_parse_wat_result_release_module(WabtParseWatResult* result) {
+  return result->module.release();
+}
+
+void wabt_destroy_parse_wat_result(WabtParseWatResult* result) {
+  delete result;
+}
+
+// WabtParseWastResult
+wabt::Result::Enum wabt_parse_wast_result_get_result(
+    WabtParseWastResult* result) {
+  return result->result;
+}
+
+wabt::Script* wabt_parse_wast_result_release_module(
+    WabtParseWastResult* result) {
+  return result->script.release();
+}
+
+void wabt_destroy_parse_wast_result(WabtParseWastResult* result) {
+  delete result;
+}
+
+// WabtReadBinaryResult
+wabt::Result::Enum wabt_read_binary_result_get_result(
+    WabtReadBinaryResult* result) {
+  return result->result;
+}
+
+wabt::Module* wabt_read_binary_result_release_module(
+    WabtReadBinaryResult* result) {
+  return result->module.release();
+}
+
+void wabt_destroy_read_binary_result(WabtReadBinaryResult* result) {
+  delete result;
+}
+
+// WabtWriteModuleResult
+wabt::Result::Enum wabt_write_module_result_get_result(
+    WabtWriteModuleResult* result) {
+  return result->result;
+}
+
+wabt::OutputBuffer* wabt_write_module_result_release_output_buffer(
+    WabtWriteModuleResult* result) {
+  return result->buffer.release();
+}
+
+wabt::OutputBuffer* wabt_write_module_result_release_log_output_buffer(
+    WabtWriteModuleResult* result) {
+  return result->log_buffer.release();
+}
+
+void wabt_destroy_write_module_result(WabtWriteModuleResult* result) {
+  delete result;
+}
+
+// WabtWriteScriptResult
+wabt::Result::Enum wabt_write_script_result_get_result(
+    WabtWriteScriptResult* result) {
+  return result->result;
+}
+
+wabt::OutputBuffer* wabt_write_script_result_release_json_output_buffer(
+    WabtWriteScriptResult* result) {
+  return result->json_buffer.release();
+}
+
+wabt::OutputBuffer* wabt_write_script_result_release_log_output_buffer(
+    WabtWriteScriptResult* result) {
+  return result->log_buffer.release();
+}
+
+size_t wabt_write_script_result_get_module_count(
+    WabtWriteScriptResult* result) {
+  return result->module_buffers.size();
+}
+
+const char* wabt_write_script_result_get_module_filename(
+    WabtWriteScriptResult* result,
+    size_t index) {
+  return result->module_buffers[index].first.c_str();
+}
+
+wabt::OutputBuffer* wabt_write_script_result_release_module_output_buffer(
+    WabtWriteScriptResult* result,
+    size_t index) {
+  return result->module_buffers[index].second.release();
+}
+
+void wabt_destroy_write_script_result(WabtWriteScriptResult* result) {
+  delete result;
+}
+
+// wabt::OutputBuffer*
+const void* wabt_output_buffer_get_data(wabt::OutputBuffer* output_buffer) {
+  return output_buffer->data.data();
+}
+
+size_t wabt_output_buffer_get_size(wabt::OutputBuffer* output_buffer) {
+  return output_buffer->data.size();
+}
+
+void wabt_destroy_output_buffer(wabt::OutputBuffer* output_buffer) {
+  delete output_buffer;
+}
+
+// See https://github.com/kripken/emscripten/issues/7073.
+void dummy_workaround_for_emscripten_issue_7073(void) {}
+
+}  // extern "C"
+
+#endif /* WABT_EMSCRIPTEN_HELPERS_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.cc
new file mode 100644 (file)
index 0000000..14c5d92
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2018 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/error-formatter.h"
+
+namespace wabt {
+
+namespace {
+
+std::string FormatError(const Error& error,
+                        Location::Type location_type,
+                        const Color& color,
+                        LexerSourceLineFinder* line_finder,
+                        int source_line_max_length,
+                        int indent) {
+  std::string indent_str(indent, ' ');
+  std::string result = indent_str;
+
+  result += color.MaybeBoldCode();
+
+  const Location& loc = error.loc;
+  if (!loc.filename.empty()) {
+    result += loc.filename.to_string();
+    result += ":";
+  }
+
+  if (location_type == Location::Type::Text) {
+    result += StringPrintf("%d:%d: ", loc.line, loc.first_column);
+  } else if (loc.offset != kInvalidOffset) {
+    result += StringPrintf("%07" PRIzx ": ", loc.offset);
+  }
+
+  result += color.MaybeRedCode();
+  result += GetErrorLevelName(error.error_level);
+  result += ": ";
+  result += color.MaybeDefaultCode();
+
+  result += error.message;
+  result += '\n';
+
+  LexerSourceLineFinder::SourceLine source_line;
+  if (line_finder) {
+    line_finder->GetSourceLine(loc, source_line_max_length, &source_line);
+  }
+
+  if (!source_line.line.empty()) {
+    result += indent_str;
+    result += source_line.line;
+    result += '\n';
+    result += indent_str;
+
+    size_t num_spaces = (loc.first_column - 1) - source_line.column_offset;
+    size_t num_carets = loc.last_column - loc.first_column;
+    num_carets = std::min(num_carets, source_line.line.size() - num_spaces);
+    num_carets = std::max<size_t>(num_carets, 1);
+    result.append(num_spaces, ' ');
+    result += color.MaybeBoldCode();
+    result += color.MaybeGreenCode();
+    result.append(num_carets, '^');
+    result += color.MaybeDefaultCode();
+    result += '\n';
+  }
+
+  return result;
+}
+
+}  // End of anonymous namespace
+
+std::string FormatErrorsToString(const Errors& errors,
+                                 Location::Type location_type,
+                                 LexerSourceLineFinder* line_finder,
+                                 const Color& color,
+                                 const std::string& header,
+                                 PrintHeader print_header,
+                                 int source_line_max_length) {
+  std::string result;
+  for (const auto& error : errors) {
+    if (!header.empty()) {
+      switch (print_header) {
+        case PrintHeader::Never:
+          break;
+        case PrintHeader::Once:
+          print_header = PrintHeader::Never;
+          // Fallthrough.
+        case PrintHeader::Always:
+          result += header;
+          result += ":\n";
+          break;
+      }
+    }
+
+    int indent = header.empty() ? 0 : 2;
+
+    result += FormatError(error, location_type, color, line_finder,
+                          source_line_max_length, indent);
+  }
+  return result;
+}
+
+void FormatErrorsToFile(const Errors& errors,
+                        Location::Type location_type,
+                        LexerSourceLineFinder* line_finder,
+                        FILE* file,
+                        const std::string& header,
+                        PrintHeader print_header,
+                        int source_line_max_length) {
+  Color color(file);
+  std::string s =
+      FormatErrorsToString(errors, location_type, line_finder, color, header,
+                           print_header, source_line_max_length);
+  fwrite(s.data(), 1, s.size(), file);
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error-formatter.h
new file mode 100644 (file)
index 0000000..cd2ed91
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2018 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_ERROR_FORMATTER_H_
+#define WABT_ERROR_FORMATTER_H_
+
+#include <cstdio>
+#include <string>
+#include <memory>
+
+#include "src/color.h"
+#include "src/error.h"
+#include "src/lexer-source-line-finder.h"
+
+namespace wabt {
+
+enum class PrintHeader {
+  Never,
+  Once,
+  Always,
+};
+
+std::string FormatErrorsToString(const Errors&,
+                                 Location::Type,
+                                 LexerSourceLineFinder* = nullptr,
+                                 const Color& color = Color(nullptr, false),
+                                 const std::string& header = {},
+                                 PrintHeader print_header = PrintHeader::Never,
+                                 int source_line_max_length = 80);
+
+void FormatErrorsToFile(const Errors&,
+                        Location::Type,
+                        LexerSourceLineFinder* = nullptr,
+                        FILE* = stderr,
+                        const std::string& header = {},
+                        PrintHeader print_header = PrintHeader::Never,
+                        int source_line_max_length = 80);
+
+}  // namespace wabt
+
+#endif  // WABT_ERROR_FORMATTER_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/error.h
new file mode 100644 (file)
index 0000000..cffca1e
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 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_ERROR_H_
+#define WABT_ERROR_H_
+
+#include <string>
+#include <vector>
+
+#include "src/common.h"
+#include "src/string-view.h"
+
+namespace wabt {
+
+enum class ErrorLevel {
+  Warning,
+  Error,
+};
+
+static WABT_INLINE const char* GetErrorLevelName(ErrorLevel error_level) {
+  switch (error_level) {
+    case ErrorLevel::Warning:
+      return "warning";
+    case ErrorLevel::Error:
+      return "error";
+  }
+  WABT_UNREACHABLE;
+}
+
+class Error {
+ public:
+  Error() : error_level(ErrorLevel::Error) {}
+  Error(ErrorLevel error_level, Location loc, string_view message)
+      : error_level(error_level), loc(loc), message(message.to_string()) {}
+
+  ErrorLevel error_level;
+  Location loc;
+  std::string message;
+};
+
+using Errors = std::vector<Error>;
+
+}  // namespace wabt
+
+#endif  //  WABT_ERROR_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.cc
new file mode 100644 (file)
index 0000000..af80e70
--- /dev/null
@@ -0,0 +1,466 @@
+/*
+ * 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/expr-visitor.h"
+
+#include "src/cast.h"
+#include "src/ir.h"
+
+namespace wabt {
+
+ExprVisitor::ExprVisitor(Delegate* delegate) : delegate_(delegate) {}
+
+Result ExprVisitor::VisitExpr(Expr* root_expr) {
+  state_stack_.clear();
+  expr_stack_.clear();
+  expr_iter_stack_.clear();
+  catch_index_stack_.clear();
+
+  PushDefault(root_expr);
+
+  while (!state_stack_.empty()) {
+    State state = state_stack_.back();
+    auto* expr = expr_stack_.back();
+
+    switch (state) {
+      case State::Default:
+        PopDefault();
+        CHECK_RESULT(HandleDefaultState(expr));
+        break;
+
+      case State::Block: {
+        auto block_expr = cast<BlockExpr>(expr);
+        auto& iter = expr_iter_stack_.back();
+        if (iter != block_expr->block.exprs.end()) {
+          PushDefault(&*iter++);
+        } else {
+          CHECK_RESULT(delegate_->EndBlockExpr(block_expr));
+          PopExprlist();
+        }
+        break;
+      }
+
+      case State::IfTrue: {
+        auto if_expr = cast<IfExpr>(expr);
+        auto& iter = expr_iter_stack_.back();
+        if (iter != if_expr->true_.exprs.end()) {
+          PushDefault(&*iter++);
+        } else {
+          CHECK_RESULT(delegate_->AfterIfTrueExpr(if_expr));
+          PopExprlist();
+          PushExprlist(State::IfFalse, expr, if_expr->false_);
+        }
+        break;
+      }
+
+      case State::IfFalse: {
+        auto if_expr = cast<IfExpr>(expr);
+        auto& iter = expr_iter_stack_.back();
+        if (iter != if_expr->false_.end()) {
+          PushDefault(&*iter++);
+        } else {
+          CHECK_RESULT(delegate_->EndIfExpr(if_expr));
+          PopExprlist();
+        }
+        break;
+      }
+
+      case State::Loop: {
+        auto loop_expr = cast<LoopExpr>(expr);
+        auto& iter = expr_iter_stack_.back();
+        if (iter != loop_expr->block.exprs.end()) {
+          PushDefault(&*iter++);
+        } else {
+          CHECK_RESULT(delegate_->EndLoopExpr(loop_expr));
+          PopExprlist();
+        }
+        break;
+      }
+
+      case State::Try: {
+        auto try_expr = cast<TryExpr>(expr);
+        auto& iter = expr_iter_stack_.back();
+        if (iter != try_expr->block.exprs.end()) {
+          PushDefault(&*iter++);
+        } else {
+          PopExprlist();
+          switch (try_expr->kind) {
+            case TryKind::Catch:
+              if (!try_expr->catches.empty()) {
+                Catch& catch_ = try_expr->catches[0];
+                CHECK_RESULT(delegate_->OnCatchExpr(try_expr, &catch_));
+                PushCatch(expr, 0, catch_.exprs);
+              } else {
+                CHECK_RESULT(delegate_->EndTryExpr(try_expr));
+              }
+              break;
+            case TryKind::Unwind:
+              CHECK_RESULT(delegate_->OnUnwindExpr(try_expr));
+              PushExprlist(State::Unwind, expr, try_expr->unwind);
+              break;
+            case TryKind::Delegate:
+              CHECK_RESULT(delegate_->OnDelegateExpr(try_expr));
+              break;
+            case TryKind::Invalid:
+              // Should not happen.
+              break;
+          }
+        }
+        break;
+      }
+
+      case State::Catch: {
+        auto try_expr = cast<TryExpr>(expr);
+        Index catch_index = catch_index_stack_.back();
+        auto& iter = expr_iter_stack_.back();
+        if (iter != try_expr->catches[catch_index].exprs.end()) {
+          PushDefault(&*iter++);
+        } else {
+          PopCatch();
+          catch_index++;
+          if (catch_index < try_expr->catches.size()) {
+            Catch& catch_ = try_expr->catches[catch_index];
+            CHECK_RESULT(delegate_->OnCatchExpr(try_expr, &catch_));
+            PushCatch(expr, catch_index, catch_.exprs);
+          } else {
+            CHECK_RESULT(delegate_->EndTryExpr(try_expr));
+          }
+        }
+        break;
+      }
+
+      case State::Unwind: {
+        auto try_expr = cast<TryExpr>(expr);
+        auto& iter = expr_iter_stack_.back();
+        if (iter != try_expr->unwind.end()) {
+          PushDefault(&*iter++);
+        } else {
+          CHECK_RESULT(delegate_->EndTryExpr(try_expr));
+          PopExprlist();
+        }
+        break;
+      }
+    }
+  }
+
+  return Result::Ok;
+}
+
+Result ExprVisitor::VisitExprList(ExprList& exprs) {
+  for (Expr& expr : exprs)
+    CHECK_RESULT(VisitExpr(&expr));
+  return Result::Ok;
+}
+
+Result ExprVisitor::VisitFunc(Func* func) {
+  return VisitExprList(func->exprs);
+}
+
+Result ExprVisitor::HandleDefaultState(Expr* expr) {
+  switch (expr->type()) {
+    case ExprType::AtomicLoad:
+      CHECK_RESULT(delegate_->OnAtomicLoadExpr(cast<AtomicLoadExpr>(expr)));
+      break;
+
+    case ExprType::AtomicStore:
+      CHECK_RESULT(delegate_->OnAtomicStoreExpr(cast<AtomicStoreExpr>(expr)));
+      break;
+
+    case ExprType::AtomicRmw:
+      CHECK_RESULT(delegate_->OnAtomicRmwExpr(cast<AtomicRmwExpr>(expr)));
+      break;
+
+    case ExprType::AtomicRmwCmpxchg:
+      CHECK_RESULT(
+          delegate_->OnAtomicRmwCmpxchgExpr(cast<AtomicRmwCmpxchgExpr>(expr)));
+      break;
+
+    case ExprType::AtomicWait:
+      CHECK_RESULT(delegate_->OnAtomicWaitExpr(cast<AtomicWaitExpr>(expr)));
+      break;
+
+    case ExprType::AtomicFence:
+      CHECK_RESULT(delegate_->OnAtomicFenceExpr(cast<AtomicFenceExpr>(expr)));
+      break;
+
+    case ExprType::AtomicNotify:
+      CHECK_RESULT(delegate_->OnAtomicNotifyExpr(cast<AtomicNotifyExpr>(expr)));
+      break;
+
+    case ExprType::Binary:
+      CHECK_RESULT(delegate_->OnBinaryExpr(cast<BinaryExpr>(expr)));
+      break;
+
+    case ExprType::Block: {
+      auto block_expr = cast<BlockExpr>(expr);
+      CHECK_RESULT(delegate_->BeginBlockExpr(block_expr));
+      PushExprlist(State::Block, expr, block_expr->block.exprs);
+      break;
+    }
+
+    case ExprType::Br:
+      CHECK_RESULT(delegate_->OnBrExpr(cast<BrExpr>(expr)));
+      break;
+
+    case ExprType::BrIf:
+      CHECK_RESULT(delegate_->OnBrIfExpr(cast<BrIfExpr>(expr)));
+      break;
+
+    case ExprType::BrTable:
+      CHECK_RESULT(delegate_->OnBrTableExpr(cast<BrTableExpr>(expr)));
+      break;
+
+    case ExprType::Call:
+      CHECK_RESULT(delegate_->OnCallExpr(cast<CallExpr>(expr)));
+      break;
+
+    case ExprType::CallIndirect:
+      CHECK_RESULT(delegate_->OnCallIndirectExpr(cast<CallIndirectExpr>(expr)));
+      break;
+
+    case ExprType::Compare:
+      CHECK_RESULT(delegate_->OnCompareExpr(cast<CompareExpr>(expr)));
+      break;
+
+    case ExprType::Const:
+      CHECK_RESULT(delegate_->OnConstExpr(cast<ConstExpr>(expr)));
+      break;
+
+    case ExprType::Convert:
+      CHECK_RESULT(delegate_->OnConvertExpr(cast<ConvertExpr>(expr)));
+      break;
+
+    case ExprType::Drop:
+      CHECK_RESULT(delegate_->OnDropExpr(cast<DropExpr>(expr)));
+      break;
+
+    case ExprType::GlobalGet:
+      CHECK_RESULT(delegate_->OnGlobalGetExpr(cast<GlobalGetExpr>(expr)));
+      break;
+
+    case ExprType::GlobalSet:
+      CHECK_RESULT(delegate_->OnGlobalSetExpr(cast<GlobalSetExpr>(expr)));
+      break;
+
+    case ExprType::If: {
+      auto if_expr = cast<IfExpr>(expr);
+      CHECK_RESULT(delegate_->BeginIfExpr(if_expr));
+      PushExprlist(State::IfTrue, expr, if_expr->true_.exprs);
+      break;
+    }
+
+    case ExprType::Load:
+      CHECK_RESULT(delegate_->OnLoadExpr(cast<LoadExpr>(expr)));
+      break;
+
+    case ExprType::LoadSplat:
+      CHECK_RESULT(delegate_->OnLoadSplatExpr(cast<LoadSplatExpr>(expr)));
+      break;
+
+    case ExprType::LocalGet:
+      CHECK_RESULT(delegate_->OnLocalGetExpr(cast<LocalGetExpr>(expr)));
+      break;
+
+    case ExprType::LocalSet:
+      CHECK_RESULT(delegate_->OnLocalSetExpr(cast<LocalSetExpr>(expr)));
+      break;
+
+    case ExprType::LocalTee:
+      CHECK_RESULT(delegate_->OnLocalTeeExpr(cast<LocalTeeExpr>(expr)));
+      break;
+
+    case ExprType::Loop: {
+      auto loop_expr = cast<LoopExpr>(expr);
+      CHECK_RESULT(delegate_->BeginLoopExpr(loop_expr));
+      PushExprlist(State::Loop, expr, loop_expr->block.exprs);
+      break;
+    }
+
+    case ExprType::MemoryCopy:
+      CHECK_RESULT(delegate_->OnMemoryCopyExpr(cast<MemoryCopyExpr>(expr)));
+      break;
+
+    case ExprType::DataDrop:
+      CHECK_RESULT(delegate_->OnDataDropExpr(cast<DataDropExpr>(expr)));
+      break;
+
+    case ExprType::MemoryFill:
+      CHECK_RESULT(delegate_->OnMemoryFillExpr(cast<MemoryFillExpr>(expr)));
+      break;
+
+    case ExprType::MemoryGrow:
+      CHECK_RESULT(delegate_->OnMemoryGrowExpr(cast<MemoryGrowExpr>(expr)));
+      break;
+
+    case ExprType::MemoryInit:
+      CHECK_RESULT(delegate_->OnMemoryInitExpr(cast<MemoryInitExpr>(expr)));
+      break;
+
+    case ExprType::MemorySize:
+      CHECK_RESULT(delegate_->OnMemorySizeExpr(cast<MemorySizeExpr>(expr)));
+      break;
+
+    case ExprType::TableCopy:
+      CHECK_RESULT(delegate_->OnTableCopyExpr(cast<TableCopyExpr>(expr)));
+      break;
+
+    case ExprType::ElemDrop:
+      CHECK_RESULT(delegate_->OnElemDropExpr(cast<ElemDropExpr>(expr)));
+      break;
+
+    case ExprType::TableInit:
+      CHECK_RESULT(delegate_->OnTableInitExpr(cast<TableInitExpr>(expr)));
+      break;
+
+    case ExprType::TableGet:
+      CHECK_RESULT(delegate_->OnTableGetExpr(cast<TableGetExpr>(expr)));
+      break;
+
+    case ExprType::TableSet:
+      CHECK_RESULT(delegate_->OnTableSetExpr(cast<TableSetExpr>(expr)));
+      break;
+
+    case ExprType::TableGrow:
+      CHECK_RESULT(delegate_->OnTableGrowExpr(cast<TableGrowExpr>(expr)));
+      break;
+
+    case ExprType::TableSize:
+      CHECK_RESULT(delegate_->OnTableSizeExpr(cast<TableSizeExpr>(expr)));
+      break;
+
+    case ExprType::TableFill:
+      CHECK_RESULT(delegate_->OnTableFillExpr(cast<TableFillExpr>(expr)));
+      break;
+
+    case ExprType::RefFunc:
+      CHECK_RESULT(delegate_->OnRefFuncExpr(cast<RefFuncExpr>(expr)));
+      break;
+
+    case ExprType::RefNull:
+      CHECK_RESULT(delegate_->OnRefNullExpr(cast<RefNullExpr>(expr)));
+      break;
+
+    case ExprType::RefIsNull:
+      CHECK_RESULT(delegate_->OnRefIsNullExpr(cast<RefIsNullExpr>(expr)));
+      break;
+
+    case ExprType::Nop:
+      CHECK_RESULT(delegate_->OnNopExpr(cast<NopExpr>(expr)));
+      break;
+
+    case ExprType::Rethrow:
+      CHECK_RESULT(delegate_->OnRethrowExpr(cast<RethrowExpr>(expr)));
+      break;
+
+    case ExprType::Return:
+      CHECK_RESULT(delegate_->OnReturnExpr(cast<ReturnExpr>(expr)));
+      break;
+
+    case ExprType::ReturnCall:
+      CHECK_RESULT(delegate_->OnReturnCallExpr(cast<ReturnCallExpr>(expr)));
+      break;
+
+    case ExprType::ReturnCallIndirect:
+      CHECK_RESULT(delegate_->OnReturnCallIndirectExpr(
+          cast<ReturnCallIndirectExpr>(expr)));
+      break;
+
+    case ExprType::Select:
+      CHECK_RESULT(delegate_->OnSelectExpr(cast<SelectExpr>(expr)));
+      break;
+
+    case ExprType::Store:
+      CHECK_RESULT(delegate_->OnStoreExpr(cast<StoreExpr>(expr)));
+      break;
+
+
+    case ExprType::Throw:
+      CHECK_RESULT(delegate_->OnThrowExpr(cast<ThrowExpr>(expr)));
+      break;
+
+    case ExprType::Try: {
+      auto try_expr = cast<TryExpr>(expr);
+      CHECK_RESULT(delegate_->BeginTryExpr(try_expr));
+      PushExprlist(State::Try, expr, try_expr->block.exprs);
+      break;
+    }
+
+    case ExprType::Unary:
+      CHECK_RESULT(delegate_->OnUnaryExpr(cast<UnaryExpr>(expr)));
+      break;
+
+    case ExprType::Ternary:
+      CHECK_RESULT(delegate_->OnTernaryExpr(cast<TernaryExpr>(expr)));
+      break;
+
+    case ExprType::SimdLaneOp: {
+      CHECK_RESULT(delegate_->OnSimdLaneOpExpr(cast<SimdLaneOpExpr>(expr)));
+      break;
+    }
+
+    case ExprType::SimdShuffleOp: {
+      CHECK_RESULT(
+          delegate_->OnSimdShuffleOpExpr(cast<SimdShuffleOpExpr>(expr)));
+      break;
+    }
+
+    case ExprType::Unreachable:
+      CHECK_RESULT(delegate_->OnUnreachableExpr(cast<UnreachableExpr>(expr)));
+      break;
+  }
+
+  return Result::Ok;
+}
+
+void ExprVisitor::PushDefault(Expr* expr) {
+  state_stack_.emplace_back(State::Default);
+  expr_stack_.emplace_back(expr);
+}
+
+void ExprVisitor::PopDefault() {
+  state_stack_.pop_back();
+  expr_stack_.pop_back();
+}
+
+void ExprVisitor::PushExprlist(State state, Expr* expr, ExprList& expr_list) {
+  state_stack_.emplace_back(state);
+  expr_stack_.emplace_back(expr);
+  expr_iter_stack_.emplace_back(expr_list.begin());
+}
+
+void ExprVisitor::PopExprlist() {
+  state_stack_.pop_back();
+  expr_stack_.pop_back();
+  expr_iter_stack_.pop_back();
+}
+
+void ExprVisitor::PushCatch(Expr* expr,
+                            Index catch_index,
+                            ExprList& expr_list) {
+  state_stack_.emplace_back(State::Catch);
+  expr_stack_.emplace_back(expr);
+  expr_iter_stack_.emplace_back(expr_list.begin());
+  catch_index_stack_.emplace_back(catch_index);
+}
+
+void ExprVisitor::PopCatch() {
+  state_stack_.pop_back();
+  expr_stack_.pop_back();
+  expr_iter_stack_.pop_back();
+  catch_index_stack_.pop_back();
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/expr-visitor.h
new file mode 100644 (file)
index 0000000..f30607c
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * 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_EXPR_VISITOR_H_
+#define WABT_EXPR_VISITOR_H_
+
+#include "src/common.h"
+#include "src/ir.h"
+
+namespace wabt {
+
+class ExprVisitor {
+ public:
+  class Delegate;
+  class DelegateNop;
+
+  explicit ExprVisitor(Delegate* delegate);
+
+  Result VisitExpr(Expr*);
+  Result VisitExprList(ExprList&);
+  Result VisitFunc(Func*);
+
+ private:
+  enum class State {
+    Default,
+    Block,
+    IfTrue,
+    IfFalse,
+    Loop,
+    Try,
+    Catch,
+    Unwind,
+  };
+
+  Result HandleDefaultState(Expr*);
+  void PushDefault(Expr*);
+  void PopDefault();
+  void PushExprlist(State state, Expr*, ExprList&);
+  void PopExprlist();
+  void PushCatch(Expr*, Index catch_index, ExprList&);
+  void PopCatch();
+
+  Delegate* delegate_;
+
+  // Use parallel arrays instead of array of structs so we can avoid allocating
+  // unneeded objects. ExprList::iterator has no default constructor, so it
+  // must only be allocated for states that use it.
+  std::vector<State> state_stack_;
+  std::vector<Expr*> expr_stack_;
+  std::vector<ExprList::iterator> expr_iter_stack_;
+  std::vector<Index> catch_index_stack_;
+};
+
+class ExprVisitor::Delegate {
+ public:
+  virtual ~Delegate() {}
+
+  virtual Result OnBinaryExpr(BinaryExpr*) = 0;
+  virtual Result BeginBlockExpr(BlockExpr*) = 0;
+  virtual Result EndBlockExpr(BlockExpr*) = 0;
+  virtual Result OnBrExpr(BrExpr*) = 0;
+  virtual Result OnBrIfExpr(BrIfExpr*) = 0;
+  virtual Result OnBrTableExpr(BrTableExpr*) = 0;
+  virtual Result OnCallExpr(CallExpr*) = 0;
+  virtual Result OnCallIndirectExpr(CallIndirectExpr*) = 0;
+  virtual Result OnCompareExpr(CompareExpr*) = 0;
+  virtual Result OnConstExpr(ConstExpr*) = 0;
+  virtual Result OnConvertExpr(ConvertExpr*) = 0;
+  virtual Result OnDropExpr(DropExpr*) = 0;
+  virtual Result OnGlobalGetExpr(GlobalGetExpr*) = 0;
+  virtual Result OnGlobalSetExpr(GlobalSetExpr*) = 0;
+  virtual Result BeginIfExpr(IfExpr*) = 0;
+  virtual Result AfterIfTrueExpr(IfExpr*) = 0;
+  virtual Result EndIfExpr(IfExpr*) = 0;
+  virtual Result OnLoadExpr(LoadExpr*) = 0;
+  virtual Result OnLocalGetExpr(LocalGetExpr*) = 0;
+  virtual Result OnLocalSetExpr(LocalSetExpr*) = 0;
+  virtual Result OnLocalTeeExpr(LocalTeeExpr*) = 0;
+  virtual Result BeginLoopExpr(LoopExpr*) = 0;
+  virtual Result EndLoopExpr(LoopExpr*) = 0;
+  virtual Result OnMemoryCopyExpr(MemoryCopyExpr*) = 0;
+  virtual Result OnDataDropExpr(DataDropExpr*) = 0;
+  virtual Result OnMemoryFillExpr(MemoryFillExpr*) = 0;
+  virtual Result OnMemoryGrowExpr(MemoryGrowExpr*) = 0;
+  virtual Result OnMemoryInitExpr(MemoryInitExpr*) = 0;
+  virtual Result OnMemorySizeExpr(MemorySizeExpr*) = 0;
+  virtual Result OnTableCopyExpr(TableCopyExpr*) = 0;
+  virtual Result OnElemDropExpr(ElemDropExpr*) = 0;
+  virtual Result OnTableInitExpr(TableInitExpr*) = 0;
+  virtual Result OnTableGetExpr(TableGetExpr*) = 0;
+  virtual Result OnTableSetExpr(TableSetExpr*) = 0;
+  virtual Result OnTableGrowExpr(TableGrowExpr*) = 0;
+  virtual Result OnTableSizeExpr(TableSizeExpr*) = 0;
+  virtual Result OnTableFillExpr(TableFillExpr*) = 0;
+  virtual Result OnRefFuncExpr(RefFuncExpr*) = 0;
+  virtual Result OnRefNullExpr(RefNullExpr*) = 0;
+  virtual Result OnRefIsNullExpr(RefIsNullExpr*) = 0;
+  virtual Result OnNopExpr(NopExpr*) = 0;
+  virtual Result OnReturnExpr(ReturnExpr*) = 0;
+  virtual Result OnReturnCallExpr(ReturnCallExpr*) = 0;
+  virtual Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) = 0;
+  virtual Result OnSelectExpr(SelectExpr*) = 0;
+  virtual Result OnStoreExpr(StoreExpr*) = 0;
+  virtual Result OnUnaryExpr(UnaryExpr*) = 0;
+  virtual Result OnUnreachableExpr(UnreachableExpr*) = 0;
+  virtual Result BeginTryExpr(TryExpr*) = 0;
+  virtual Result OnCatchExpr(TryExpr*, Catch*) = 0;
+  virtual Result OnUnwindExpr(TryExpr*) = 0;
+  virtual Result OnDelegateExpr(TryExpr*) = 0;
+  virtual Result EndTryExpr(TryExpr*) = 0;
+  virtual Result OnThrowExpr(ThrowExpr*) = 0;
+  virtual Result OnRethrowExpr(RethrowExpr*) = 0;
+  virtual Result OnAtomicWaitExpr(AtomicWaitExpr*) = 0;
+  virtual Result OnAtomicFenceExpr(AtomicFenceExpr*) = 0;
+  virtual Result OnAtomicNotifyExpr(AtomicNotifyExpr*) = 0;
+  virtual Result OnAtomicLoadExpr(AtomicLoadExpr*) = 0;
+  virtual Result OnAtomicStoreExpr(AtomicStoreExpr*) = 0;
+  virtual Result OnAtomicRmwExpr(AtomicRmwExpr*) = 0;
+  virtual Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) = 0;
+  virtual Result OnTernaryExpr(TernaryExpr*) = 0;
+  virtual Result OnSimdLaneOpExpr(SimdLaneOpExpr*) = 0;
+  virtual Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) = 0;
+  virtual Result OnLoadSplatExpr(LoadSplatExpr*) = 0;
+};
+
+class ExprVisitor::DelegateNop : public ExprVisitor::Delegate {
+ public:
+  Result OnBinaryExpr(BinaryExpr*) override { return Result::Ok; }
+  Result BeginBlockExpr(BlockExpr*) override { return Result::Ok; }
+  Result EndBlockExpr(BlockExpr*) override { return Result::Ok; }
+  Result OnBrExpr(BrExpr*) override { return Result::Ok; }
+  Result OnBrIfExpr(BrIfExpr*) override { return Result::Ok; }
+  Result OnBrTableExpr(BrTableExpr*) override { return Result::Ok; }
+  Result OnCallExpr(CallExpr*) override { return Result::Ok; }
+  Result OnCallIndirectExpr(CallIndirectExpr*) override { return Result::Ok; }
+  Result OnCompareExpr(CompareExpr*) override { return Result::Ok; }
+  Result OnConstExpr(ConstExpr*) override { return Result::Ok; }
+  Result OnConvertExpr(ConvertExpr*) override { return Result::Ok; }
+  Result OnDropExpr(DropExpr*) override { return Result::Ok; }
+  Result OnGlobalGetExpr(GlobalGetExpr*) override { return Result::Ok; }
+  Result OnGlobalSetExpr(GlobalSetExpr*) override { return Result::Ok; }
+  Result BeginIfExpr(IfExpr*) override { return Result::Ok; }
+  Result AfterIfTrueExpr(IfExpr*) override { return Result::Ok; }
+  Result EndIfExpr(IfExpr*) override { return Result::Ok; }
+  Result OnLoadExpr(LoadExpr*) override { return Result::Ok; }
+  Result OnLocalGetExpr(LocalGetExpr*) override { return Result::Ok; }
+  Result OnLocalSetExpr(LocalSetExpr*) override { return Result::Ok; }
+  Result OnLocalTeeExpr(LocalTeeExpr*) override { return Result::Ok; }
+  Result BeginLoopExpr(LoopExpr*) override { return Result::Ok; }
+  Result EndLoopExpr(LoopExpr*) override { return Result::Ok; }
+  Result OnMemoryCopyExpr(MemoryCopyExpr*) override { return Result::Ok; }
+  Result OnDataDropExpr(DataDropExpr*) override { return Result::Ok; }
+  Result OnMemoryFillExpr(MemoryFillExpr*) override { return Result::Ok; }
+  Result OnMemoryGrowExpr(MemoryGrowExpr*) override { return Result::Ok; }
+  Result OnMemoryInitExpr(MemoryInitExpr*) override { return Result::Ok; }
+  Result OnMemorySizeExpr(MemorySizeExpr*) override { return Result::Ok; }
+  Result OnTableCopyExpr(TableCopyExpr*) override { return Result::Ok; }
+  Result OnElemDropExpr(ElemDropExpr*) override { return Result::Ok; }
+  Result OnTableInitExpr(TableInitExpr*) override { return Result::Ok; }
+  Result OnTableGetExpr(TableGetExpr*) override { return Result::Ok; }
+  Result OnTableSetExpr(TableSetExpr*) override { return Result::Ok; }
+  Result OnTableGrowExpr(TableGrowExpr*) override { return Result::Ok; }
+  Result OnTableSizeExpr(TableSizeExpr*) override { return Result::Ok; }
+  Result OnTableFillExpr(TableFillExpr*) override { return Result::Ok; }
+  Result OnRefFuncExpr(RefFuncExpr*) override { return Result::Ok; }
+  Result OnRefNullExpr(RefNullExpr*) override { return Result::Ok; }
+  Result OnRefIsNullExpr(RefIsNullExpr*) override { return Result::Ok; }
+  Result OnNopExpr(NopExpr*) override { return Result::Ok; }
+  Result OnReturnExpr(ReturnExpr*) override { return Result::Ok; }
+  Result OnReturnCallExpr(ReturnCallExpr*) override { return Result::Ok; }
+  Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override {
+    return Result::Ok;
+  }
+  Result OnSelectExpr(SelectExpr*) override { return Result::Ok; }
+  Result OnStoreExpr(StoreExpr*) override { return Result::Ok; }
+  Result OnUnaryExpr(UnaryExpr*) override { return Result::Ok; }
+  Result OnUnreachableExpr(UnreachableExpr*) override { return Result::Ok; }
+  Result BeginTryExpr(TryExpr*) override { return Result::Ok; }
+  Result OnCatchExpr(TryExpr*, Catch*) override { return Result::Ok; }
+  Result OnUnwindExpr(TryExpr*) override { return Result::Ok; }
+  Result OnDelegateExpr(TryExpr*) override { return Result::Ok; }
+  Result EndTryExpr(TryExpr*) override { return Result::Ok; }
+  Result OnThrowExpr(ThrowExpr*) override { return Result::Ok; }
+  Result OnRethrowExpr(RethrowExpr*) override { return Result::Ok; }
+  Result OnAtomicWaitExpr(AtomicWaitExpr*) override { return Result::Ok; }
+  Result OnAtomicFenceExpr(AtomicFenceExpr*) override { return Result::Ok; }
+  Result OnAtomicNotifyExpr(AtomicNotifyExpr*) override { return Result::Ok; }
+  Result OnAtomicLoadExpr(AtomicLoadExpr*) override { return Result::Ok; }
+  Result OnAtomicStoreExpr(AtomicStoreExpr*) override { return Result::Ok; }
+  Result OnAtomicRmwExpr(AtomicRmwExpr*) override { return Result::Ok; }
+  Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) override {
+    return Result::Ok;
+  }
+  Result OnTernaryExpr(TernaryExpr*) override { return Result::Ok; }
+  Result OnSimdLaneOpExpr(SimdLaneOpExpr*) override { return Result::Ok; }
+  Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) override { return Result::Ok; }
+  Result OnLoadSplatExpr(LoadSplatExpr*) override { return Result::Ok; }
+};
+
+}  // namespace wabt
+
+#endif  // WABT_EXPR_VISITOR_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.cc
new file mode 100644 (file)
index 0000000..1c72c36
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * 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/feature.h"
+
+#include "src/option-parser.h"
+
+namespace wabt {
+
+void Features::AddOptions(OptionParser* parser) {
+#define WABT_FEATURE(variable, flag, default_, help)       \
+  if (default_ == true) {                                  \
+    parser->AddOption("disable-" flag, "Disable " help,    \
+                      [this]() { disable_##variable(); }); \
+  } else {                                                 \
+    parser->AddOption("enable-" flag, "Enable " help,      \
+                      [this]() { enable_##variable(); });  \
+  }
+
+#include "src/feature.def"
+#undef WABT_FEATURE
+  parser->AddOption("enable-all", "Enable all features",
+                    [this]() { EnableAll(); });
+}
+
+void Features::UpdateDependencies() {
+  // Exception handling requires reference types.
+  if (exceptions_enabled_) {
+    reference_types_enabled_ = true;
+  }
+  // Reference types requires bulk memory.
+  if (reference_types_enabled_) {
+    bulk_memory_enabled_ = true;
+  }
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.def b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.def
new file mode 100644 (file)
index 0000000..17f4de3
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_FEATURE
+#error "You must define WABT_FEATURE before including this file."
+#endif
+
+/*
+ *           variable          flag                       default  help
+ * ========================================================================= */
+
+WABT_FEATURE(exceptions,       "exceptions",              false,   "Experimental exception handling")
+WABT_FEATURE(mutable_globals,  "mutable-globals",         true,    "Import/export mutable globals")
+WABT_FEATURE(sat_float_to_int, "saturating-float-to-int", true,    "Saturating float-to-int operators")
+WABT_FEATURE(sign_extension,   "sign-extension",          true,    "Sign-extension operators")
+WABT_FEATURE(simd,             "simd",                    false,   "SIMD support")
+WABT_FEATURE(threads,          "threads",                 false,   "Threading support")
+WABT_FEATURE(multi_value,      "multi-value",             true,    "Multi-value")
+WABT_FEATURE(tail_call,        "tail-call",               false,   "Tail-call support")
+WABT_FEATURE(bulk_memory,      "bulk-memory",             false,   "Bulk-memory operations")
+WABT_FEATURE(reference_types,  "reference-types",         false,   "Reference types (externref)")
+WABT_FEATURE(annotations,      "annotations",             false,   "Custom annotation syntax")
+WABT_FEATURE(gc,               "gc",                      false,   "Garbage collection")
+WABT_FEATURE(memory64,         "memory64",                false,   "64-bit memory")
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/feature.h
new file mode 100644 (file)
index 0000000..7ebc9ef
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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_FEATURE_H_
+#define WABT_FEATURE_H_
+
+#include "src/common.h"
+
+namespace wabt {
+
+class OptionParser;
+
+class Features {
+ public:
+  void AddOptions(OptionParser*);
+
+  void EnableAll() {
+#define WABT_FEATURE(variable, flag, default_, help) enable_##variable();
+#include "src/feature.def"
+#undef WABT_FEATURE
+  }
+
+#define WABT_FEATURE(variable, flag, default_, help)              \
+  bool variable##_enabled() const { return variable##_enabled_; } \
+  void enable_##variable() { set_##variable##_enabled(true); }    \
+  void disable_##variable() { set_##variable##_enabled(false); }  \
+  void set_##variable##_enabled(bool value) {                     \
+    variable##_enabled_ = value;                                  \
+    UpdateDependencies();                                         \
+  }
+#include "src/feature.def"
+#undef WABT_FEATURE
+
+ private:
+  void UpdateDependencies();
+
+#define WABT_FEATURE(variable, flag, default_, help) \
+  bool variable##_enabled_ = default_;
+#include "src/feature.def"
+#undef WABT_FEATURE
+};
+
+}  // namespace wabt
+
+#endif  // WABT_FEATURE_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.cc
new file mode 100644 (file)
index 0000000..989453c
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * 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/filenames.h"
+
+namespace wabt {
+
+const char* kWasmExtension = ".wasm";
+
+const char* kWatExtension = ".wat";
+
+string_view StripExtension(string_view filename) {
+  return filename.substr(0, filename.find_last_of('.'));
+}
+
+string_view GetBasename(string_view filename) {
+  size_t last_slash = filename.find_last_of('/');
+  size_t last_backslash = filename.find_last_of('\\');
+  if (last_slash == string_view::npos && last_backslash == string_view::npos) {
+    return filename;
+  }
+
+  if (last_slash == string_view::npos) {
+    if (last_backslash == string_view::npos) {
+      return filename;
+    }
+    last_slash = last_backslash;
+  } else if (last_backslash != string_view::npos) {
+    last_slash = std::max(last_slash, last_backslash);
+  }
+
+  return filename.substr(last_slash + 1);
+}
+
+string_view GetExtension(string_view filename) {
+  size_t pos = filename.find_last_of('.');
+  if (pos == string_view::npos) {
+    return "";
+  }
+  return filename.substr(pos);
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/filenames.h
new file mode 100644 (file)
index 0000000..87529aa
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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_FILENAMES_H_
+#define WABT_FILENAMES_H_
+
+#include "src/common.h"
+
+namespace wabt {
+
+extern const char* kWasmExtension;
+extern const char* kWatExtension;
+
+// Return only the file extension, e.g.:
+//
+// "foo.txt", => ".txt"
+// "foo" => ""
+// "/foo/bar/foo.wasm" => ".wasm"
+string_view GetExtension(string_view filename);
+
+// Strip extension, e.g.:
+//
+// "foo", => "foo"
+// "foo.bar" => "foo"
+// "/path/to/foo.bar" => "/path/to/foo"
+// "\\path\\to\\foo.bar" => "\\path\\to\\foo"
+string_view StripExtension(string_view s);
+
+// Strip everything up to and including the last slash, e.g.:
+//
+// "/foo/bar/baz", => "baz"
+// "/usr/local/include/stdio.h", => "stdio.h"
+// "foo.bar", => "foo.bar"
+string_view GetBasename(string_view filename);
+
+}  // namespace wabt
+
+#endif /* WABT_FILENAMES_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.cc
new file mode 100644 (file)
index 0000000..03758e9
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ * 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/generate-names.h"
+
+#include <cassert>
+#include <cstdio>
+#include <string>
+#include <vector>
+
+#include "src/cast.h"
+#include "src/expr-visitor.h"
+#include "src/ir.h"
+
+namespace wabt {
+
+namespace {
+
+class NameGenerator : public ExprVisitor::DelegateNop {
+ public:
+  NameGenerator(NameOpts opts);
+
+  Result VisitModule(Module* module);
+
+  // Implementation of ExprVisitor::DelegateNop.
+  Result BeginBlockExpr(BlockExpr* expr) override;
+  Result BeginLoopExpr(LoopExpr* expr) override;
+  Result BeginIfExpr(IfExpr* expr) override;
+
+ private:
+  static bool HasName(const std::string& str);
+
+  // Generate a name with the given prefix, followed by the index and
+  // optionally a disambiguating number. If index == kInvalidIndex, the index
+  // is not appended.
+  void GenerateName(const char* prefix,
+                    Index index,
+                    unsigned disambiguator,
+                    std::string* out_str);
+
+  // Like GenerateName, but only generates a name if |out_str| is empty.
+  void MaybeGenerateName(const char* prefix,
+                         Index index,
+                         std::string* out_str);
+
+  // Generate a name via GenerateName and bind it to the given binding hash. If
+  // the name already exists, the name will be disambiguated until it can be
+  // added.
+  void GenerateAndBindName(BindingHash* bindings,
+                           const char* prefix,
+                           Index index,
+                           std::string* out_str);
+
+  // Like GenerateAndBindName, but only  generates a name if |out_str| is empty.
+  void MaybeGenerateAndBindName(BindingHash* bindings,
+                                const char* prefix,
+                                Index index,
+                                std::string* out_str);
+
+  // Like MaybeGenerateAndBindName but uses the name directly, without
+  // appending the index. If the name already exists, a disambiguating suffix
+  // is added.
+  void MaybeUseAndBindName(BindingHash* bindings,
+                           const char* name,
+                           Index index,
+                           std::string* out_str);
+
+  void GenerateAndBindLocalNames(Func* func);
+
+  template <typename T>
+  Result VisitAll(const std::vector<T*>& items,
+                  Result (NameGenerator::*func)(Index, T*));
+
+  Result VisitFunc(Index func_index, Func* func);
+  Result VisitGlobal(Index global_index, Global* global);
+  Result VisitType(Index func_type_index, TypeEntry* type);
+  Result VisitTable(Index table_index, Table* table);
+  Result VisitMemory(Index memory_index, Memory* memory);
+  Result VisitEvent(Index event_index, Event* event);
+  Result VisitDataSegment(Index data_segment_index, DataSegment* data_segment);
+  Result VisitElemSegment(Index elem_segment_index, ElemSegment* elem_segment);
+  Result VisitImport(Import* import);
+  Result VisitExport(Export* export_);
+
+  Module* module_ = nullptr;
+  ExprVisitor visitor_;
+  Index label_count_ = 0;
+
+  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;
+
+  NameOpts opts_;
+};
+
+NameGenerator::NameGenerator(NameOpts opts)
+  : visitor_(this), opts_(opts) {}
+
+// static
+bool NameGenerator::HasName(const std::string& str) {
+  return !str.empty();
+}
+
+void NameGenerator::GenerateName(const char* prefix,
+                                 Index index,
+                                 unsigned disambiguator,
+                                 std::string* str) {
+  *str = "$";
+  *str += prefix;
+  if (index != kInvalidIndex) {
+    if (opts_ & NameOpts::AlphaNames) {
+      // For params and locals, do not use a prefix char.
+      if (!strcmp(prefix, "p") || !strcmp(prefix, "l")) {
+        str->pop_back();
+      } else {
+        *str += '_';
+      }
+      *str += IndexToAlphaName(index);
+    } else {
+      *str += std::to_string(index);
+    }
+  }
+  if (disambiguator != 0) {
+    *str += '_' + std::to_string(disambiguator);
+  }
+}
+
+void NameGenerator::MaybeGenerateName(const char* prefix,
+                                      Index index,
+                                      std::string* str) {
+  if (!HasName(*str)) {
+    // There's no bindings hash, so the name can't be a duplicate. Therefore it
+    // doesn't need a disambiguating number.
+    GenerateName(prefix, index, 0, str);
+  }
+}
+
+void NameGenerator::GenerateAndBindName(BindingHash* bindings,
+                                        const char* prefix,
+                                        Index index,
+                                        std::string* str) {
+  unsigned disambiguator = 0;
+  while (true) {
+    GenerateName(prefix, index, disambiguator, str);
+    if (bindings->find(*str) == bindings->end()) {
+      bindings->emplace(*str, Binding(index));
+      break;
+    }
+
+    disambiguator++;
+  }
+}
+
+void NameGenerator::MaybeGenerateAndBindName(BindingHash* bindings,
+                                             const char* prefix,
+                                             Index index,
+                                             std::string* str) {
+  if (!HasName(*str)) {
+    GenerateAndBindName(bindings, prefix, index, str);
+  }
+}
+
+void NameGenerator::MaybeUseAndBindName(BindingHash* bindings,
+                                        const char* name,
+                                        Index index,
+                                        std::string* str) {
+  if (!HasName(*str)) {
+    unsigned disambiguator = 0;
+    while (true) {
+      GenerateName(name, kInvalidIndex, disambiguator, str);
+      if (bindings->find(*str) == bindings->end()) {
+        bindings->emplace(*str, Binding(index));
+        break;
+      }
+
+      disambiguator++;
+    }
+  }
+}
+
+void NameGenerator::GenerateAndBindLocalNames(Func* func) {
+  std::vector<std::string> index_to_name;
+  MakeTypeBindingReverseMapping(func->GetNumParamsAndLocals(), func->bindings,
+                                &index_to_name);
+  for (size_t i = 0; i < index_to_name.size(); ++i) {
+    const std::string& old_name = index_to_name[i];
+    if (!old_name.empty()) {
+      continue;
+    }
+
+    const char* prefix = i < func->GetNumParams() ? "p" : "l";
+    std::string new_name;
+    GenerateAndBindName(&func->bindings, prefix, i, &new_name);
+    index_to_name[i] = new_name;
+  }
+}
+
+Result NameGenerator::BeginBlockExpr(BlockExpr* expr) {
+  MaybeGenerateName("B", label_count_++, &expr->block.label);
+  return Result::Ok;
+}
+
+Result NameGenerator::BeginLoopExpr(LoopExpr* expr) {
+  MaybeGenerateName("L", label_count_++, &expr->block.label);
+  return Result::Ok;
+}
+
+Result NameGenerator::BeginIfExpr(IfExpr* expr) {
+  MaybeGenerateName("I", label_count_++, &expr->true_.label);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitFunc(Index func_index, Func* func) {
+  MaybeGenerateAndBindName(&module_->func_bindings, "f", func_index,
+                           &func->name);
+  GenerateAndBindLocalNames(func);
+
+  label_count_ = 0;
+  CHECK_RESULT(visitor_.VisitFunc(func));
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitGlobal(Index global_index, Global* global) {
+  MaybeGenerateAndBindName(&module_->global_bindings, "g", global_index,
+                           &global->name);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitType(Index type_index, TypeEntry* type) {
+  MaybeGenerateAndBindName(&module_->type_bindings, "t", type_index,
+                           &type->name);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitTable(Index table_index, Table* table) {
+  MaybeGenerateAndBindName(&module_->table_bindings, "T", table_index,
+                           &table->name);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitMemory(Index memory_index, Memory* memory) {
+  MaybeGenerateAndBindName(&module_->memory_bindings, "M", memory_index,
+                           &memory->name);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitEvent(Index event_index, Event* event) {
+  MaybeGenerateAndBindName(&module_->event_bindings, "e", event_index,
+                           &event->name);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitDataSegment(Index data_segment_index,
+                                       DataSegment* data_segment) {
+  MaybeGenerateAndBindName(&module_->data_segment_bindings, "d",
+                           data_segment_index, &data_segment->name);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitElemSegment(Index elem_segment_index,
+                                       ElemSegment* elem_segment) {
+  MaybeGenerateAndBindName(&module_->elem_segment_bindings, "e",
+                           elem_segment_index, &elem_segment->name);
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitImport(Import* import) {
+  BindingHash* bindings = nullptr;
+  std::string* name = nullptr;
+  Index index = kInvalidIndex;
+
+  switch (import->kind()) {
+    case ExternalKind::Func:
+      if (auto* func_import = cast<FuncImport>(import)) {
+        bindings = &module_->func_bindings;
+        name = &func_import->func.name;
+        index = num_func_imports_++;
+      }
+      break;
+
+    case ExternalKind::Table:
+      if (auto* table_import = cast<TableImport>(import)) {
+        bindings = &module_->table_bindings;
+        name = &table_import->table.name;
+        index = num_table_imports_++;
+      }
+      break;
+
+    case ExternalKind::Memory:
+      if (auto* memory_import = cast<MemoryImport>(import)) {
+        bindings = &module_->memory_bindings;
+        name = &memory_import->memory.name;
+        index = num_memory_imports_++;
+      }
+      break;
+
+    case ExternalKind::Global:
+      if (auto* global_import = cast<GlobalImport>(import)) {
+        bindings = &module_->global_bindings;
+        name = &global_import->global.name;
+        index = num_global_imports_++;
+      }
+      break;
+
+    case ExternalKind::Event:
+      if (auto* event_import = cast<EventImport>(import)) {
+        bindings = &module_->event_bindings;
+        name = &event_import->event.name;
+        index = num_event_imports_++;
+      }
+      break;
+  }
+
+  if (bindings && name) {
+    assert(index != kInvalidIndex);
+    std::string new_name = import->module_name + '.' + import->field_name;
+    MaybeUseAndBindName(bindings, new_name.c_str(), index, name);
+  }
+
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitExport(Export* export_) {
+  BindingHash* bindings = nullptr;
+  std::string* name = nullptr;
+  Index index = kInvalidIndex;
+
+  switch (export_->kind) {
+    case ExternalKind::Func:
+      if (Func* func = module_->GetFunc(export_->var)) {
+        index = module_->GetFuncIndex(export_->var);
+        bindings = &module_->func_bindings;
+        name = &func->name;
+      }
+      break;
+
+    case ExternalKind::Table:
+      if (Table* table = module_->GetTable(export_->var)) {
+        index = module_->GetTableIndex(export_->var);
+        bindings = &module_->table_bindings;
+        name = &table->name;
+      }
+      break;
+
+    case ExternalKind::Memory:
+      if (Memory* memory = module_->GetMemory(export_->var)) {
+        index = module_->GetMemoryIndex(export_->var);
+        bindings = &module_->memory_bindings;
+        name = &memory->name;
+      }
+      break;
+
+    case ExternalKind::Global:
+      if (Global* global = module_->GetGlobal(export_->var)) {
+        index = module_->GetGlobalIndex(export_->var);
+        bindings = &module_->global_bindings;
+        name = &global->name;
+      }
+      break;
+
+    case ExternalKind::Event:
+      if (Event* event = module_->GetEvent(export_->var)) {
+        index = module_->GetEventIndex(export_->var);
+        bindings = &module_->event_bindings;
+        name = &event->name;
+      }
+      break;
+  }
+
+  if (bindings && name) {
+    MaybeUseAndBindName(bindings, export_->name.c_str(), index, name);
+  }
+
+  return Result::Ok;
+}
+
+template <typename T>
+Result NameGenerator::VisitAll(const std::vector<T*>& items,
+                               Result (NameGenerator::*func)(Index, T*)) {
+  for (Index i = 0; i < items.size(); ++i) {
+    CHECK_RESULT((this->*func)(i, items[i]));
+  }
+  return Result::Ok;
+}
+
+Result NameGenerator::VisitModule(Module* module) {
+  module_ = module;
+  // Visit imports and exports first to give better names, derived from the
+  // import/export name.
+  for (auto* import : module->imports) {
+    CHECK_RESULT(VisitImport(import));
+  }
+  for (auto* export_ : module->exports) {
+    CHECK_RESULT(VisitExport(export_));
+  }
+
+  VisitAll(module->globals, &NameGenerator::VisitGlobal);
+  VisitAll(module->types, &NameGenerator::VisitType);
+  VisitAll(module->funcs, &NameGenerator::VisitFunc);
+  VisitAll(module->tables, &NameGenerator::VisitTable);
+  VisitAll(module->memories, &NameGenerator::VisitMemory);
+  VisitAll(module->events, &NameGenerator::VisitEvent);
+  VisitAll(module->data_segments, &NameGenerator::VisitDataSegment);
+  VisitAll(module->elem_segments, &NameGenerator::VisitElemSegment);
+  module_ = nullptr;
+  return Result::Ok;
+}
+
+}  // end anonymous namespace
+
+Result GenerateNames(Module* module, NameOpts opts) {
+  NameGenerator generator(opts);
+  return generator.VisitModule(module);
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/generate-names.h
new file mode 100644 (file)
index 0000000..9cd926e
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * 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_GENERATE_NAMES_H_
+#define WABT_GENERATE_NAMES_H_
+
+#include "src/common.h"
+
+namespace wabt {
+
+struct Module;
+
+enum NameOpts {
+  None = 0,
+  AlphaNames = 1 << 0,
+};
+
+Result GenerateNames(struct Module*, NameOpts opts = NameOpts::None);
+
+inline std::string IndexToAlphaName(Index index) {
+  std::string s;
+  do {
+    // For multiple chars, put most frequently changing char first.
+    s += 'a' + (index % 26);
+    index /= 26;
+    // Continue remaining sequence with 'a' rather than 'b'.
+  } while (index--);
+  return s;
+}
+
+}  // namespace wabt
+
+#endif /* WABT_GENERATE_NAMES_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.cc
new file mode 100644 (file)
index 0000000..efb8427
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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/hash-util.h"
+
+#include "config.h"
+
+namespace wabt {
+
+// Hash combiner from:
+// http://stackoverflow.com/questions/4948780/magic-number-in-boosthash-combine
+
+hash_code HashCombine(hash_code seed, hash_code y) {
+#if SIZEOF_SIZE_T == 4
+  constexpr hash_code magic = 0x9e3779b9;
+#elif SIZEOF_SIZE_T == 8
+  constexpr hash_code magic = 0x9e3779b97f4a7c16;
+#else
+#error "weird sizeof size_t"
+#endif
+  seed ^= y + magic + (seed << 6) + (seed >> 2);
+  return seed;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/hash-util.h
new file mode 100644 (file)
index 0000000..0a135d5
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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_HASH_UTIL_H_
+#define WABT_HASH_UTIL_H_
+
+#include <cstdlib>
+#include <functional>
+
+namespace wabt {
+
+typedef std::size_t hash_code;
+
+inline hash_code HashCombine() {
+  return 0;
+}
+inline hash_code HashCombine(hash_code seed) {
+  return seed;
+}
+hash_code HashCombine(hash_code x, hash_code y);
+
+template <typename T, typename... U>
+inline hash_code HashCombine(const T& first, const U&... rest) {
+  return HashCombine(HashCombine(rest...), std::hash<T>()(first));
+}
+
+template <typename It>
+inline hash_code HashRange(It first, It last) {
+  hash_code result = 0;
+  for (auto iter = first; iter != last; ++iter) {
+    result = HashCombine(result, *iter);
+  }
+  return result;
+}
+
+}  // namespace wabt
+
+#endif  // WABT_HASH_UTIL_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.cc
new file mode 100644 (file)
index 0000000..0cd9c52
--- /dev/null
@@ -0,0 +1,1367 @@
+/*
+ * 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/interp/binary-reader-interp.h"
+
+#include <map>
+#include <set>
+
+#include "src/binary-reader-nop.h"
+#include "src/feature.h"
+#include "src/interp/interp.h"
+#include "src/shared-validator.h"
+#include "src/stream.h"
+
+namespace wabt {
+namespace interp {
+
+namespace {
+
+ValueTypes ToInterp(Index count, Type* types) {
+  return ValueTypes(&types[0], &types[count]);
+}
+
+Mutability ToMutability(bool mut) {
+  return mut ? Mutability::Var : Mutability::Const;
+}
+
+SegmentMode ToSegmentMode(uint8_t flags) {
+  if ((flags & SegDeclared) == SegDeclared) {
+    return SegmentMode::Declared;
+  } else if ((flags & SegPassive) == SegPassive) {
+    return SegmentMode::Passive;
+  } else {
+    return SegmentMode::Active;
+  }
+}
+
+struct Label {
+  Istream::Offset offset;
+  Istream::Offset fixup_offset;
+};
+
+struct FixupMap {
+  using Offset = Istream::Offset;
+  using Fixups = std::vector<Offset>;
+
+  void Clear();
+  void Append(Index, Offset);
+  void Resolve(Istream&, Index);
+
+  std::map<Index, Fixups> map;
+};
+
+class BinaryReaderInterp : public BinaryReaderNop {
+ public:
+  BinaryReaderInterp(ModuleDesc* module,
+                     Errors* errors,
+                     const Features& features);
+
+  ValueType GetType(InitExpr);
+
+  // Implement BinaryReader.
+  bool OnError(const Error&) override;
+
+  Result EndModule() override;
+
+  Result OnTypeCount(Index count) override;
+  Result OnFuncType(Index index,
+                    Index param_count,
+                    Type* param_types,
+                    Index result_count,
+                    Type* result_types) 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 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 EndGlobalInitExpr(Index index) override;
+
+  Result OnExport(Index index,
+                  ExternalKind kind,
+                  Index item_index,
+                  string_view name) override;
+
+  Result OnStartFunction(Index func_index) 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 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 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 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 OnMemoryGrowExpr() override;
+  Result OnMemoryFillExpr() override;
+  Result OnMemoryInitExpr(Index segment_index) override;
+  Result OnMemorySizeExpr() override;
+  Result OnRefFuncExpr(Index func_index) override;
+  Result OnRefNullExpr(Type type) override;
+  Result OnRefIsNullExpr() override;
+  Result OnNopExpr() override;
+  Result OnReturnExpr() override;
+  Result OnSelectExpr(Index result_count, Type* result_types) override;
+  Result OnStoreExpr(Opcode opcode,
+                     Address alignment_log2,
+                     Address offset) override;
+  Result OnUnaryExpr(Opcode opcode) override;
+  Result OnTableCopyExpr(Index dst_index, Index src_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 OnElemDropExpr(Index segment_index) override;
+  Result OnTableInitExpr(Index segment_index, Index table_index) override;
+  Result OnTernaryExpr(Opcode opcode) override;
+  Result OnUnreachableExpr() 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 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 OnDataCount(Index count) override;
+  Result EndDataSegmentInitExpr(Index index) override;
+  Result BeginDataSegment(Index index,
+                          Index memory_index,
+                          uint8_t flags) override;
+  Result OnDataSegmentData(Index index,
+                           const void* data,
+                           Address size) 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:
+  Label* GetLabel(Index depth);
+  Label* TopLabel();
+  void PushLabel(Istream::Offset offset = Istream::kInvalidOffset,
+                 Istream::Offset fixup_offset = Istream::kInvalidOffset);
+  void PopLabel();
+
+  void PrintError(const char* format, ...);
+
+  Result GetDropCount(Index keep_count,
+                      size_t type_stack_limit,
+                      Index* out_drop_count);
+  Result GetBrDropKeepCount(Index depth,
+                            Index* out_drop_count,
+                            Index* out_keep_count);
+  Result GetReturnDropKeepCount(Index* out_drop_count, Index* out_keep_count);
+  Result GetReturnCallDropKeepCount(const FuncType&,
+                                    Index keep_extra,
+                                    Index* out_drop_count,
+                                    Index* out_keep_count);
+  void EmitBr(Index depth, Index drop_count, Index keep_count);
+  void FixupTopLabel();
+  u32 GetFuncOffset(Index func_index);
+
+  Index TranslateLocalIndex(Index local_index);
+
+  Index num_func_imports() const;
+
+  Errors* errors_ = nullptr;
+  ModuleDesc& module_;
+  Istream& istream_;
+
+  SharedValidator validator_;
+
+  FuncDesc* func_;
+  std::vector<Label> label_stack_;
+  FixupMap depth_fixups_;
+  FixupMap func_fixups_;
+
+  InitExpr init_expr_;
+  u32 local_decl_count_;
+  u32 local_count_;
+
+  std::vector<FuncType> func_types_;      // Includes imported and defined.
+  std::vector<TableType> table_types_;    // Includes imported and defined.
+  std::vector<MemoryType> memory_types_;  // Includes imported and defined.
+  std::vector<GlobalType> global_types_;  // Includes imported and defined.
+  std::vector<EventType> event_types_;    // Includes imported and defined.
+
+  static const Index kMemoryIndex0 = 0;
+
+  // TODO: Use this in all locations below, for now. In the future we'll want
+  // to use the real locations.
+  static const Location loc;
+};
+
+// static
+const Location BinaryReaderInterp::loc{kInvalidOffset};
+
+void FixupMap::Clear() {
+  map.clear();
+}
+
+void FixupMap::Append(Index index, Offset offset) {
+  map[index].push_back(offset);
+}
+
+void FixupMap::Resolve(Istream& istream, Index index) {
+  auto iter = map.find(index);
+  if (iter == map.end()) {
+    return;
+  }
+  for (Offset offset : iter->second) {
+    istream.ResolveFixupU32(offset);
+  }
+  map.erase(iter);
+}
+
+BinaryReaderInterp::BinaryReaderInterp(ModuleDesc* module,
+                                       Errors* errors,
+                                       const Features& features)
+    : errors_(errors),
+      module_(*module),
+      istream_(module->istream),
+      validator_(errors, ValidateOptions(features)) {}
+
+Label* BinaryReaderInterp::GetLabel(Index depth) {
+  assert(depth < label_stack_.size());
+  return &label_stack_[label_stack_.size() - depth - 1];
+}
+
+Label* BinaryReaderInterp::TopLabel() {
+  return GetLabel(0);
+}
+
+void WABT_PRINTF_FORMAT(2, 3) BinaryReaderInterp::PrintError(const char* format,
+                                                             ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  errors_->emplace_back(ErrorLevel::Error, Location(kInvalidOffset), buffer);
+}
+
+Result BinaryReaderInterp::GetDropCount(Index keep_count,
+                                        size_t type_stack_limit,
+                                        Index* out_drop_count) {
+  assert(validator_.type_stack_size() >= type_stack_limit);
+  Index type_stack_count = validator_.type_stack_size() - type_stack_limit;
+  // The keep_count may be larger than the type_stack_count if the typechecker
+  // is currently unreachable. In that case, it doesn't matter what value we
+  // drop, but 0 is a reasonable choice.
+  *out_drop_count =
+      type_stack_count >= keep_count ? type_stack_count - keep_count : 0;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::GetBrDropKeepCount(Index depth,
+                                              Index* out_drop_count,
+                                              Index* out_keep_count) {
+  SharedValidator::Label* label;
+  CHECK_RESULT(validator_.GetLabel(depth, &label));
+  Index keep_count = label->br_types().size();
+  CHECK_RESULT(
+      GetDropCount(keep_count, label->type_stack_limit, out_drop_count));
+  *out_keep_count = keep_count;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::GetReturnDropKeepCount(Index* out_drop_count,
+                                                  Index* out_keep_count) {
+  CHECK_RESULT(GetBrDropKeepCount(label_stack_.size() - 1, out_drop_count,
+                                  out_keep_count));
+  *out_drop_count += validator_.GetLocalCount();
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::GetReturnCallDropKeepCount(const FuncType& func_type,
+                                                      Index keep_extra,
+                                                      Index* out_drop_count,
+                                                      Index* out_keep_count) {
+  Index keep_count = static_cast<Index>(func_type.params.size()) + keep_extra;
+  CHECK_RESULT(GetDropCount(keep_count, 0, out_drop_count));
+  *out_drop_count += validator_.GetLocalCount();
+  *out_keep_count = keep_count;
+  return Result::Ok;
+}
+
+void BinaryReaderInterp::EmitBr(Index depth,
+                                Index drop_count,
+                                Index keep_count) {
+  istream_.EmitDropKeep(drop_count, keep_count);
+  Istream::Offset offset = GetLabel(depth)->offset;
+  istream_.Emit(Opcode::Br);
+  if (offset == Istream::kInvalidOffset) {
+    // depth_fixups_ stores the depth counting up from zero, where zero is the
+    // top-level function scope.
+    depth_fixups_.Append(label_stack_.size() - 1 - depth, istream_.end());
+  }
+  istream_.Emit(offset);
+}
+
+void BinaryReaderInterp::FixupTopLabel() {
+  depth_fixups_.Resolve(istream_, label_stack_.size() - 1);
+}
+
+u32 BinaryReaderInterp::GetFuncOffset(Index func_index) {
+  assert(func_index >= num_func_imports());
+  FuncDesc& func = module_.funcs[func_index - num_func_imports()];
+  if (func.code_offset == Istream::kInvalidOffset) {
+    func_fixups_.Append(func_index, istream_.end());
+  }
+  return func.code_offset;
+}
+
+bool BinaryReaderInterp::OnError(const Error& error) {
+  errors_->push_back(error);
+  return true;
+}
+
+Result BinaryReaderInterp::EndModule() {
+  CHECK_RESULT(validator_.EndModule());
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTypeCount(Index count) {
+  module_.func_types.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnFuncType(Index index,
+                                      Index param_count,
+                                      Type* param_types,
+                                      Index result_count,
+                                      Type* result_types) {
+  CHECK_RESULT(validator_.OnFuncType(loc, param_count, param_types,
+                                     result_count, result_types));
+  module_.func_types.push_back(FuncType(ToInterp(param_count, param_types),
+                                        ToInterp(result_count, result_types)));
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnImportFunc(Index import_index,
+                                        string_view module_name,
+                                        string_view field_name,
+                                        Index func_index,
+                                        Index sig_index) {
+  CHECK_RESULT(validator_.OnFunction(loc, Var(sig_index)));
+  FuncType& func_type = module_.func_types[sig_index];
+  module_.imports.push_back(ImportDesc{ImportType(
+      module_name.to_string(), field_name.to_string(), func_type.Clone())});
+  func_types_.push_back(func_type);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnImportTable(Index import_index,
+                                         string_view module_name,
+                                         string_view field_name,
+                                         Index table_index,
+                                         Type elem_type,
+                                         const Limits* elem_limits) {
+  CHECK_RESULT(validator_.OnTable(loc, elem_type, *elem_limits));
+  TableType table_type{elem_type, *elem_limits};
+  module_.imports.push_back(ImportDesc{ImportType(
+      module_name.to_string(), field_name.to_string(), table_type.Clone())});
+  table_types_.push_back(table_type);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnImportMemory(Index import_index,
+                                          string_view module_name,
+                                          string_view field_name,
+                                          Index memory_index,
+                                          const Limits* page_limits) {
+  CHECK_RESULT(validator_.OnMemory(loc, *page_limits));
+  MemoryType memory_type{*page_limits};
+  module_.imports.push_back(ImportDesc{ImportType(
+      module_name.to_string(), field_name.to_string(), memory_type.Clone())});
+  memory_types_.push_back(memory_type);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnImportGlobal(Index import_index,
+                                          string_view module_name,
+                                          string_view field_name,
+                                          Index global_index,
+                                          Type type,
+                                          bool mutable_) {
+  CHECK_RESULT(validator_.OnGlobalImport(loc, type, mutable_));
+  GlobalType global_type{type, ToMutability(mutable_)};
+  module_.imports.push_back(ImportDesc{ImportType(
+      module_name.to_string(), field_name.to_string(), global_type.Clone())});
+  global_types_.push_back(global_type);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnFunctionCount(Index count) {
+  module_.funcs.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnFunction(Index index, Index sig_index) {
+  CHECK_RESULT(validator_.OnFunction(loc, Var(sig_index)));
+  FuncType& func_type = module_.func_types[sig_index];
+  module_.funcs.push_back(FuncDesc{func_type, {}, 0});
+  func_types_.push_back(func_type);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableCount(Index count) {
+  module_.tables.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTable(Index index,
+                                   Type elem_type,
+                                   const Limits* elem_limits) {
+  CHECK_RESULT(validator_.OnTable(loc, elem_type, *elem_limits));
+  TableType table_type{elem_type, *elem_limits};
+  module_.tables.push_back(TableDesc{table_type});
+  table_types_.push_back(table_type);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnMemoryCount(Index count) {
+  module_.memories.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnMemory(Index index, const Limits* limits) {
+  CHECK_RESULT(validator_.OnMemory(loc, *limits));
+  MemoryType memory_type{*limits};
+  module_.memories.push_back(MemoryDesc{memory_type});
+  memory_types_.push_back(memory_type);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnGlobalCount(Index count) {
+  module_.globals.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::BeginGlobal(Index index, Type type, bool mutable_) {
+  CHECK_RESULT(validator_.OnGlobal(loc, type, mutable_));
+  GlobalType global_type{type, ToMutability(mutable_)};
+  module_.globals.push_back(GlobalDesc{global_type, InitExpr{}});
+  global_types_.push_back(global_type);
+  init_expr_.kind = InitExprKind::None;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::EndGlobalInitExpr(Index index) {
+  switch (init_expr_.kind) {
+    case InitExprKind::I32:
+      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::I32));
+      break;
+
+    case InitExprKind::I64:
+      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::I64));
+      break;
+
+    case InitExprKind::F32:
+      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::F32));
+      break;
+
+    case InitExprKind::F64:
+      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::F64));
+      break;
+
+    case InitExprKind::V128:
+      CHECK_RESULT(validator_.OnGlobalInitExpr_Const(loc, ValueType::V128));
+      break;
+
+    case InitExprKind::GlobalGet:
+      CHECK_RESULT(
+          validator_.OnGlobalInitExpr_GlobalGet(loc, Var(init_expr_.index_)));
+      break;
+
+    case InitExprKind::RefNull:
+      CHECK_RESULT(validator_.OnGlobalInitExpr_RefNull(loc, init_expr_.type_));
+      break;
+
+    case InitExprKind::RefFunc:
+      CHECK_RESULT(
+          validator_.OnGlobalInitExpr_RefFunc(loc, Var(init_expr_.index_)));
+      break;
+
+    default:
+      CHECK_RESULT(validator_.OnGlobalInitExpr_Other(loc));
+      break;
+  }
+
+  GlobalDesc& global = module_.globals.back();
+  global.init = init_expr_;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprF32ConstExpr(Index index,
+                                                  uint32_t value_bits) {
+  init_expr_.kind = InitExprKind::F32;
+  init_expr_.f32_ = Bitcast<f32>(value_bits);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprF64ConstExpr(Index index,
+                                                  uint64_t value_bits) {
+  init_expr_.kind = InitExprKind::F64;
+  init_expr_.f64_ = Bitcast<f64>(value_bits);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprV128ConstExpr(Index index,
+                                                   v128 value_bits) {
+  init_expr_.kind = InitExprKind::V128;
+  init_expr_.v128_ = Bitcast<v128>(value_bits);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprGlobalGetExpr(Index index,
+                                                   Index global_index) {
+  init_expr_.kind = InitExprKind::GlobalGet;
+  init_expr_.index_ = global_index;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprI32ConstExpr(Index index, uint32_t value) {
+  init_expr_.kind = InitExprKind::I32;
+  init_expr_.i32_ = value;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprI64ConstExpr(Index index, uint64_t value) {
+  init_expr_.kind = InitExprKind::I64;
+  init_expr_.i64_ = value;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprRefNull(Index index, Type type) {
+  init_expr_.kind = InitExprKind::RefNull;
+  init_expr_.type_ = type;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnInitExprRefFunc(Index index, Index func_index) {
+  init_expr_.kind = InitExprKind::RefFunc;
+  init_expr_.index_ = func_index;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnExport(Index index,
+                                    ExternalKind kind,
+                                    Index item_index,
+                                    string_view name) {
+  CHECK_RESULT(validator_.OnExport(loc, kind, Var(item_index), name));
+
+  std::unique_ptr<ExternType> type;
+  switch (kind) {
+    case ExternalKind::Func:   type = func_types_[item_index].Clone(); break;
+    case ExternalKind::Table:  type = table_types_[item_index].Clone(); break;
+    case ExternalKind::Memory: type = memory_types_[item_index].Clone(); break;
+    case ExternalKind::Global: type = global_types_[item_index].Clone(); break;
+    case ExternalKind::Event:  type = event_types_[item_index].Clone(); break;
+  }
+  module_.exports.push_back(
+      ExportDesc{ExportType(name.to_string(), std::move(type)), item_index});
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnStartFunction(Index func_index) {
+  CHECK_RESULT(validator_.OnStart(loc, Var(func_index)));
+  module_.starts.push_back(StartDesc{func_index});
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnElemSegmentCount(Index count) {
+  module_.elems.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::BeginElemSegment(Index index,
+                                            Index table_index,
+                                            uint8_t flags) {
+  auto mode = ToSegmentMode(flags);
+  CHECK_RESULT(validator_.OnElemSegment(loc, Var(table_index), mode));
+
+  ElemDesc desc;
+  desc.type = ValueType::Void;  // Initialized later in OnElemSegmentElemType.
+  desc.mode = mode;
+  desc.table_index = table_index;
+  module_.elems.push_back(desc);
+  init_expr_.kind = InitExprKind::None;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::EndElemSegmentInitExpr(Index index) {
+  switch (init_expr_.kind) {
+    case InitExprKind::I32:
+      CHECK_RESULT(validator_.OnElemSegmentInitExpr_Const(loc, ValueType::I32));
+      break;
+
+    case InitExprKind::GlobalGet:
+      CHECK_RESULT(validator_.OnElemSegmentInitExpr_GlobalGet(
+          loc, Var(init_expr_.index_)));
+      break;
+
+    default:
+      CHECK_RESULT(validator_.OnElemSegmentInitExpr_Other(loc));
+      break;
+  }
+
+  ElemDesc& elem = module_.elems.back();
+  elem.offset = init_expr_;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnElemSegmentElemType(Index index, Type elem_type) {
+  validator_.OnElemSegmentElemType(elem_type);
+  ElemDesc& elem = module_.elems.back();
+  elem.type = elem_type;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnElemSegmentElemExprCount(Index index,
+                                                      Index count) {
+  ElemDesc& elem = module_.elems.back();
+  elem.elements.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnElemSegmentElemExpr_RefNull(Index segment_index,
+                                                         Type type) {
+  CHECK_RESULT(validator_.OnElemSegmentElemExpr_RefNull(loc, type));
+  ElemDesc& elem = module_.elems.back();
+  elem.elements.push_back(ElemExpr{ElemKind::RefNull, 0});
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnElemSegmentElemExpr_RefFunc(Index segment_index,
+                                                         Index func_index) {
+  CHECK_RESULT(validator_.OnElemSegmentElemExpr_RefFunc(loc, Var(func_index)));
+  ElemDesc& elem = module_.elems.back();
+  elem.elements.push_back(ElemExpr{ElemKind::RefFunc, func_index});
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnDataCount(Index count) {
+  validator_.OnDataCount(count);
+  module_.datas.reserve(count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::EndDataSegmentInitExpr(Index index) {
+  switch (init_expr_.kind) {
+    case InitExprKind::I32:
+      CHECK_RESULT(validator_.OnDataSegmentInitExpr_Const(loc, ValueType::I32));
+      break;
+
+    case InitExprKind::GlobalGet:
+      CHECK_RESULT(validator_.OnDataSegmentInitExpr_GlobalGet(
+          loc, Var(init_expr_.index_)));
+      break;
+
+    default:
+      CHECK_RESULT(validator_.OnDataSegmentInitExpr_Other(loc));
+      break;
+  }
+
+  DataDesc& data = module_.datas.back();
+  data.offset = init_expr_;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::BeginDataSegment(Index index,
+                                            Index memory_index,
+                                            uint8_t flags) {
+  auto mode = ToSegmentMode(flags);
+  CHECK_RESULT(validator_.OnDataSegment(loc, Var(memory_index), mode));
+
+  DataDesc desc;
+  desc.mode = mode;
+  desc.memory_index = memory_index;
+  module_.datas.push_back(desc);
+  init_expr_.kind = InitExprKind::None;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnDataSegmentData(Index index,
+                                             const void* src_data,
+                                             Address size) {
+  DataDesc& dst_data = module_.datas.back();
+  if (size > 0) {
+    dst_data.data.resize(size);
+    memcpy(dst_data.data.data(), src_data, size);
+  }
+  return Result::Ok;
+}
+
+void BinaryReaderInterp::PushLabel(Istream::Offset offset,
+                                   Istream::Offset fixup_offset) {
+  label_stack_.push_back(Label{offset, fixup_offset});
+}
+
+void BinaryReaderInterp::PopLabel() {
+  label_stack_.pop_back();
+}
+
+Result BinaryReaderInterp::BeginFunctionBody(Index index, Offset size) {
+  Index defined_index = index - num_func_imports();
+  func_ = &module_.funcs[defined_index];
+  func_->code_offset = istream_.end();
+
+  depth_fixups_.Clear();
+  label_stack_.clear();
+
+  func_fixups_.Resolve(istream_, defined_index);
+
+  CHECK_RESULT(validator_.BeginFunctionBody(loc, index));
+
+  // Push implicit func label (equivalent to return).
+  PushLabel();
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::EndFunctionBody(Index index) {
+  FixupTopLabel();
+  Index drop_count, keep_count;
+  CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count));
+  CHECK_RESULT(validator_.EndFunctionBody(loc));
+  istream_.EmitDropKeep(drop_count, keep_count);
+  istream_.Emit(Opcode::Return);
+  PopLabel();
+  func_ = nullptr;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnLocalDeclCount(Index count) {
+  local_decl_count_ = count;
+  local_count_ = 0;
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnLocalDecl(Index decl_index,
+                                       Index count,
+                                       Type type) {
+  CHECK_RESULT(validator_.OnLocalDecl(loc, count, type));
+
+  local_count_ += count;
+  func_->locals.push_back(LocalDesc{type, count, local_count_});
+
+  if (decl_index == local_decl_count_ - 1) {
+    istream_.Emit(Opcode::InterpAlloca, local_count_);
+  }
+  return Result::Ok;
+}
+
+Index BinaryReaderInterp::num_func_imports() const {
+  return func_types_.size() - module_.funcs.size();
+}
+
+Result BinaryReaderInterp::OnOpcode(Opcode opcode) {
+  if (func_ == nullptr || label_stack_.empty()) {
+    PrintError("Unexpected instruction after end of function");
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnUnaryExpr(Opcode opcode) {
+  CHECK_RESULT(validator_.OnUnary(loc, opcode));
+  istream_.Emit(opcode);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTernaryExpr(Opcode opcode) {
+  CHECK_RESULT(validator_.OnTernary(loc, opcode));
+  istream_.Emit(opcode);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnSimdLaneOpExpr(Opcode opcode, uint64_t value) {
+  CHECK_RESULT(validator_.OnSimdLaneOp(loc, opcode, value));
+  istream_.Emit(opcode, static_cast<u8>(value));
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnSimdShuffleOpExpr(Opcode opcode, v128 value) {
+  CHECK_RESULT(validator_.OnSimdShuffleOp(loc, opcode, value));
+  istream_.Emit(opcode, value);
+  return Result::Ok;
+}
+
+uint32_t GetAlignment(Address alignment_log2) {
+  return alignment_log2 < 32 ? 1 << alignment_log2 : ~0u;
+}
+
+Result BinaryReaderInterp::OnLoadSplatExpr(Opcode opcode,
+                                           Address align_log2,
+                                           Address offset) {
+  CHECK_RESULT(validator_.OnLoadSplat(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnAtomicLoadExpr(Opcode opcode,
+                                            Address align_log2,
+                                            Address offset) {
+  CHECK_RESULT(validator_.OnAtomicLoad(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnAtomicStoreExpr(Opcode opcode,
+                                             Address align_log2,
+                                             Address offset) {
+  CHECK_RESULT(validator_.OnAtomicStore(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnAtomicRmwExpr(Opcode opcode,
+                                           Address align_log2,
+                                           Address offset) {
+  CHECK_RESULT(validator_.OnAtomicRmw(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnAtomicRmwCmpxchgExpr(Opcode opcode,
+                                                  Address align_log2,
+                                                  Address offset) {
+  CHECK_RESULT(
+      validator_.OnAtomicRmwCmpxchg(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnBinaryExpr(Opcode opcode) {
+  CHECK_RESULT(validator_.OnBinary(loc, opcode));
+  istream_.Emit(opcode);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnBlockExpr(Type sig_type) {
+  CHECK_RESULT(validator_.OnBlock(loc, sig_type));
+  PushLabel();
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnLoopExpr(Type sig_type) {
+  CHECK_RESULT(validator_.OnLoop(loc, sig_type));
+  PushLabel(istream_.end());
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnIfExpr(Type sig_type) {
+  CHECK_RESULT(validator_.OnIf(loc, sig_type));
+  istream_.Emit(Opcode::InterpBrUnless);
+  auto fixup = istream_.EmitFixupU32();
+  PushLabel(Istream::kInvalidOffset, fixup);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnElseExpr() {
+  CHECK_RESULT(validator_.OnElse(loc));
+  Label* label = TopLabel();
+  Istream::Offset fixup_cond_offset = label->fixup_offset;
+  istream_.Emit(Opcode::Br);
+  label->fixup_offset = istream_.EmitFixupU32();
+  istream_.ResolveFixupU32(fixup_cond_offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnEndExpr() {
+  SharedValidator::Label* label;
+  CHECK_RESULT(validator_.GetLabel(0, &label));
+  LabelType label_type = label->label_type;
+  CHECK_RESULT(validator_.OnEnd(loc));
+  if (label_type == LabelType::If || label_type == LabelType::Else) {
+    istream_.ResolveFixupU32(TopLabel()->fixup_offset);
+  }
+  FixupTopLabel();
+  PopLabel();
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnBrExpr(Index depth) {
+  Index drop_count, keep_count;
+  CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count));
+  CHECK_RESULT(validator_.OnBr(loc, Var(depth)));
+  EmitBr(depth, drop_count, keep_count);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnBrIfExpr(Index depth) {
+  Index drop_count, keep_count;
+  CHECK_RESULT(validator_.OnBrIf(loc, Var(depth)));
+  CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count));
+  // Flip the br_if so if <cond> is true it can drop values from the stack.
+  istream_.Emit(Opcode::InterpBrUnless);
+  auto fixup = istream_.EmitFixupU32();
+  EmitBr(depth, drop_count, keep_count);
+  istream_.ResolveFixupU32(fixup);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnBrTableExpr(Index num_targets,
+                                         Index* target_depths,
+                                         Index default_target_depth) {
+  CHECK_RESULT(validator_.BeginBrTable(loc));
+  Index drop_count, keep_count;
+  istream_.Emit(Opcode::BrTable, num_targets);
+
+  for (Index i = 0; i < num_targets; ++i) {
+    Index depth = target_depths[i];
+    CHECK_RESULT(validator_.OnBrTableTarget(loc, Var(depth)));
+    CHECK_RESULT(GetBrDropKeepCount(depth, &drop_count, &keep_count));
+    // Emit DropKeep directly (instead of using EmitDropKeep) so the
+    // instruction has a fixed size.
+    istream_.Emit(Opcode::InterpDropKeep, drop_count, keep_count);
+    EmitBr(depth, 0, 0);
+  }
+  CHECK_RESULT(validator_.OnBrTableTarget(loc, Var(default_target_depth)));
+  CHECK_RESULT(
+      GetBrDropKeepCount(default_target_depth, &drop_count, &keep_count));
+  // The default case doesn't need a fixed size, since it is never jumped over.
+  istream_.EmitDropKeep(drop_count, keep_count);
+  EmitBr(default_target_depth, 0, 0);
+
+  CHECK_RESULT(validator_.EndBrTable(loc));
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnCallExpr(Index func_index) {
+  CHECK_RESULT(validator_.OnCall(loc, Var(func_index)));
+
+  if (func_index >= num_func_imports()) {
+    istream_.Emit(Opcode::Call, func_index);
+  } else {
+    istream_.Emit(Opcode::InterpCallImport, func_index);
+  }
+
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnCallIndirectExpr(Index sig_index,
+                                              Index table_index) {
+  CHECK_RESULT(
+      validator_.OnCallIndirect(loc, Var(sig_index), Var(table_index)));
+  istream_.Emit(Opcode::CallIndirect, table_index, sig_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnReturnCallExpr(Index func_index) {
+  FuncType& func_type = func_types_[func_index];
+
+  Index drop_count, keep_count;
+  CHECK_RESULT(
+      GetReturnCallDropKeepCount(func_type, 0, &drop_count, &keep_count));
+  // The validator must be run after we get the drop/keep counts, since it
+  // will change the type stack.
+  CHECK_RESULT(validator_.OnReturnCall(loc, Var(func_index)));
+  istream_.EmitDropKeep(drop_count, keep_count);
+
+  if (func_index >= num_func_imports()) {
+    istream_.Emit(Opcode::Br, GetFuncOffset(func_index));
+  } else {
+    istream_.Emit(Opcode::InterpCallImport, func_index);
+    istream_.Emit(Opcode::Return);
+  }
+
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnReturnCallIndirectExpr(Index sig_index,
+                                                    Index table_index) {
+  FuncType& func_type = module_.func_types[sig_index];
+
+  Index drop_count, keep_count;
+  // +1 to include the index of the function.
+  CHECK_RESULT(
+      GetReturnCallDropKeepCount(func_type, +1, &drop_count, &keep_count));
+  // The validator must be run after we get the drop/keep counts, since it
+  // changes the type stack.
+  CHECK_RESULT(
+      validator_.OnReturnCallIndirect(loc, Var(sig_index), Var(table_index)));
+  istream_.EmitDropKeep(drop_count, keep_count);
+  istream_.Emit(Opcode::ReturnCallIndirect, table_index, sig_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnCompareExpr(Opcode opcode) {
+  CHECK_RESULT(validator_.OnCompare(loc, opcode));
+  istream_.Emit(opcode);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnConvertExpr(Opcode opcode) {
+  CHECK_RESULT(validator_.OnConvert(loc, opcode));
+  istream_.Emit(opcode);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnDropExpr() {
+  CHECK_RESULT(validator_.OnDrop(loc));
+  istream_.Emit(Opcode::Drop);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnI32ConstExpr(uint32_t value) {
+  CHECK_RESULT(validator_.OnConst(loc, Type::I32));
+  istream_.Emit(Opcode::I32Const, value);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnI64ConstExpr(uint64_t value) {
+  CHECK_RESULT(validator_.OnConst(loc, Type::I64));
+  istream_.Emit(Opcode::I64Const, value);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnF32ConstExpr(uint32_t value_bits) {
+  CHECK_RESULT(validator_.OnConst(loc, Type::F32));
+  istream_.Emit(Opcode::F32Const, value_bits);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnF64ConstExpr(uint64_t value_bits) {
+  CHECK_RESULT(validator_.OnConst(loc, Type::F64));
+  istream_.Emit(Opcode::F64Const, value_bits);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnV128ConstExpr(v128 value_bits) {
+  CHECK_RESULT(validator_.OnConst(loc, Type::V128));
+  istream_.Emit(Opcode::V128Const, value_bits);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnGlobalGetExpr(Index global_index) {
+  CHECK_RESULT(validator_.OnGlobalGet(loc, Var(global_index)));
+  istream_.Emit(Opcode::GlobalGet, global_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnGlobalSetExpr(Index global_index) {
+  CHECK_RESULT(validator_.OnGlobalSet(loc, Var(global_index)));
+  istream_.Emit(Opcode::GlobalSet, global_index);
+  return Result::Ok;
+}
+
+Index BinaryReaderInterp::TranslateLocalIndex(Index local_index) {
+  return validator_.type_stack_size() + validator_.GetLocalCount() -
+         local_index;
+}
+
+Result BinaryReaderInterp::OnLocalGetExpr(Index local_index) {
+  // Get the translated index before calling validator_.OnLocalGet because it
+  // will update the type stack size. We need the index to be relative to the
+  // old stack size.
+  Index translated_local_index = TranslateLocalIndex(local_index);
+  CHECK_RESULT(validator_.OnLocalGet(loc, Var(local_index)));
+  istream_.Emit(Opcode::LocalGet, translated_local_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnLocalSetExpr(Index local_index) {
+  // See comment in OnLocalGetExpr above.
+  Index translated_local_index = TranslateLocalIndex(local_index);
+  CHECK_RESULT(validator_.OnLocalSet(loc, Var(local_index)));
+  istream_.Emit(Opcode::LocalSet, translated_local_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnLocalTeeExpr(Index local_index) {
+  CHECK_RESULT(validator_.OnLocalTee(loc, Var(local_index)));
+  istream_.Emit(Opcode::LocalTee, TranslateLocalIndex(local_index));
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnLoadExpr(Opcode opcode,
+                                      Address align_log2,
+                                      Address offset) {
+  CHECK_RESULT(validator_.OnLoad(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnStoreExpr(Opcode opcode,
+                                       Address align_log2,
+                                       Address offset) {
+  CHECK_RESULT(validator_.OnStore(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnMemoryGrowExpr() {
+  CHECK_RESULT(validator_.OnMemoryGrow(loc));
+  istream_.Emit(Opcode::MemoryGrow, kMemoryIndex0);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnMemorySizeExpr() {
+  CHECK_RESULT(validator_.OnMemorySize(loc));
+  istream_.Emit(Opcode::MemorySize, kMemoryIndex0);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableGrowExpr(Index table_index) {
+  CHECK_RESULT(validator_.OnTableGrow(loc, Var(table_index)));
+  istream_.Emit(Opcode::TableGrow, table_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableSizeExpr(Index table_index) {
+  CHECK_RESULT(validator_.OnTableSize(loc, Var(table_index)));
+  istream_.Emit(Opcode::TableSize, table_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableFillExpr(Index table_index) {
+  CHECK_RESULT(validator_.OnTableFill(loc, Var(table_index)));
+  istream_.Emit(Opcode::TableFill, table_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnRefFuncExpr(Index func_index) {
+  CHECK_RESULT(validator_.OnRefFunc(loc, Var(func_index)));
+  istream_.Emit(Opcode::RefFunc, func_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnRefNullExpr(Type type) {
+  CHECK_RESULT(validator_.OnRefNull(loc, type));
+  istream_.Emit(Opcode::RefNull);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnRefIsNullExpr() {
+  CHECK_RESULT(validator_.OnRefIsNull(loc));
+  istream_.Emit(Opcode::RefIsNull);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnNopExpr() {
+  CHECK_RESULT(validator_.OnNop(loc));
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnReturnExpr() {
+  Index drop_count, keep_count;
+  CHECK_RESULT(GetReturnDropKeepCount(&drop_count, &keep_count));
+  CHECK_RESULT(validator_.OnReturn(loc));
+  istream_.EmitDropKeep(drop_count, keep_count);
+  istream_.Emit(Opcode::Return);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnSelectExpr(Index result_count,
+                                        Type* result_types) {
+  CHECK_RESULT(validator_.OnSelect(loc, result_count, result_types));
+  istream_.Emit(Opcode::Select);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnUnreachableExpr() {
+  CHECK_RESULT(validator_.OnUnreachable(loc));
+  istream_.Emit(Opcode::Unreachable);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnAtomicWaitExpr(Opcode opcode,
+                                            Address align_log2,
+                                            Address offset) {
+  CHECK_RESULT(validator_.OnAtomicWait(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnAtomicFenceExpr(uint32_t consistency_model) {
+  CHECK_RESULT(validator_.OnAtomicFence(loc, consistency_model));
+  istream_.Emit(Opcode::AtomicFence, consistency_model);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnAtomicNotifyExpr(Opcode opcode,
+                                              Address align_log2,
+                                              Address offset) {
+  CHECK_RESULT(
+      validator_.OnAtomicNotify(loc, opcode, GetAlignment(align_log2)));
+  istream_.Emit(opcode, kMemoryIndex0, offset);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnMemoryCopyExpr() {
+  CHECK_RESULT(validator_.OnMemoryCopy(loc));
+  istream_.Emit(Opcode::MemoryCopy, kMemoryIndex0, kMemoryIndex0);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnDataDropExpr(Index segment_index) {
+  CHECK_RESULT(validator_.OnDataDrop(loc, Var(segment_index)));
+  istream_.Emit(Opcode::DataDrop, segment_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnMemoryFillExpr() {
+  CHECK_RESULT(validator_.OnMemoryFill(loc));
+  istream_.Emit(Opcode::MemoryFill, kMemoryIndex0);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnMemoryInitExpr(Index segment_index) {
+  CHECK_RESULT(validator_.OnMemoryInit(loc, Var(segment_index)));
+  istream_.Emit(Opcode::MemoryInit, kMemoryIndex0, segment_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableGetExpr(Index table_index) {
+  CHECK_RESULT(validator_.OnTableGet(loc, Var(table_index)));
+  istream_.Emit(Opcode::TableGet, table_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableSetExpr(Index table_index) {
+  CHECK_RESULT(validator_.OnTableSet(loc, Var(table_index)));
+  istream_.Emit(Opcode::TableSet, table_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableCopyExpr(Index dst_index, Index src_index) {
+  CHECK_RESULT(validator_.OnTableCopy(loc, Var(dst_index), Var(src_index)));
+  istream_.Emit(Opcode::TableCopy, dst_index, src_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnElemDropExpr(Index segment_index) {
+  CHECK_RESULT(validator_.OnElemDrop(loc, Var(segment_index)));
+  istream_.Emit(Opcode::ElemDrop, segment_index);
+  return Result::Ok;
+}
+
+Result BinaryReaderInterp::OnTableInitExpr(Index segment_index,
+                                           Index table_index) {
+  CHECK_RESULT(
+      validator_.OnTableInit(loc, Var(segment_index), Var(table_index)));
+  istream_.Emit(Opcode::TableInit, table_index, segment_index);
+  return Result::Ok;
+}
+
+}  // namespace
+
+Result ReadBinaryInterp(const void* data,
+                        size_t size,
+                        const ReadBinaryOptions& options,
+                        Errors* errors,
+                        ModuleDesc* out_module) {
+  BinaryReaderInterp reader(out_module, errors, options.features);
+  return ReadBinary(data, size, &reader, options);
+}
+
+}  // namespace interp
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/binary-reader-interp.h
new file mode 100644 (file)
index 0000000..0197e9a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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_INTERP_H_
+#define WABT_BINARY_READER_INTERP_H_
+
+#include "src/common.h"
+#include "src/error.h"
+#include "src/interp/interp.h"
+
+namespace wabt {
+
+struct ReadBinaryOptions;
+
+namespace interp {
+
+Result ReadBinaryInterp(const void* data,
+                        size_t size,
+                        const ReadBinaryOptions& options,
+                        Errors*,
+                        ModuleDesc* out_module);
+
+}  // namespace interp
+}  // namespace wabt
+
+#endif /* WABT_BINARY_READER_INTERP_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-inl.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/interp/interp-inl.h
new file mode 100644 (file)
index 0000000..e1dcb72
--- /dev/null
@@ -0,0 +1,927 @@
+/*
+ * 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 <cassert>
+#include <limits>
+#include <string>
+
+namespace wabt {
+namespace interp {
+
+//// Ref ////
+inline Ref::Ref(size_t index) : index(index) {}
+
+inline bool operator==(Ref lhs, Ref rhs) {
+  return lhs.index == rhs.index;
+}
+
+inline bool operator!=(Ref lhs, Ref rhs) {
+  return lhs.index != rhs.index;
+}
+
+//// ExternType ////
+inline ExternType::ExternType(ExternKind kind) : kind(kind) {}
+
+//// FuncType ////
+// static
+inline bool FuncType::classof(const ExternType* type) {
+  return type->kind == skind;
+}
+
+inline FuncType::FuncType(ValueTypes params, ValueTypes results)
+    : ExternType(ExternKind::Func), params(params), results(results) {}
+
+//// TableType ////
+// static
+inline bool TableType::classof(const ExternType* type) {
+  return type->kind == skind;
+}
+
+inline TableType::TableType(ValueType element, Limits limits)
+    : ExternType(ExternKind::Table), element(element), limits(limits) {
+  // Always set max.
+  if (!limits.has_max) {
+    this->limits.max = std::numeric_limits<u32>::max();
+  }
+}
+
+//// MemoryType ////
+// static
+inline bool MemoryType::classof(const ExternType* type) {
+  return type->kind == skind;
+}
+
+inline MemoryType::MemoryType(Limits limits)
+    : ExternType(ExternKind::Memory), limits(limits) {
+  // Always set max.
+  if (!limits.has_max) {
+    this->limits.max = WABT_MAX_PAGES;
+  }
+}
+
+//// GlobalType ////
+// static
+inline bool GlobalType::classof(const ExternType* type) {
+  return type->kind == skind;
+}
+
+inline GlobalType::GlobalType(ValueType type, Mutability mut)
+    : ExternType(ExternKind::Global), type(type), mut(mut) {}
+
+//// EventType ////
+// static
+inline bool EventType::classof(const ExternType* type) {
+  return type->kind == skind;
+}
+
+inline EventType::EventType(EventAttr attr, const ValueTypes& signature)
+    : ExternType(ExternKind::Event), attr(attr), signature(signature) {}
+
+//// ImportType ////
+inline ImportType::ImportType(std::string module,
+                              std::string name,
+                              std::unique_ptr<ExternType> type)
+    : module(module), name(name), type(std::move(type)) {}
+
+inline ImportType::ImportType(const ImportType& other)
+    : module(other.module), name(other.name), type(other.type->Clone()) {}
+
+inline ImportType& ImportType::operator=(const ImportType& other) {
+  if (this != &other) {
+    module = other.module;
+    name = other.name;
+    type = other.type->Clone();
+  }
+  return *this;
+}
+
+//// ExportType ////
+inline ExportType::ExportType(std::string name,
+                              std::unique_ptr<ExternType> type)
+    : name(name), type(std::move(type)) {}
+
+inline ExportType::ExportType(const ExportType& other)
+    : name(other.name), type(other.type->Clone()) {}
+
+inline ExportType& ExportType::operator=(const ExportType& other) {
+  if (this != &other) {
+    name = other.name;
+    type = other.type->Clone();
+  }
+  return *this;
+}
+
+//// Frame ////
+inline Frame::Frame(Ref func,
+                    u32 values,
+                    u32 offset,
+                    Instance* inst,
+                    Module* mod)
+    : func(func), values(values), offset(offset), inst(inst), mod(mod) {}
+
+//// FreeList ////
+template <typename T>
+bool FreeList<T>::IsUsed(Index index) const {
+  return index < list_.size() && !is_free_[index];
+}
+
+template <typename T>
+template <typename... Args>
+auto FreeList<T>::New(Args&&... args) -> Index {
+  if (!free_.empty()) {
+    Index index = free_.back();
+    assert(is_free_[index]);
+    free_.pop_back();
+    is_free_[index] = false;
+    list_[index] = T(std::forward<Args>(args)...);
+    return index;
+  }
+  assert(list_.size() == is_free_.size());
+  is_free_.push_back(false);
+  list_.emplace_back(std::forward<Args>(args)...);
+  return list_.size() - 1;
+}
+
+template <typename T>
+void FreeList<T>::Delete(Index index) {
+  list_[index] = T();
+  is_free_[index] = true;
+  free_.push_back(index);
+}
+
+template <typename T>
+const T& FreeList<T>::Get(Index index) const {
+  assert(IsUsed(index));
+  return list_[index];
+}
+
+template <typename T>
+T& FreeList<T>::Get(Index index) {
+  assert(IsUsed(index));
+  return list_[index];
+}
+
+template <typename T>
+auto FreeList<T>::size() const -> Index {
+  return list_.size();
+}
+
+template <typename T>
+auto FreeList<T>::count() const -> Index {
+  return list_.size() - free_.size();
+}
+
+//// RefPtr ////
+template <typename T>
+RefPtr<T>::RefPtr() : obj_(nullptr), store_(nullptr), root_index_(0) {}
+
+template <typename T>
+RefPtr<T>::RefPtr(Store& store, Ref ref) {
+#ifndef NDEBUG
+  if (!store.Is<T>(ref)) {
+    ObjectKind ref_kind;
+    if (ref == Ref::Null) {
+      ref_kind = ObjectKind::Null;
+    } else {
+      ref_kind = store.objects_.Get(ref.index)->kind();
+    }
+    fprintf(stderr, "Invalid conversion from Ref (%s) to RefPtr<%s>!\n",
+            GetName(ref_kind), T::GetTypeName());
+    abort();
+  }
+#endif
+  root_index_ = store.NewRoot(ref);
+  obj_ = static_cast<T*>(store.objects_.Get(ref.index).get());
+  store_ = &store;
+}
+
+template <typename T>
+RefPtr<T>::RefPtr(const RefPtr& other)
+    : obj_(other.obj_), store_(other.store_) {
+  root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0;
+}
+
+template <typename T>
+RefPtr<T>& RefPtr<T>::operator=(const RefPtr& other) {
+  obj_ = other.obj_;
+  store_ = other.store_;
+  root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0;
+  return *this;
+}
+
+template <typename T>
+RefPtr<T>::RefPtr(RefPtr&& other)
+    : obj_(other.obj_), store_(other.store_), root_index_(other.root_index_) {
+  other.obj_ = nullptr;
+  other.store_ = nullptr;
+  other.root_index_ = 0;
+}
+
+template <typename T>
+RefPtr<T>& RefPtr<T>::operator=(RefPtr&& other) {
+  obj_ = other.obj_;
+  store_ = other.store_;
+  root_index_ = other.root_index_;
+  other.obj_ = nullptr;
+  other.store_ = nullptr;
+  other.root_index_ = 0;
+  return *this;
+}
+
+template <typename T>
+RefPtr<T>::~RefPtr() {
+  reset();
+}
+
+template <typename T>
+template <typename U>
+RefPtr<T>::RefPtr(const RefPtr<U>& other)
+    : obj_(other.obj_), store_(other.store_) {
+  root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0;
+}
+
+template <typename T>
+template <typename U>
+RefPtr<T>& RefPtr<T>::operator=(const RefPtr<U>& other){
+  obj_ = other.obj_;
+  store_ = other.store_;
+  root_index_ = store_ ? store_->CopyRoot(other.root_index_) : 0;
+  return *this;
+}
+
+template <typename T>
+template <typename U>
+RefPtr<T>::RefPtr(RefPtr&& other)
+    : obj_(other.obj_), store_(other.store_), root_index_(other.root_index_) {
+  other.obj_ = nullptr;
+  other.store_ = nullptr;
+  other.root_index_ = 0;
+}
+
+template <typename T>
+template <typename U>
+RefPtr<T>& RefPtr<T>::operator=(RefPtr&& other) {
+  obj_ = other.obj_;
+  store_ = other.store_;
+  root_index_ = other.root_index_;
+  other.obj_ = nullptr;
+  other.store_ = nullptr;
+  other.root_index_ = 0;
+  return *this;
+}
+
+template <typename T>
+template <typename U>
+RefPtr<U> RefPtr<T>::As() {
+  static_assert(std::is_base_of<T, U>::value, "T must be base class of U");
+  assert(store_->Is<U>(obj_->self()));
+  RefPtr<U> result;
+  result.obj_ = static_cast<U*>(obj_);
+  result.store_ = store_;
+  result.root_index_ = store_->CopyRoot(root_index_);
+  return result;
+}
+
+template <typename T>
+bool RefPtr<T>::empty() const {
+  return obj_ == nullptr;
+}
+
+template <typename T>
+void RefPtr<T>::reset() {
+  if (obj_) {
+    store_->DeleteRoot(root_index_);
+    obj_ = nullptr;
+    root_index_ = 0;
+    store_ = nullptr;
+  }
+}
+
+template <typename T>
+T* RefPtr<T>::get() const {
+  return obj_;
+}
+
+template <typename T>
+T* RefPtr<T>::operator->() const {
+  return obj_;
+}
+
+template <typename T>
+T& RefPtr<T>::operator*() const {
+  return *obj_;
+}
+
+template <typename T>
+RefPtr<T>::operator bool() const {
+  return obj_ != nullptr;
+}
+
+template <typename T>
+Ref RefPtr<T>::ref() const {
+  return store_ ? store_->roots_.Get(root_index_) : Ref::Null;
+}
+
+template <typename T>
+Store* RefPtr<T>::store() const {
+  return store_;
+}
+
+template <typename U, typename V>
+bool operator==(const RefPtr<U>& lhs, const RefPtr<V>& rhs) {
+  return lhs.obj_->self() == rhs.obj_->self();
+}
+
+template <typename U, typename V>
+bool operator!=(const RefPtr<U>& lhs, const RefPtr<V>& rhs) {
+  return lhs.obj_->self() != rhs.obj_->self();
+}
+
+//// ValueType ////
+inline bool IsReference(ValueType type) { return type.IsRef(); }
+template <> inline bool HasType<s32>(ValueType type) { return type == ValueType::I32; }
+template <> inline bool HasType<u32>(ValueType type) { return type == ValueType::I32; }
+template <> inline bool HasType<s64>(ValueType type) { return type == ValueType::I64; }
+template <> inline bool HasType<u64>(ValueType type) { return type == ValueType::I64; }
+template <> inline bool HasType<f32>(ValueType type) { return type == ValueType::F32; }
+template <> inline bool HasType<f64>(ValueType type) { return type == ValueType::F64; }
+template <> inline bool HasType<Ref>(ValueType type) { return IsReference(type); }
+
+template <typename T> void RequireType(ValueType type) {
+  assert(HasType<T>(type));
+}
+
+inline bool TypesMatch(ValueType expected, ValueType actual) {
+  // Currently there is no subtyping, so expected and actual must match
+  // exactly. In the future this may be expanded.
+  return expected == actual;
+}
+
+//// Value ////
+inline Value WABT_VECTORCALL Value::Make(s32 val) { Value res; res.i32_ = val; res.SetType(ValueType::I32); return res; }
+inline Value WABT_VECTORCALL Value::Make(u32 val) { Value res; res.i32_ = val; res.SetType(ValueType::I32); return res; }
+inline Value WABT_VECTORCALL Value::Make(s64 val) { Value res; res.i64_ = val; res.SetType(ValueType::I64); return res; }
+inline Value WABT_VECTORCALL Value::Make(u64 val) { Value res; res.i64_ = val; res.SetType(ValueType::I64); return res; }
+inline Value WABT_VECTORCALL Value::Make(f32 val) { Value res; res.f32_ = val; res.SetType(ValueType::F32); return res; }
+inline Value WABT_VECTORCALL Value::Make(f64 val) { Value res; res.f64_ = val; res.SetType(ValueType::F64); return res; }
+inline Value WABT_VECTORCALL Value::Make(v128 val) { Value res; res.v128_ = val; res.SetType(ValueType::V128); return res; }
+inline Value WABT_VECTORCALL Value::Make(Ref val) { Value res; res.ref_ = val; res.SetType(ValueType::ExternRef); return res; }
+template <typename T, u8 L>
+Value WABT_VECTORCALL Value::Make(Simd<T, L> val) {
+  Value res;
+  res.v128_ = Bitcast<v128>(val);
+  res.SetType(ValueType::V128);
+  return res;
+}
+
+template <> inline s8 WABT_VECTORCALL Value::Get<s8>() const { CheckType(ValueType::I32); return i32_; }
+template <> inline u8 WABT_VECTORCALL Value::Get<u8>() const { CheckType(ValueType::I32); return i32_; }
+template <> inline s16 WABT_VECTORCALL Value::Get<s16>() const { CheckType(ValueType::I32); return i32_; }
+template <> inline u16 WABT_VECTORCALL Value::Get<u16>() const { CheckType(ValueType::I32); return i32_; }
+template <> inline s32 WABT_VECTORCALL Value::Get<s32>() const { CheckType(ValueType::I32); return i32_; }
+template <> inline u32 WABT_VECTORCALL Value::Get<u32>() const { CheckType(ValueType::I32); return i32_; }
+template <> inline s64 WABT_VECTORCALL Value::Get<s64>() const { CheckType(ValueType::I64); return i64_; }
+template <> inline u64 WABT_VECTORCALL Value::Get<u64>() const { CheckType(ValueType::I64); return i64_; }
+template <> inline f32 WABT_VECTORCALL Value::Get<f32>() const { CheckType(ValueType::F32); return f32_; }
+template <> inline f64 WABT_VECTORCALL Value::Get<f64>() const { CheckType(ValueType::F64); return f64_; }
+template <> inline v128 WABT_VECTORCALL Value::Get<v128>() const { CheckType(ValueType::V128); return v128_; }
+template <> inline Ref WABT_VECTORCALL Value::Get<Ref>() const { CheckType(ValueType::ExternRef); return ref_; }
+
+template <> inline s8x16 WABT_VECTORCALL Value::Get<s8x16>() const { CheckType(ValueType::V128); return Bitcast<s8x16>(v128_); }
+template <> inline u8x16 WABT_VECTORCALL Value::Get<u8x16>() const { CheckType(ValueType::V128); return Bitcast<u8x16>(v128_); }
+template <> inline s16x8 WABT_VECTORCALL Value::Get<s16x8>() const { CheckType(ValueType::V128); return Bitcast<s16x8>(v128_); }
+template <> inline u16x8 WABT_VECTORCALL Value::Get<u16x8>() const { CheckType(ValueType::V128); return Bitcast<u16x8>(v128_); }
+template <> inline s32x4 WABT_VECTORCALL Value::Get<s32x4>() const { CheckType(ValueType::V128); return Bitcast<s32x4>(v128_); }
+template <> inline u32x4 WABT_VECTORCALL Value::Get<u32x4>() const { CheckType(ValueType::V128); return Bitcast<u32x4>(v128_); }
+template <> inline s64x2 WABT_VECTORCALL Value::Get<s64x2>() const { CheckType(ValueType::V128); return Bitcast<s64x2>(v128_); }
+template <> inline u64x2 WABT_VECTORCALL Value::Get<u64x2>() const { CheckType(ValueType::V128); return Bitcast<u64x2>(v128_); }
+template <> inline f32x4 WABT_VECTORCALL Value::Get<f32x4>() const { CheckType(ValueType::V128); return Bitcast<f32x4>(v128_); }
+template <> inline f64x2 WABT_VECTORCALL Value::Get<f64x2>() const { CheckType(ValueType::V128); return Bitcast<f64x2>(v128_); }
+
+template <> inline void WABT_VECTORCALL Value::Set<s32>(s32 val) { i32_ = val; SetType(ValueType::I32); }
+template <> inline void WABT_VECTORCALL Value::Set<u32>(u32 val) { i32_ = val; SetType(ValueType::I32); }
+template <> inline void WABT_VECTORCALL Value::Set<s64>(s64 val) { i64_ = val; SetType(ValueType::I64); }
+template <> inline void WABT_VECTORCALL Value::Set<u64>(u64 val) { i64_ = val; SetType(ValueType::I64); }
+template <> inline void WABT_VECTORCALL Value::Set<f32>(f32 val) { f32_ = val; SetType(ValueType::F32); }
+template <> inline void WABT_VECTORCALL Value::Set<f64>(f64 val) { f64_ = val; SetType(ValueType::F64); }
+template <> inline void WABT_VECTORCALL Value::Set<v128>(v128 val) { v128_ = val; SetType(ValueType::V128); }
+template <> inline void WABT_VECTORCALL Value::Set<Ref>(Ref val) { ref_ = val; SetType(ValueType::ExternRef); }
+
+//// Store ////
+inline bool Store::IsValid(Ref ref) const {
+  return objects_.IsUsed(ref.index) && objects_.Get(ref.index);
+}
+
+template <typename T>
+bool Store::Is(Ref ref) const {
+  return objects_.IsUsed(ref.index) && isa<T>(objects_.Get(ref.index).get());
+}
+
+template <typename T>
+Result Store::Get(Ref ref, RefPtr<T>* out) {
+  if (Is<T>(ref)) {
+    *out = RefPtr<T>(*this, ref);
+    return Result::Ok;
+  }
+  return Result::Error;
+}
+
+template <typename T>
+RefPtr<T> Store::UnsafeGet(Ref ref) {
+  return RefPtr<T>(*this, ref);
+}
+
+template <typename T, typename... Args>
+RefPtr<T> Store::Alloc(Args&&... args) {
+  Ref ref{objects_.New(new T(std::forward<Args>(args)...))};
+  RefPtr<T> ptr{*this, ref};
+  ptr->self_ = ref;
+  return ptr;
+}
+
+inline Store::ObjectList::Index Store::object_count() const {
+  return objects_.count();
+}
+
+inline const Features& Store::features() const {
+  return features_;
+}
+
+//// Object ////
+// static
+inline bool Object::classof(const Object* obj) {
+  return true;
+}
+
+inline Object::Object(ObjectKind kind) : kind_(kind) {}
+
+inline ObjectKind Object::kind() const {
+  return kind_;
+}
+
+inline Ref Object::self() const {
+  return self_;
+}
+
+inline void* Object::host_info() const {
+  return host_info_;
+}
+
+inline void Object::set_host_info(void* host_info) {
+  host_info_ = host_info;
+}
+
+inline Finalizer Object::get_finalizer() const {
+  return finalizer_;
+}
+
+inline void Object::set_finalizer(Finalizer finalizer) {
+  finalizer_ = finalizer;
+}
+
+//// Foreign ////
+// static
+inline bool Foreign::classof(const Object* obj) {
+  return obj->kind() == skind;
+}
+
+// static
+inline Foreign::Ptr Foreign::New(Store& store, void* ptr) {
+  return store.Alloc<Foreign>(store, ptr);
+}
+
+inline void* Foreign::ptr() {
+  return ptr_;
+}
+
+//// Trap ////
+// static
+inline bool Trap::classof(const Object* obj) {
+  return obj->kind() == skind;
+}
+
+// static
+inline Trap::Ptr Trap::New(Store& store,
+                           const std::string& msg,
+                           const std::vector<Frame>& trace) {
+  return store.Alloc<Trap>(store, msg, trace);
+}
+
+inline std::string Trap::message() const {
+  return message_;
+}
+
+//// Extern ////
+// static
+inline bool Extern::classof(const Object* obj) {
+  switch (obj->kind()) {
+    case ObjectKind::DefinedFunc:
+    case ObjectKind::HostFunc:
+    case ObjectKind::Table:
+    case ObjectKind::Memory:
+    case ObjectKind::Global:
+    case ObjectKind::Event:
+      return true;
+    default:
+      return false;
+  }
+}
+
+inline Extern::Extern(ObjectKind kind) : Object(kind) {}
+
+//// Func ////
+// static
+inline bool Func::classof(const Object* obj) {
+  switch (obj->kind()) {
+    case ObjectKind::DefinedFunc:
+    case ObjectKind::HostFunc:
+      return true;
+    default:
+      return false;
+  }
+}
+
+inline const ExternType& Func::extern_type() {
+  return type_;
+}
+
+inline const FuncType& Func::type() const {
+  return type_;
+}
+
+//// DefinedFunc ////
+// static
+inline bool DefinedFunc::classof(const Object* obj) {
+  return obj->kind() == skind;
+}
+
+// static
+inline DefinedFunc::Ptr DefinedFunc::New(Store& store,
+                                         Ref instance,
+                                         FuncDesc desc) {
+  return store.Alloc<DefinedFunc>(store, instance, desc);
+}
+
+inline Ref DefinedFunc::instance() const {
+  return instance_;
+}
+
+inline const FuncDesc& DefinedFunc::desc() const {
+  return desc_;
+}
+
+//// HostFunc ////
+// static
+inline bool HostFunc::classof(const Object* obj) {
+  return obj->kind() == skind;
+}
+
+// static
+inline HostFunc::Ptr HostFunc::New(Store& store, FuncType type, Callback cb) {
+  return store.Alloc<HostFunc>(store, type, cb);
+}
+
+//// Table ////
+// static
+inline bool Table::classof(const Object* obj) {
+  return obj->kind() == skind;
+}
+
+// static
+inline Table::Ptr Table::New(Store& store, TableType type) {
+  return store.Alloc<Table>(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<u32>(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<Memory>(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 <typename T>
+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 <typename T>
+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 <typename T>
+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 <typename T>
+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 <typename T>
+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 <typename T, typename F>
+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 <typename T>
+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<Global>(store, type, value);
+}
+
+inline Value Global::Get() const {
+  return value_;
+}
+
+template <typename T>
+Result Global::Get(T* out) const {
+  if (HasType<T>(type_.type)) {
+    *out = value_.Get<T>();
+    return Result::Ok;
+  }
+  return Result::Error;
+}
+
+template <typename T>
+T WABT_VECTORCALL Global::UnsafeGet() const {
+  RequireType<T>(type_.type);
+  return value_.Get<T>();
+}
+
+template <typename T>
+Result WABT_VECTORCALL Global::Set(T val) {
+  if (type_.mut == Mutability::Var && HasType<T>(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<Event>(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<Module>(store, std::move(desc));
+}
+
+inline const ModuleDesc& Module::desc() const {
+  return desc_;
+}
+
+inline const std::vector<ImportType>& Module::import_types() const {
+  return import_types_;
+}
+
+inline const std::vector<ExportType>& 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<ElemSegment>& Instance::elems() const {
+  return elems_;
+}
+
+inline std::vector<ElemSegment>& Instance::elems() {
+  return elems_;
+}
+
+inline const std::vector<DataSegment>& Instance::datas() const {
+  return datas_;
+}
+
+inline std::vector<DataSegment>& 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<Thread>(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 (file)
index 0000000..d5643d5
--- /dev/null
@@ -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 <cmath>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#if COMPILER_IS_MSVC
+#include <emmintrin.h>
+#include <immintrin.h>
+#endif
+
+#include "src/common.h"
+#include "src/interp/interp.h"
+
+namespace wabt {
+namespace interp {
+
+template <
+    typename T,
+    typename std::enable_if<!std::is_floating_point<T>::value, int>::type = 0>
+bool WABT_VECTORCALL IsNaN(T val) {
+  return false;
+}
+
+template <
+    typename T,
+    typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
+bool WABT_VECTORCALL IsNaN(T val) {
+  return std::isnan(val);
+}
+
+template <
+    typename T,
+    typename std::enable_if<!std::is_floating_point<T>::value, int>::type = 0>
+T WABT_VECTORCALL CanonNaN(T val) {
+  return val;
+}
+
+template <
+    typename T,
+    typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0>
+T WABT_VECTORCALL CanonNaN(T val) {
+  if (WABT_UNLIKELY(std::isnan(val))) {
+    return std::numeric_limits<f32>::quiet_NaN();
+  }
+  return val;
+}
+
+template <typename T> T ShiftMask(T val) { return val & (sizeof(T)*8-1); }
+
+template <typename T> bool WABT_VECTORCALL IntEqz(T val) { return val == 0; }
+template <typename T> bool WABT_VECTORCALL Eq(T lhs, T rhs) { return lhs == rhs; }
+template <typename T> bool WABT_VECTORCALL Ne(T lhs, T rhs) { return lhs != rhs; }
+template <typename T> bool WABT_VECTORCALL Lt(T lhs, T rhs) { return lhs < rhs; }
+template <typename T> bool WABT_VECTORCALL Le(T lhs, T rhs) { return lhs <= rhs; }
+template <typename T> bool WABT_VECTORCALL Gt(T lhs, T rhs) { return lhs > rhs; }
+template <typename T> bool WABT_VECTORCALL Ge(T lhs, T rhs) { return lhs >= rhs; }
+template <typename T> T WABT_VECTORCALL IntClz(T val) { return Clz(val); }
+template <typename T> T WABT_VECTORCALL IntCtz(T val) { return Ctz(val); }
+template <typename T> T WABT_VECTORCALL IntPopcnt(T val) { return Popcount(val); }
+template <typename T> T WABT_VECTORCALL IntNot(T val) { return ~val; }
+template <typename T> T WABT_VECTORCALL IntNeg(T val) { return ~val + 1; }
+template <typename T> T WABT_VECTORCALL Add(T lhs, T rhs) { return CanonNaN(lhs + rhs); }
+template <typename T> T WABT_VECTORCALL Sub(T lhs, T rhs) { return CanonNaN(lhs - rhs); }
+template <typename T> T WABT_VECTORCALL IntAnd(T lhs, T rhs) { return lhs & rhs; }
+template <typename T> T WABT_VECTORCALL IntOr(T lhs, T rhs) { return lhs | rhs; }
+template <typename T> T WABT_VECTORCALL IntXor(T lhs, T rhs) { return lhs ^ rhs; }
+template <typename T> T WABT_VECTORCALL IntShl(T lhs, T rhs) { return lhs << ShiftMask(rhs); }
+template <typename T> T WABT_VECTORCALL IntShr(T lhs, T rhs) { return lhs >> ShiftMask(rhs); }
+template <typename T> T WABT_VECTORCALL IntMin(T lhs, T rhs) { return std::min(lhs, rhs); }
+template <typename T> T WABT_VECTORCALL IntMax(T lhs, T rhs) { return std::max(lhs, rhs); }
+template <typename T> T WABT_VECTORCALL IntAndNot(T lhs, T rhs) { return lhs & ~rhs; }
+template <typename T> T WABT_VECTORCALL IntAvgr(T lhs, T rhs) { return (lhs + rhs + 1) / 2; }
+template <typename T> 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 <typename T>
+T WABT_VECTORCALL IntAbs(T val) {
+  static_assert(std::is_unsigned<T>::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 <typename T> struct PromoteMul { using type = T; };
+template <> struct PromoteMul<u16> { using type = u32; };
+
+template <typename T>
+T WABT_VECTORCALL Mul(T lhs, T rhs) {
+  using U = typename PromoteMul<T>::type;
+  return CanonNaN(U(lhs) * U(rhs));
+}
+
+template <typename T> struct Mask { using Type = T; };
+template <> struct Mask<f32> { using Type = u32; };
+template <> struct Mask<f64> { using Type = u64; };
+
+template <typename T> typename Mask<T>::Type WABT_VECTORCALL EqMask(T lhs, T rhs) { return lhs == rhs ? -1 : 0; }
+template <typename T> typename Mask<T>::Type WABT_VECTORCALL NeMask(T lhs, T rhs) { return lhs != rhs ? -1 : 0; }
+template <typename T> typename Mask<T>::Type WABT_VECTORCALL LtMask(T lhs, T rhs) { return lhs < rhs ? -1 : 0; }
+template <typename T> typename Mask<T>::Type WABT_VECTORCALL LeMask(T lhs, T rhs) { return lhs <= rhs ? -1 : 0; }
+template <typename T> typename Mask<T>::Type WABT_VECTORCALL GtMask(T lhs, T rhs) { return lhs > rhs ? -1 : 0; }
+template <typename T> typename Mask<T>::Type WABT_VECTORCALL GeMask(T lhs, T rhs) { return lhs >= rhs ? -1 : 0; }
+
+template <typename T>
+T WABT_VECTORCALL IntRotl(T lhs, T rhs) {
+  return (lhs << ShiftMask(rhs)) | (lhs >> ShiftMask<T>(0 - rhs));
+}
+
+template <typename T>
+T WABT_VECTORCALL IntRotr(T lhs, T rhs) {
+  return (lhs >> ShiftMask(rhs)) | (lhs << ShiftMask<T>(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 <typename T,
+          typename std::enable_if<std::is_signed<T>::value, int>::type = 0>
+bool IsNormalDivRem(T lhs, T rhs) {
+  return !(lhs == std::numeric_limits<T>::min() && rhs == -1);
+}
+
+template <typename T,
+          typename std::enable_if<!std::is_signed<T>::value, int>::type = 0>
+bool IsNormalDivRem(T lhs, T rhs) {
+  return true;
+}
+
+template <typename T>
+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 <typename T>
+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 <typename T> T WABT_VECTORCALL FloatAbs(T val);
+template <typename T> 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 <typename T>
+T WABT_VECTORCALL FloatAbs(T val) {
+  return std::abs(val);
+}
+
+template <typename T>
+T WABT_VECTORCALL FloatCopysign(T lhs, T rhs) {
+  return std::copysign(lhs, rhs);
+}
+#endif
+
+#if COMPILER_IS_MSVC
+#else
+#endif
+
+template <typename T> T WABT_VECTORCALL FloatNeg(T val) { return -val; }
+template <typename T> T WABT_VECTORCALL FloatCeil(T val) { return CanonNaN(std::ceil(val)); }
+template <typename T> T WABT_VECTORCALL FloatFloor(T val) { return CanonNaN(std::floor(val)); }
+template <typename T> T WABT_VECTORCALL FloatTrunc(T val) { return CanonNaN(std::trunc(val)); }
+template <typename T> T WABT_VECTORCALL FloatNearest(T val) { return CanonNaN(std::nearbyint(val)); }
+template <typename T> T WABT_VECTORCALL FloatSqrt(T val) { return CanonNaN(std::sqrt(val)); }
+
+template <typename T>
+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<T>::quiet_NaN()
+               : ((std::signbit(lhs) ^ std::signbit(rhs))
+                      ? -std::numeric_limits<T>::infinity()
+                      : std::numeric_limits<T>::infinity());
+  }
+  return CanonNaN(lhs / rhs);
+}
+
+template <typename T>
+T WABT_VECTORCALL FloatMin(T lhs, T rhs) {
+  if (WABT_UNLIKELY(std::isnan(lhs) || std::isnan(rhs))) {
+    return std::numeric_limits<T>::quiet_NaN();
+  } else if (WABT_UNLIKELY(lhs == 0 && rhs == 0)) {
+    return std::signbit(lhs) ? lhs : rhs;
+  } else {
+    return std::min(lhs, rhs);
+  }
+}
+
+template <typename T>
+T WABT_VECTORCALL FloatPMin(T lhs, T rhs) {
+  return std::min(lhs, rhs);
+}
+
+template <typename T>
+T WABT_VECTORCALL FloatMax(T lhs, T rhs) {
+  if (WABT_UNLIKELY(std::isnan(lhs) || std::isnan(rhs))) {
+    return std::numeric_limits<T>::quiet_NaN();
+  } else if (WABT_UNLIKELY(lhs == 0 && rhs == 0)) {
+    return std::signbit(lhs) ? rhs : lhs;
+  } else {
+    return std::max(lhs, rhs);
+  }
+}
+
+template <typename T>
+T WABT_VECTORCALL FloatPMax(T lhs, T rhs) {
+  return std::max(lhs, rhs);
+}
+
+template <typename R, typename T> bool WABT_VECTORCALL CanConvert(T val) { return true; }
+template <> inline bool WABT_VECTORCALL CanConvert<s32, f32>(f32 val) { return val >= -2147483648.f && val < 2147483648.f; }
+template <> inline bool WABT_VECTORCALL CanConvert<s32, f64>(f64 val) { return val > -2147483649. && val < 2147483648.; }
+template <> inline bool WABT_VECTORCALL CanConvert<u32, f32>(f32 val) { return val > -1.f && val < 4294967296.f; }
+template <> inline bool WABT_VECTORCALL CanConvert<u32, f64>(f64 val) { return val > -1. && val < 4294967296.; }
+template <> inline bool WABT_VECTORCALL CanConvert<s64, f32>(f32 val) { return val >= -9223372036854775808.f && val < 9223372036854775808.f; }
+template <> inline bool WABT_VECTORCALL CanConvert<s64, f64>(f64 val) { return val >= -9223372036854775808. && val < 9223372036854775808.; }
+template <> inline bool WABT_VECTORCALL CanConvert<u64, f32>(f32 val) { return val > -1.f && val < 18446744073709551616.f; }
+template <> inline bool WABT_VECTORCALL CanConvert<u64, f64>(f64 val) { return val > -1. && val < 18446744073709551616.; }
+
+template <typename R, typename T>
+R WABT_VECTORCALL Convert(T val) {
+  assert((CanConvert<R, T>(val)));
+  return static_cast<R>(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<f32>::max();
+  } else if (WABT_UNLIKELY(val > -kMax && val < -kMin)) {
+    return -std::numeric_limits<f32>::max();
+  } else if (WABT_UNLIKELY(std::isnan(val))) {
+    return std::numeric_limits<f32>::quiet_NaN();
+  } else {
+    return std::copysign(std::numeric_limits<f32>::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 <typename T, int N>
+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 <typename R, typename T>
+R WABT_VECTORCALL IntTruncSat(T val) {
+  if (WABT_UNLIKELY(std::isnan(val))) {
+    return 0;
+  } else if (WABT_UNLIKELY(!CanConvert<R>(val))) {
+    return std::signbit(val) ? std::numeric_limits<R>::min()
+                             : std::numeric_limits<R>::max();
+  } else {
+    return static_cast<R>(val);
+  }
+}
+
+template <typename T> struct SatPromote;
+template <> struct SatPromote<s8> { using type = s32; };
+template <> struct SatPromote<s16> { using type = s32; };
+template <> struct SatPromote<u8> { using type = s32; };
+template <> struct SatPromote<u16> { using type = s32; };
+
+template <typename R, typename T>
+R WABT_VECTORCALL Saturate(T val) {
+  static_assert(sizeof(R) < sizeof(T), "Incorrect types for Saturate");
+  const T min = std::numeric_limits<R>::min();
+  const T max = std::numeric_limits<R>::max();
+  return val > max ? max : val < min ? min : val;
+}
+
+template <typename T, typename U = typename SatPromote<T>::type>
+T WABT_VECTORCALL IntAddSat(T lhs, T rhs) {
+  return Saturate<T, U>(lhs + rhs);
+}
+
+template <typename T, typename U = typename SatPromote<T>::type>
+T WABT_VECTORCALL IntSubSat(T lhs, T rhs) {
+  return Saturate<T, U>(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 (file)
index 0000000..001b2d9
--- /dev/null
@@ -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 <cinttypes>
+
+#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<s32>());
+
+    case Type::I64:
+      return StringPrintf("i64:%" PRIu64, tv.value.Get<s64>());
+
+    case Type::F32:
+      return StringPrintf("f32:%f", tv.value.Get<f32>());
+
+    case Type::F64:
+      return StringPrintf("f64:%f", tv.value.Get<f64>());
+
+    case Type::V128: {
+      v128 simd = tv.value.Get<v128>();
+      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<u32>() & 0xff);
+
+    case Type::I16:  // For SIMD lane.
+      return StringPrintf("i16:%u", tv.value.Get<u32>() & 0xffff);
+
+    case Type::FuncRef:
+      return StringPrintf("funcref:%" PRIzd, tv.value.Get<Ref>().index);
+
+    case Type::ExternRef:
+      return StringPrintf("externref:%" PRIzd, tv.value.Get<Ref>().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 (file)
index 0000000..d05b34d
--- /dev/null
@@ -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 <string>
+#include <vector>
+
+#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 (file)
index 0000000..80deec2
--- /dev/null
@@ -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 <cinttypes>
+#include <unordered_map>
+
+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<char>(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<char>(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<char>(old_path_ptr, old_path_len, &old_path, trap));
+    CHECK_RESULT(getMemPtr<char>(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<char>(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<char>(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<uvwasi_iovec_t> iovs(iovcnt);
+    for (int i = 0; i < iovcnt; i++) {
+      iovs[i].buf_len = wasm_iovs[i].buf_len;
+
+      CHECK_RESULT(getMemPtr<uint8_t>(wasm_iovs[i].buf, wasm_iovs[i].buf_len,
+                                      reinterpret_cast<uint8_t**>(&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<uvwasi_ciovec_t> iovs(iovcnt);
+    for (int i = 0; i < iovcnt; i++) {
+      iovs[i].buf_len = wasm_iovs[i].buf_len;
+      CHECK_RESULT(getMemPtr<const uint8_t>(
+          wasm_iovs[i].buf, wasm_iovs[i].buf_len,
+          reinterpret_cast<const uint8_t**>(&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<char>(wasm_buf, environ_buf_size, &buf, trap));
+    std::vector<char*> 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<uint32_t>(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<uint32_t>(environc, params[0].i32_, trap));
+    CHECK_RESULT(writeValue<uint32_t>(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<char>(wasm_buf, arg_buf_size, &buf, trap));
+    std::vector<char*> 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<uint32_t>(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<uint32_t>(argc, params[0].i32_, trap));
+    CHECK_RESULT(writeValue<uint32_t>(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 <typename T>
+  Result writeValue(T value, uint32_t target_address, Trap::Ptr* trap) {
+    T* abs_address;
+    CHECK_RESULT(getMemPtr<T>(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 <typename T>
+  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<T*>(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<Instance*, WasiInstance*> 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<FuncType>(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<Module>(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<Memory>(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<Func>(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 (file)
index 0000000..465d176
--- /dev/null
@@ -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 (file)
index 0000000..2a0c861
--- /dev/null
@@ -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 <wasm.h>
+
+#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<FileStream> s_log_stream;
+static std::unique_ptr<FileStream> 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<wasm_externtype_t> New(std::unique_ptr<ExternType>);
+
+  std::unique_ptr<wasm_externtype_t> 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 <typename T>
+  T* As() const { return cast<T>(I.get()); }
+
+  std::unique_ptr<ExternType> I;
+
+ protected:
+  wasm_externtype_t(std::unique_ptr<ExternType> 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<FuncType>(ToWabtValueTypes(params),
+                                               ToWabtValueTypes(results))},
+        params(*params),
+        results(*results) {}
+
+  wasm_functype_t(FuncType ft) : wasm_externtype_t{MakeUnique<FuncType>(ft)} {
+    FromWabtValueTypes(ft.params, &params);
+    FromWabtValueTypes(ft.results, &results);
+  }
+
+  ~wasm_functype_t() {
+    wasm_valtype_vec_delete(&params);
+    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<GlobalType>(type->I,
+                                                 ToWabtMutability(mut))},
+        valtype{*type} {
+    wasm_valtype_delete(type);
+  }
+
+  wasm_globaltype_t(GlobalType gt)
+      : wasm_externtype_t{MakeUnique<GlobalType>(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<TableType>(type->I,
+                                                ToWabtLimits(*limits))},
+        elemtype(*type),
+        limits(*limits) {
+    wasm_valtype_delete(type);
+  }
+
+  wasm_tabletype_t(TableType tt)
+      : wasm_externtype_t{MakeUnique<TableType>(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<MemoryType>(ToWabtLimits(*limits))},
+        limits{*limits} {}
+
+  wasm_memorytype_t(MemoryType mt)
+      : wasm_externtype_t{MakeUnique<MemoryType>(mt)},
+        limits{FromWabtLimits(mt.limits)} {}
+
+  // Stored here because API requires returning pointers.
+  wasm_limits_t limits;
+};
+
+// static
+std::unique_ptr<wasm_externtype_t> wasm_externtype_t::New(
+    std::unique_ptr<ExternType> ptr) {
+  switch (ptr->kind) {
+    case ExternKind::Func:
+      return MakeUnique<wasm_functype_t>(*cast<FuncType>(ptr.get()));
+
+    case ExternKind::Table:
+      return MakeUnique<wasm_tabletype_t>(*cast<TableType>(ptr.get()));
+
+    case ExternKind::Memory:
+      return MakeUnique<wasm_memorytype_t>(*cast<MemoryType>(ptr.get()));
+
+    case ExternKind::Global:
+      return MakeUnique<wasm_globaltype_t>(*cast<GlobalType>(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<wasm_byte_t*>(I.module.data())},
+        name{I.name.size(), const_cast<wasm_byte_t*>(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<wasm_externtype_t> 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<wasm_byte_t*>(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<wasm_externtype_t> 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<Object> ptr) : I(ptr) {}
+
+  template <typename T>
+  T* As() const { return cast<T>(I.get()); }
+
+  RefPtr<Object> I;
+};
+
+struct wasm_frame_t {
+  Frame I;
+};
+
+struct wasm_trap_t : wasm_ref_t {
+  wasm_trap_t(RefPtr<Trap> ptr) : wasm_ref_t(ptr) {}
+};
+
+struct wasm_foreign_t : wasm_ref_t {
+  wasm_foreign_t(RefPtr<Foreign> ptr) : wasm_ref_t(ptr) {}
+};
+
+struct wasm_module_t : wasm_ref_t {
+  wasm_module_t(RefPtr<Module> 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<Extern> ptr) : wasm_ref_t(ptr) {}
+};
+
+struct wasm_func_t : wasm_extern_t {
+  wasm_func_t(RefPtr<Func> ptr) : wasm_extern_t(ptr) {}
+};
+
+struct wasm_global_t : wasm_extern_t {
+  wasm_global_t(RefPtr<Global> ptr) : wasm_extern_t(ptr) {}
+};
+
+struct wasm_table_t : wasm_extern_t {
+  wasm_table_t(RefPtr<Table> ptr) : wasm_extern_t(ptr) {}
+};
+
+struct wasm_memory_t : wasm_extern_t {
+  wasm_memory_t(RefPtr<Memory> ptr) : wasm_extern_t(ptr) {}
+};
+
+struct wasm_instance_t : wasm_ref_t {
+  wasm_instance_t(RefPtr<Instance> 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<s32>();
+      break;
+    case Type::I64:
+      out_value.kind = WASM_I64;
+      out_value.of.i64 = tv.value.Get<s64>();
+      break;
+    case Type::F32:
+      out_value.kind = WASM_F32;
+      out_value.of.f32 = tv.value.Get<f32>();
+      break;
+    case Type::F64:
+      out_value.kind = WASM_F64;
+      out_value.of.f64 = tv.value.Get<f64>();
+      break;
+    case Type::FuncRef: {
+      Ref ref = tv.value.Get<Ref>();
+      out_value.kind = WASM_FUNCREF;
+      out_value.of.ref = new wasm_func_t(store.UnsafeGet<Func>(ref));
+      break;
+    }
+    case Type::ExternRef: {
+      Ref ref = tv.value.Get<Ref>();
+      out_value.kind = WASM_ANYREF;
+      out_value.of.ref = new wasm_foreign_t(store.UnsafeGet<Foreign>(ref));
+      break;
+    }
+    default:
+      TRACE("unexpected wabt type: %d", static_cast<int>(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<Trap>()->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<Module>()->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<Module>()->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<Module>()->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<Instance>()->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<Extern>(exports[i])};
+  }
+}
+
+uint32_t wasm_instance_func_index(const wasm_instance_t* instance,
+                                const wasm_func_t* func) {
+  auto&& funcs = instance->As<Instance>()->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<FuncType>());
+  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<FuncType>();
+  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(&params, 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(&params);
+    if (trap) {
+      *out_trap = trap->I.As<Trap>();
+      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<FuncType>();
+  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(&params, 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(&params);
+    if (trap) {
+      *out_trap = trap->I.As<Trap>();
+      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<Func>()->type()};
+}
+
+size_t wasm_func_result_arity(const wasm_func_t* func) {
+  return func->As<Func>()->type().results.size();
+}
+
+size_t wasm_func_param_arity(const wasm_func_t* func) {
+  return func->As<Func>()->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<Func>()->type();
+  Values wabt_args = ToWabtValues(args, func_type.params.size());
+  Values wabt_results;
+  Trap::Ptr trap;
+  if (Failed(
+          f->As<Func>()->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<GlobalType>()->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<GlobalType>(), value.value)};
+}
+
+own wasm_globaltype_t* wasm_global_type(const wasm_global_t* global) {
+  return new wasm_globaltype_t{global->As<Global>()->type()};
+}
+
+void wasm_global_get(const wasm_global_t* global, own wasm_val_t* out) {
+  assert(global);
+  TRACE0();
+  TypedValue tv{global->As<Global>()->type().type, global->As<Global>()->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<Global>()->Set(*global->I.store(), val->of.ref->I->self());
+  } else {
+    global->As<Global>()->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<TableType>())};
+}
+
+own wasm_tabletype_t* wasm_table_type(const wasm_table_t* table) {
+  return new wasm_tabletype_t{table->As<Table>()->type()};
+}
+
+wasm_table_size_t wasm_table_size(const wasm_table_t* table) {
+  return table->As<Table>()->size();
+}
+
+own wasm_ref_t* wasm_table_get(const wasm_table_t* table,
+                               wasm_table_size_t index) {
+  Ref ref;
+  if (Failed(table->As<Table>()->Get(index, &ref))) {
+    return nullptr;
+  }
+  if (ref == Ref::Null) {
+    return nullptr;
+  }
+  return new wasm_ref_t{table->I.store()->UnsafeGet<Object>(ref)};
+}
+
+bool wasm_table_set(wasm_table_t* table,
+                    wasm_table_size_t index,
+                    wasm_ref_t* ref) {
+  return Succeeded(table->As<Table>()->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<Table>()->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<MemoryType>())};
+}
+
+own wasm_memorytype_t* wasm_memory_type(const wasm_memory_t* memory) {
+  return new wasm_memorytype_t{memory->As<Memory>()->type()};
+}
+
+byte_t* wasm_memory_data(wasm_memory_t* memory) {
+  return reinterpret_cast<byte_t*>(memory->As<Memory>()->UnsafeData());
+}
+
+wasm_memory_pages_t wasm_memory_size(const wasm_memory_t* memory) {
+  return memory->As<Memory>()->PageSize();
+}
+
+size_t wasm_memory_data_size(const wasm_memory_t* memory) {
+  return memory->As<Memory>()->ByteSize();
+}
+
+bool wasm_memory_grow(wasm_memory_t* memory, wasm_memory_pages_t delta) {
+  return Succeeded(memory->As<Memory>()->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>()->extern_type().Clone())
+      .release();
+}
+
+wasm_externkind_t wasm_extern_kind(const wasm_extern_t* extern_) {
+  return FromWabtExternKind(extern_->As<Extern>()->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<wasm_##name##_t*>(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<wasm_##name##_t*>(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<const wasm_##name##_t*>(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<wasm_shared_##name##_t*>(                               \
+        const_cast<wasm_##name##_t*>(t));                                      \
+  }                                                                            \
+  own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*,                     \
+                                            const wasm_shared_##name##_t* t) { \
+    return static_cast<wasm_##name##_t*>(                                      \
+        const_cast<wasm_shared_##name##_t*>(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<const wasm_##name##type_t*>(t);                         \
+  }                                                                            \
+  wasm_##name##type_t* wasm_externtype_as_##name##type(wasm_externtype_t* t) { \
+    return static_cast<wasm_##name##type_t*>(t);                               \
+  }                                                                            \
+  wasm_externtype_t* wasm_##name##type_as_externtype(wasm_##name##type_t* t) { \
+    return static_cast<wasm_externtype_t*>(t);                                 \
+  }                                                                            \
+  const wasm_externtype_t* wasm_##name##type_as_externtype_const(              \
+      const wasm_##name##type_t* t) {                                          \
+    return static_cast<const wasm_externtype_t*>(t);                           \
+  }                                                                            \
+  wasm_extern_t* wasm_##name##_as_extern(wasm_##name##_t* name) {              \
+    return static_cast<wasm_extern_t*>(name);                                  \
+  }                                                                            \
+  const wasm_extern_t* wasm_##name##_as_extern_const(                          \
+      const wasm_##name##_t* name) {                                           \
+    return static_cast<const wasm_extern_t*>(name);                            \
+  }                                                                            \
+  wasm_##name##_t* wasm_extern_as_##name(wasm_extern_t* ext) {                 \
+    return static_cast<wasm_##name##_t*>(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 (file)
index 0000000..5988be1
--- /dev/null
@@ -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 <algorithm>
+#include <cassert>
+#include <cinttypes>
+
+#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<ExternType> FuncType::Clone() const {
+  return MakeUnique<FuncType>(*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<ExternType> TableType::Clone() const {
+  return MakeUnique<TableType>(*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<ExternType> MemoryType::Clone() const {
+  return MakeUnique<MemoryType>(*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<ExternType> GlobalType::Clone() const {
+  return MakeUnique<GlobalType>(*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<ExternType> EventType::Clone() const {
+  return MakeUnique<EventType>(*this);
+}
+
+Result Match(const EventType& expected,
+             const EventType& actual,
+             std::string* out_msg) {
+  // TODO signature
+  return Result::Ok;
+}
+
+//// Limits ////
+template <typename T>
+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<bool> 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<Frame>& trace)
+    : Object(skind), message_(msg), trace_(trace) {}
+
+void Trap::Mark(Store& store) {
+  for (auto&& frame : trace_) {
+    frame.Mark(store);
+  }
+}
+
+//// Extern ////
+template <typename T>
+Result Extern::MatchImpl(Store& store,
+                         const ImportType& import_type,
+                         const T& actual,
+                         Trap::Ptr* out_trap) {
+  const T* extern_type = dyn_cast<T>(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<u32>(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<u64>(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<Ref>());
+  }
+}
+
+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>(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<Instance>(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<u32>();
+        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<u32>();
+        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<TraceSource>(this);
+  }
+}
+
+void Thread::Mark(Store& store) {
+  for (auto&& frame : frames_) {
+    frame.Mark(store);
+  }
+  for (auto index: refs_) {
+    store.Mark(values_[index].Get<Ref>());
+  }
+}
+
+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<Instance>(func.instance()).get();
+  mod_ = store_.UnsafeGet<Module>(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 <typename T>
+T WABT_VECTORCALL Thread::Pop() {
+  return Pop().Get<T>();
+}
+
+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<u64>() : Pop<u32>();
+}
+
+template <typename T>
+void WABT_VECTORCALL Thread::Push(T value) {
+  Push(Value::Make(value));
+}
+
+template <>
+void Thread::Push<bool>(bool value) {
+  Push(Value::Make(static_cast<u32>(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<u32>()) {
+        pc = instr.imm_u32;
+      }
+      break;
+
+    case O::BrTable: {
+      auto key = Pop<u32>();
+      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<u32>();
+      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<u32>();
+      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<u32>(instr, out_trap);
+    case O::I64Load:    return DoLoad<u64>(instr, out_trap);
+    case O::F32Load:    return DoLoad<f32>(instr, out_trap);
+    case O::F64Load:    return DoLoad<f64>(instr, out_trap);
+    case O::I32Load8S:  return DoLoad<s32, s8>(instr, out_trap);
+    case O::I32Load8U:  return DoLoad<u32, u8>(instr, out_trap);
+    case O::I32Load16S: return DoLoad<s32, s16>(instr, out_trap);
+    case O::I32Load16U: return DoLoad<u32, u16>(instr, out_trap);
+    case O::I64Load8S:  return DoLoad<s64, s8>(instr, out_trap);
+    case O::I64Load8U:  return DoLoad<u64, u8>(instr, out_trap);
+    case O::I64Load16S: return DoLoad<s64, s16>(instr, out_trap);
+    case O::I64Load16U: return DoLoad<u64, u16>(instr, out_trap);
+    case O::I64Load32S: return DoLoad<s64, s32>(instr, out_trap);
+    case O::I64Load32U: return DoLoad<u64, u32>(instr, out_trap);
+
+    case O::I32Store:   return DoStore<u32>(instr, out_trap);
+    case O::I64Store:   return DoStore<u64>(instr, out_trap);
+    case O::F32Store:   return DoStore<f32>(instr, out_trap);
+    case O::F64Store:   return DoStore<f64>(instr, out_trap);
+    case O::I32Store8:  return DoStore<u32, u8>(instr, out_trap);
+    case O::I32Store16: return DoStore<u32, u16>(instr, out_trap);
+    case O::I64Store8:  return DoStore<u64, u8>(instr, out_trap);
+    case O::I64Store16: return DoStore<u64, u16>(instr, out_trap);
+    case O::I64Store32: return DoStore<u64, u32>(instr, out_trap);
+
+    case O::MemorySize: {
+      Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32]};
+      if (memory->type().limits.is_64) {
+        Push<u64>(memory->PageSize());
+      } else {
+        Push<u32>(static_cast<u32>(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<u64>()))) {
+          Push<s64>(-1);
+        } else {
+          Push<u64>(old_size);
+        }
+      } else {
+        if (Failed(memory->Grow(Pop<u32>()))) {
+          Push<s32>(-1);
+        } else {
+          Push<u32>(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<u32>);
+    case O::I32Eq:  return DoBinop(Eq<u32>);
+    case O::I32Ne:  return DoBinop(Ne<u32>);
+    case O::I32LtS: return DoBinop(Lt<s32>);
+    case O::I32LtU: return DoBinop(Lt<u32>);
+    case O::I32GtS: return DoBinop(Gt<s32>);
+    case O::I32GtU: return DoBinop(Gt<u32>);
+    case O::I32LeS: return DoBinop(Le<s32>);
+    case O::I32LeU: return DoBinop(Le<u32>);
+    case O::I32GeS: return DoBinop(Ge<s32>);
+    case O::I32GeU: return DoBinop(Ge<u32>);
+
+    case O::I64Eqz: return DoUnop(IntEqz<u64>);
+    case O::I64Eq:  return DoBinop(Eq<u64>);
+    case O::I64Ne:  return DoBinop(Ne<u64>);
+    case O::I64LtS: return DoBinop(Lt<s64>);
+    case O::I64LtU: return DoBinop(Lt<u64>);
+    case O::I64GtS: return DoBinop(Gt<s64>);
+    case O::I64GtU: return DoBinop(Gt<u64>);
+    case O::I64LeS: return DoBinop(Le<s64>);
+    case O::I64LeU: return DoBinop(Le<u64>);
+    case O::I64GeS: return DoBinop(Ge<s64>);
+    case O::I64GeU: return DoBinop(Ge<u64>);
+
+    case O::F32Eq:  return DoBinop(Eq<f32>);
+    case O::F32Ne:  return DoBinop(Ne<f32>);
+    case O::F32Lt:  return DoBinop(Lt<f32>);
+    case O::F32Gt:  return DoBinop(Gt<f32>);
+    case O::F32Le:  return DoBinop(Le<f32>);
+    case O::F32Ge:  return DoBinop(Ge<f32>);
+
+    case O::F64Eq:  return DoBinop(Eq<f64>);
+    case O::F64Ne:  return DoBinop(Ne<f64>);
+    case O::F64Lt:  return DoBinop(Lt<f64>);
+    case O::F64Gt:  return DoBinop(Gt<f64>);
+    case O::F64Le:  return DoBinop(Le<f64>);
+    case O::F64Ge:  return DoBinop(Ge<f64>);
+
+    case O::I32Clz:    return DoUnop(IntClz<u32>);
+    case O::I32Ctz:    return DoUnop(IntCtz<u32>);
+    case O::I32Popcnt: return DoUnop(IntPopcnt<u32>);
+    case O::I32Add:    return DoBinop(Add<u32>);
+    case O::I32Sub:    return DoBinop(Sub<u32>);
+    case O::I32Mul:    return DoBinop(Mul<u32>);
+    case O::I32DivS:   return DoBinop(IntDiv<s32>, out_trap);
+    case O::I32DivU:   return DoBinop(IntDiv<u32>, out_trap);
+    case O::I32RemS:   return DoBinop(IntRem<s32>, out_trap);
+    case O::I32RemU:   return DoBinop(IntRem<u32>, out_trap);
+    case O::I32And:    return DoBinop(IntAnd<u32>);
+    case O::I32Or:     return DoBinop(IntOr<u32>);
+    case O::I32Xor:    return DoBinop(IntXor<u32>);
+    case O::I32Shl:    return DoBinop(IntShl<u32>);
+    case O::I32ShrS:   return DoBinop(IntShr<s32>);
+    case O::I32ShrU:   return DoBinop(IntShr<u32>);
+    case O::I32Rotl:   return DoBinop(IntRotl<u32>);
+    case O::I32Rotr:   return DoBinop(IntRotr<u32>);
+
+    case O::I64Clz:    return DoUnop(IntClz<u64>);
+    case O::I64Ctz:    return DoUnop(IntCtz<u64>);
+    case O::I64Popcnt: return DoUnop(IntPopcnt<u64>);
+    case O::I64Add:    return DoBinop(Add<u64>);
+    case O::I64Sub:    return DoBinop(Sub<u64>);
+    case O::I64Mul:    return DoBinop(Mul<u64>);
+    case O::I64DivS:   return DoBinop(IntDiv<s64>, out_trap);
+    case O::I64DivU:   return DoBinop(IntDiv<u64>, out_trap);
+    case O::I64RemS:   return DoBinop(IntRem<s64>, out_trap);
+    case O::I64RemU:   return DoBinop(IntRem<u64>, out_trap);
+    case O::I64And:    return DoBinop(IntAnd<u64>);
+    case O::I64Or:     return DoBinop(IntOr<u64>);
+    case O::I64Xor:    return DoBinop(IntXor<u64>);
+    case O::I64Shl:    return DoBinop(IntShl<u64>);
+    case O::I64ShrS:   return DoBinop(IntShr<s64>);
+    case O::I64ShrU:   return DoBinop(IntShr<u64>);
+    case O::I64Rotl:   return DoBinop(IntRotl<u64>);
+    case O::I64Rotr:   return DoBinop(IntRotr<u64>);
+
+    case O::F32Abs:     return DoUnop(FloatAbs<f32>);
+    case O::F32Neg:     return DoUnop(FloatNeg<f32>);
+    case O::F32Ceil:    return DoUnop(FloatCeil<f32>);
+    case O::F32Floor:   return DoUnop(FloatFloor<f32>);
+    case O::F32Trunc:   return DoUnop(FloatTrunc<f32>);
+    case O::F32Nearest: return DoUnop(FloatNearest<f32>);
+    case O::F32Sqrt:    return DoUnop(FloatSqrt<f32>);
+    case O::F32Add:      return DoBinop(Add<f32>);
+    case O::F32Sub:      return DoBinop(Sub<f32>);
+    case O::F32Mul:      return DoBinop(Mul<f32>);
+    case O::F32Div:      return DoBinop(FloatDiv<f32>);
+    case O::F32Min:      return DoBinop(FloatMin<f32>);
+    case O::F32Max:      return DoBinop(FloatMax<f32>);
+    case O::F32Copysign: return DoBinop(FloatCopysign<f32>);
+
+    case O::F64Abs:     return DoUnop(FloatAbs<f64>);
+    case O::F64Neg:     return DoUnop(FloatNeg<f64>);
+    case O::F64Ceil:    return DoUnop(FloatCeil<f64>);
+    case O::F64Floor:   return DoUnop(FloatFloor<f64>);
+    case O::F64Trunc:   return DoUnop(FloatTrunc<f64>);
+    case O::F64Nearest: return DoUnop(FloatNearest<f64>);
+    case O::F64Sqrt:    return DoUnop(FloatSqrt<f64>);
+    case O::F64Add:      return DoBinop(Add<f64>);
+    case O::F64Sub:      return DoBinop(Sub<f64>);
+    case O::F64Mul:      return DoBinop(Mul<f64>);
+    case O::F64Div:      return DoBinop(FloatDiv<f64>);
+    case O::F64Min:      return DoBinop(FloatMin<f64>);
+    case O::F64Max:      return DoBinop(FloatMax<f64>);
+    case O::F64Copysign: return DoBinop(FloatCopysign<f64>);
+
+    case O::I32WrapI64:      return DoConvert<u32, u64>(out_trap);
+    case O::I32TruncF32S:    return DoConvert<s32, f32>(out_trap);
+    case O::I32TruncF32U:    return DoConvert<u32, f32>(out_trap);
+    case O::I32TruncF64S:    return DoConvert<s32, f64>(out_trap);
+    case O::I32TruncF64U:    return DoConvert<u32, f64>(out_trap);
+    case O::I64ExtendI32S:   return DoConvert<s64, s32>(out_trap);
+    case O::I64ExtendI32U:   return DoConvert<u64, u32>(out_trap);
+    case O::I64TruncF32S:    return DoConvert<s64, f32>(out_trap);
+    case O::I64TruncF32U:    return DoConvert<u64, f32>(out_trap);
+    case O::I64TruncF64S:    return DoConvert<s64, f64>(out_trap);
+    case O::I64TruncF64U:    return DoConvert<u64, f64>(out_trap);
+    case O::F32ConvertI32S:  return DoConvert<f32, s32>(out_trap);
+    case O::F32ConvertI32U:  return DoConvert<f32, u32>(out_trap);
+    case O::F32ConvertI64S:  return DoConvert<f32, s64>(out_trap);
+    case O::F32ConvertI64U:  return DoConvert<f32, u64>(out_trap);
+    case O::F32DemoteF64:    return DoConvert<f32, f64>(out_trap);
+    case O::F64ConvertI32S:  return DoConvert<f64, s32>(out_trap);
+    case O::F64ConvertI32U:  return DoConvert<f64, u32>(out_trap);
+    case O::F64ConvertI64S:  return DoConvert<f64, s64>(out_trap);
+    case O::F64ConvertI64U:  return DoConvert<f64, u64>(out_trap);
+    case O::F64PromoteF32:   return DoConvert<f64, f32>(out_trap);
+
+    case O::I32ReinterpretF32: return DoReinterpret<u32, f32>();
+    case O::F32ReinterpretI32: return DoReinterpret<f32, u32>();
+    case O::I64ReinterpretF64: return DoReinterpret<u64, f64>();
+    case O::F64ReinterpretI64: return DoReinterpret<f64, u64>();
+
+    case O::I32Extend8S:   return DoUnop(IntExtend<u32, 7>);
+    case O::I32Extend16S:  return DoUnop(IntExtend<u32, 15>);
+    case O::I64Extend8S:   return DoUnop(IntExtend<u64, 7>);
+    case O::I64Extend16S:  return DoUnop(IntExtend<u64, 15>);
+    case O::I64Extend32S:  return DoUnop(IntExtend<u64, 31>);
+
+    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<u32>()) {
+        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<s32, f32>);
+    case O::I32TruncSatF32U: return DoUnop(IntTruncSat<u32, f32>);
+    case O::I32TruncSatF64S: return DoUnop(IntTruncSat<s32, f64>);
+    case O::I32TruncSatF64U: return DoUnop(IntTruncSat<u32, f64>);
+    case O::I64TruncSatF32S: return DoUnop(IntTruncSat<s64, f32>);
+    case O::I64TruncSatF32U: return DoUnop(IntTruncSat<u64, f32>);
+    case O::I64TruncSatF64S: return DoUnop(IntTruncSat<s64, f64>);
+    case O::I64TruncSatF64U: return DoUnop(IntTruncSat<u64, f64>);
+
+    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>() == Ref::Null);
+      break;
+
+    case O::RefFunc:
+      Push(inst_->funcs()[instr.imm_u32]);
+      break;
+
+    case O::V128Load: return DoLoad<v128>(instr, out_trap);
+    case O::V128Store: return DoStore<v128>(instr, out_trap);
+
+    case O::V128Const:
+      Push<v128>(instr.imm_v128);
+      break;
+
+    case O::I8X16Splat:        return DoSimdSplat<u8x16, u32>();
+    case O::I8X16ExtractLaneS: return DoSimdExtract<s8x16, s32>(instr);
+    case O::I8X16ExtractLaneU: return DoSimdExtract<u8x16, u32>(instr);
+    case O::I8X16ReplaceLane:  return DoSimdReplace<u8x16, u32>(instr);
+    case O::I16X8Splat:        return DoSimdSplat<u16x8, u32>();
+    case O::I16X8ExtractLaneS: return DoSimdExtract<s16x8, s32>(instr);
+    case O::I16X8ExtractLaneU: return DoSimdExtract<u16x8, u32>(instr);
+    case O::I16X8ReplaceLane:  return DoSimdReplace<u16x8, u32>(instr);
+    case O::I32X4Splat:        return DoSimdSplat<u32x4, u32>();
+    case O::I32X4ExtractLane:  return DoSimdExtract<s32x4, u32>(instr);
+    case O::I32X4ReplaceLane:  return DoSimdReplace<u32x4, u32>(instr);
+    case O::I64X2Splat:        return DoSimdSplat<u64x2, u64>();
+    case O::I64X2ExtractLane:  return DoSimdExtract<u64x2, u64>(instr);
+    case O::I64X2ReplaceLane:  return DoSimdReplace<u64x2, u64>(instr);
+    case O::F32X4Splat:        return DoSimdSplat<f32x4, f32>();
+    case O::F32X4ExtractLane:  return DoSimdExtract<f32x4, f32>(instr);
+    case O::F32X4ReplaceLane:  return DoSimdReplace<f32x4, f32>(instr);
+    case O::F64X2Splat:        return DoSimdSplat<f64x2, f64>();
+    case O::F64X2ExtractLane:  return DoSimdExtract<f64x2, f64>(instr);
+    case O::F64X2ReplaceLane:  return DoSimdReplace<f64x2, f64>(instr);
+
+    case O::I8X16Eq:  return DoSimdBinop(EqMask<u8>);
+    case O::I8X16Ne:  return DoSimdBinop(NeMask<u8>);
+    case O::I8X16LtS: return DoSimdBinop(LtMask<s8>);
+    case O::I8X16LtU: return DoSimdBinop(LtMask<u8>);
+    case O::I8X16GtS: return DoSimdBinop(GtMask<s8>);
+    case O::I8X16GtU: return DoSimdBinop(GtMask<u8>);
+    case O::I8X16LeS: return DoSimdBinop(LeMask<s8>);
+    case O::I8X16LeU: return DoSimdBinop(LeMask<u8>);
+    case O::I8X16GeS: return DoSimdBinop(GeMask<s8>);
+    case O::I8X16GeU: return DoSimdBinop(GeMask<u8>);
+    case O::I16X8Eq:  return DoSimdBinop(EqMask<u16>);
+    case O::I16X8Ne:  return DoSimdBinop(NeMask<u16>);
+    case O::I16X8LtS: return DoSimdBinop(LtMask<s16>);
+    case O::I16X8LtU: return DoSimdBinop(LtMask<u16>);
+    case O::I16X8GtS: return DoSimdBinop(GtMask<s16>);
+    case O::I16X8GtU: return DoSimdBinop(GtMask<u16>);
+    case O::I16X8LeS: return DoSimdBinop(LeMask<s16>);
+    case O::I16X8LeU: return DoSimdBinop(LeMask<u16>);
+    case O::I16X8GeS: return DoSimdBinop(GeMask<s16>);
+    case O::I16X8GeU: return DoSimdBinop(GeMask<u16>);
+    case O::I32X4Eq:  return DoSimdBinop(EqMask<u32>);
+    case O::I32X4Ne:  return DoSimdBinop(NeMask<u32>);
+    case O::I32X4LtS: return DoSimdBinop(LtMask<s32>);
+    case O::I32X4LtU: return DoSimdBinop(LtMask<u32>);
+    case O::I32X4GtS: return DoSimdBinop(GtMask<s32>);
+    case O::I32X4GtU: return DoSimdBinop(GtMask<u32>);
+    case O::I32X4LeS: return DoSimdBinop(LeMask<s32>);
+    case O::I32X4LeU: return DoSimdBinop(LeMask<u32>);
+    case O::I32X4GeS: return DoSimdBinop(GeMask<s32>);
+    case O::I32X4GeU: return DoSimdBinop(GeMask<u32>);
+    case O::F32X4Eq:  return DoSimdBinop(EqMask<f32>);
+    case O::F32X4Ne:  return DoSimdBinop(NeMask<f32>);
+    case O::F32X4Lt:  return DoSimdBinop(LtMask<f32>);
+    case O::F32X4Gt:  return DoSimdBinop(GtMask<f32>);
+    case O::F32X4Le:  return DoSimdBinop(LeMask<f32>);
+    case O::F32X4Ge:  return DoSimdBinop(GeMask<f32>);
+    case O::F64X2Eq:  return DoSimdBinop(EqMask<f64>);
+    case O::F64X2Ne:  return DoSimdBinop(NeMask<f64>);
+    case O::F64X2Lt:  return DoSimdBinop(LtMask<f64>);
+    case O::F64X2Gt:  return DoSimdBinop(GtMask<f64>);
+    case O::F64X2Le:  return DoSimdBinop(LeMask<f64>);
+    case O::F64X2Ge:  return DoSimdBinop(GeMask<f64>);
+
+    case O::V128Not:       return DoSimdUnop(IntNot<u64>);
+    case O::V128And:       return DoSimdBinop(IntAnd<u64>);
+    case O::V128Or:        return DoSimdBinop(IntOr<u64>);
+    case O::V128Xor:       return DoSimdBinop(IntXor<u64>);
+    case O::V128BitSelect: return DoSimdBitSelect();
+
+    case O::I8X16Neg:          return DoSimdUnop(IntNeg<u8>);
+    case O::I8X16AnyTrue:      return DoSimdIsTrue<u8x16, 1>();
+    case O::I8X16Bitmask:      return DoSimdBitmask<s8x16>();
+    case O::I8X16AllTrue:      return DoSimdIsTrue<u8x16, 16>();
+    case O::I8X16Shl:          return DoSimdShift(IntShl<u8>);
+    case O::I8X16ShrS:         return DoSimdShift(IntShr<s8>);
+    case O::I8X16ShrU:         return DoSimdShift(IntShr<u8>);
+    case O::I8X16Add:          return DoSimdBinop(Add<u8>);
+    case O::I8X16AddSatS:      return DoSimdBinop(IntAddSat<s8>);
+    case O::I8X16AddSatU:      return DoSimdBinop(IntAddSat<u8>);
+    case O::I8X16Sub:          return DoSimdBinop(Sub<u8>);
+    case O::I8X16SubSatS:      return DoSimdBinop(IntSubSat<s8>);
+    case O::I8X16SubSatU:      return DoSimdBinop(IntSubSat<u8>);
+    case O::I8X16MinS:         return DoSimdBinop(IntMin<s8>);
+    case O::I8X16MinU:         return DoSimdBinop(IntMin<u8>);
+    case O::I8X16MaxS:         return DoSimdBinop(IntMax<s8>);
+    case O::I8X16MaxU:         return DoSimdBinop(IntMax<u8>);
+
+    case O::I16X8Neg:          return DoSimdUnop(IntNeg<u16>);
+    case O::I16X8AnyTrue:      return DoSimdIsTrue<u16x8, 1>();
+    case O::I16X8Bitmask:      return DoSimdBitmask<s16x8>();
+    case O::I16X8AllTrue:      return DoSimdIsTrue<u16x8, 8>();
+    case O::I16X8Shl:          return DoSimdShift(IntShl<u16>);
+    case O::I16X8ShrS:         return DoSimdShift(IntShr<s16>);
+    case O::I16X8ShrU:         return DoSimdShift(IntShr<u16>);
+    case O::I16X8Add:          return DoSimdBinop(Add<u16>);
+    case O::I16X8AddSatS:      return DoSimdBinop(IntAddSat<s16>);
+    case O::I16X8AddSatU:      return DoSimdBinop(IntAddSat<u16>);
+    case O::I16X8Sub:          return DoSimdBinop(Sub<u16>);
+    case O::I16X8SubSatS:      return DoSimdBinop(IntSubSat<s16>);
+    case O::I16X8SubSatU:      return DoSimdBinop(IntSubSat<u16>);
+    case O::I16X8Mul:          return DoSimdBinop(Mul<u16>);
+    case O::I16X8MinS:         return DoSimdBinop(IntMin<s16>);
+    case O::I16X8MinU:         return DoSimdBinop(IntMin<u16>);
+    case O::I16X8MaxS:         return DoSimdBinop(IntMax<s16>);
+    case O::I16X8MaxU:         return DoSimdBinop(IntMax<u16>);
+
+    case O::I32X4Neg:          return DoSimdUnop(IntNeg<u32>);
+    case O::I32X4AnyTrue:      return DoSimdIsTrue<u32x4, 1>();
+    case O::I32X4Bitmask:      return DoSimdBitmask<s32x4>();
+    case O::I32X4AllTrue:      return DoSimdIsTrue<u32x4, 4>();
+    case O::I32X4Shl:          return DoSimdShift(IntShl<u32>);
+    case O::I32X4ShrS:         return DoSimdShift(IntShr<s32>);
+    case O::I32X4ShrU:         return DoSimdShift(IntShr<u32>);
+    case O::I32X4Add:          return DoSimdBinop(Add<u32>);
+    case O::I32X4Sub:          return DoSimdBinop(Sub<u32>);
+    case O::I32X4Mul:          return DoSimdBinop(Mul<u32>);
+    case O::I32X4MinS:         return DoSimdBinop(IntMin<s32>);
+    case O::I32X4MinU:         return DoSimdBinop(IntMin<u32>);
+    case O::I32X4MaxS:         return DoSimdBinop(IntMax<s32>);
+    case O::I32X4MaxU:         return DoSimdBinop(IntMax<u32>);
+
+    case O::I64X2Neg:          return DoSimdUnop(IntNeg<u64>);
+    case O::I64X2Shl:          return DoSimdShift(IntShl<u64>);
+    case O::I64X2ShrS:         return DoSimdShift(IntShr<s64>);
+    case O::I64X2ShrU:         return DoSimdShift(IntShr<u64>);
+    case O::I64X2Add:          return DoSimdBinop(Add<u64>);
+    case O::I64X2Sub:          return DoSimdBinop(Sub<u64>);
+    case O::I64X2Mul:          return DoSimdBinop(Mul<u64>);
+
+    case O::F32X4Ceil:         return DoSimdUnop(FloatCeil<f32>);
+    case O::F32X4Floor:        return DoSimdUnop(FloatFloor<f32>);
+    case O::F32X4Trunc:        return DoSimdUnop(FloatTrunc<f32>);
+    case O::F32X4Nearest:      return DoSimdUnop(FloatNearest<f32>);
+
+    case O::F64X2Ceil:         return DoSimdUnop(FloatCeil<f64>);
+    case O::F64X2Floor:        return DoSimdUnop(FloatFloor<f64>);
+    case O::F64X2Trunc:        return DoSimdUnop(FloatTrunc<f64>);
+    case O::F64X2Nearest:      return DoSimdUnop(FloatNearest<f64>);
+
+    case O::F32X4Abs:          return DoSimdUnop(FloatAbs<f32>);
+    case O::F32X4Neg:          return DoSimdUnop(FloatNeg<f32>);
+    case O::F32X4Sqrt:         return DoSimdUnop(FloatSqrt<f32>);
+    case O::F32X4Add:          return DoSimdBinop(Add<f32>);
+    case O::F32X4Sub:          return DoSimdBinop(Sub<f32>);
+    case O::F32X4Mul:          return DoSimdBinop(Mul<f32>);
+    case O::F32X4Div:          return DoSimdBinop(FloatDiv<f32>);
+    case O::F32X4Min:          return DoSimdBinop(FloatMin<f32>);
+    case O::F32X4Max:          return DoSimdBinop(FloatMax<f32>);
+    case O::F32X4PMin:         return DoSimdBinop(FloatPMin<f32>);
+    case O::F32X4PMax:         return DoSimdBinop(FloatPMax<f32>);
+
+    case O::F64X2Abs:          return DoSimdUnop(FloatAbs<f64>);
+    case O::F64X2Neg:          return DoSimdUnop(FloatNeg<f64>);
+    case O::F64X2Sqrt:         return DoSimdUnop(FloatSqrt<f64>);
+    case O::F64X2Add:          return DoSimdBinop(Add<f64>);
+    case O::F64X2Sub:          return DoSimdBinop(Sub<f64>);
+    case O::F64X2Mul:          return DoSimdBinop(Mul<f64>);
+    case O::F64X2Div:          return DoSimdBinop(FloatDiv<f64>);
+    case O::F64X2Min:          return DoSimdBinop(FloatMin<f64>);
+    case O::F64X2Max:          return DoSimdBinop(FloatMax<f64>);
+    case O::F64X2PMin:         return DoSimdBinop(FloatPMin<f64>);
+    case O::F64X2PMax:         return DoSimdBinop(FloatPMax<f64>);
+
+    case O::I32X4TruncSatF32X4S: return DoSimdUnop(IntTruncSat<s32, f32>);
+    case O::I32X4TruncSatF32X4U: return DoSimdUnop(IntTruncSat<u32, f32>);
+    case O::F32X4ConvertI32X4S:  return DoSimdUnop(Convert<f32, s32>);
+    case O::F32X4ConvertI32X4U:  return DoSimdUnop(Convert<f32, u32>);
+
+    case O::I8X16Swizzle:     return DoSimdSwizzle();
+    case O::I8X16Shuffle:     return DoSimdShuffle(instr);
+
+    case O::V128Load8Splat:    return DoSimdLoadSplat<u8x16, u32>(instr, out_trap);
+    case O::V128Load16Splat:   return DoSimdLoadSplat<u16x8, u32>(instr, out_trap);
+    case O::V128Load32Splat:   return DoSimdLoadSplat<u32x4, u32>(instr, out_trap);
+    case O::V128Load64Splat:   return DoSimdLoadSplat<u64x2, u64>(instr, out_trap);
+
+    case O::I8X16NarrowI16X8S:    return DoSimdNarrow<s8x16, s16x8>();
+    case O::I8X16NarrowI16X8U:    return DoSimdNarrow<u8x16, s16x8>();
+    case O::I16X8NarrowI32X4S:    return DoSimdNarrow<s16x8, s32x4>();
+    case O::I16X8NarrowI32X4U:    return DoSimdNarrow<u16x8, s32x4>();
+    case O::I16X8WidenLowI8X16S:  return DoSimdWiden<s16x8, s8x16, true>();
+    case O::I16X8WidenHighI8X16S: return DoSimdWiden<s16x8, s8x16, false>();
+    case O::I16X8WidenLowI8X16U:  return DoSimdWiden<u16x8, u8x16, true>();
+    case O::I16X8WidenHighI8X16U: return DoSimdWiden<u16x8, u8x16, false>();
+    case O::I32X4WidenLowI16X8S:  return DoSimdWiden<s32x4, s16x8, true>();
+    case O::I32X4WidenHighI16X8S: return DoSimdWiden<s32x4, s16x8, false>();
+    case O::I32X4WidenLowI16X8U:  return DoSimdWiden<u32x4, u16x8, true>();
+    case O::I32X4WidenHighI16X8U: return DoSimdWiden<u32x4, u16x8, false>();
+
+    case O::V128Load8X8S:  return DoSimdLoadExtend<s16x8, s8x8>(instr, out_trap);
+    case O::V128Load8X8U:  return DoSimdLoadExtend<u16x8, u8x8>(instr, out_trap);
+    case O::V128Load16X4S: return DoSimdLoadExtend<s32x4, s16x4>(instr, out_trap);
+    case O::V128Load16X4U: return DoSimdLoadExtend<u32x4, u16x4>(instr, out_trap);
+    case O::V128Load32X2S: return DoSimdLoadExtend<s64x2, s32x2>(instr, out_trap);
+    case O::V128Load32X2U: return DoSimdLoadExtend<u64x2, u32x2>(instr, out_trap);
+
+    case O::V128Andnot: return DoSimdBinop(IntAndNot<u64>);
+    case O::I8X16AvgrU: return DoSimdBinop(IntAvgr<u8>);
+    case O::I16X8AvgrU: return DoSimdBinop(IntAvgr<u16>);
+
+    case O::I8X16Abs: return DoSimdUnop(IntAbs<u8>);
+    case O::I16X8Abs: return DoSimdUnop(IntAbs<u16>);
+    case O::I32X4Abs: return DoSimdUnop(IntAbs<u32>);
+
+    case O::AtomicFence:
+    case O::MemoryAtomicNotify:
+    case O::MemoryAtomicWait32:
+    case O::MemoryAtomicWait64:
+      return TRAP("not implemented");
+
+    case O::I32AtomicLoad:       return DoAtomicLoad<u32>(instr, out_trap);
+    case O::I64AtomicLoad:       return DoAtomicLoad<u64>(instr, out_trap);
+    case O::I32AtomicLoad8U:     return DoAtomicLoad<u32, u8>(instr, out_trap);
+    case O::I32AtomicLoad16U:    return DoAtomicLoad<u32, u16>(instr, out_trap);
+    case O::I64AtomicLoad8U:     return DoAtomicLoad<u64, u8>(instr, out_trap);
+    case O::I64AtomicLoad16U:    return DoAtomicLoad<u64, u16>(instr, out_trap);
+    case O::I64AtomicLoad32U:    return DoAtomicLoad<u64, u32>(instr, out_trap);
+    case O::I32AtomicStore:      return DoAtomicStore<u32>(instr, out_trap);
+    case O::I64AtomicStore:      return DoAtomicStore<u64>(instr, out_trap);
+    case O::I32AtomicStore8:     return DoAtomicStore<u32, u8>(instr, out_trap);
+    case O::I32AtomicStore16:    return DoAtomicStore<u32, u16>(instr, out_trap);
+    case O::I64AtomicStore8:     return DoAtomicStore<u64, u8>(instr, out_trap);
+    case O::I64AtomicStore16:    return DoAtomicStore<u64, u16>(instr, out_trap);
+    case O::I64AtomicStore32:    return DoAtomicStore<u64, u32>(instr, out_trap);
+    case O::I32AtomicRmwAdd:     return DoAtomicRmw<u32>(Add<u32>, instr, out_trap);
+    case O::I64AtomicRmwAdd:     return DoAtomicRmw<u64>(Add<u64>, instr, out_trap);
+    case O::I32AtomicRmw8AddU:   return DoAtomicRmw<u32>(Add<u8>, instr, out_trap);
+    case O::I32AtomicRmw16AddU:  return DoAtomicRmw<u32>(Add<u16>, instr, out_trap);
+    case O::I64AtomicRmw8AddU:   return DoAtomicRmw<u64>(Add<u8>, instr, out_trap);
+    case O::I64AtomicRmw16AddU:  return DoAtomicRmw<u64>(Add<u16>, instr, out_trap);
+    case O::I64AtomicRmw32AddU:  return DoAtomicRmw<u64>(Add<u32>, instr, out_trap);
+    case O::I32AtomicRmwSub:     return DoAtomicRmw<u32>(Sub<u32>, instr, out_trap);
+    case O::I64AtomicRmwSub:     return DoAtomicRmw<u64>(Sub<u64>, instr, out_trap);
+    case O::I32AtomicRmw8SubU:   return DoAtomicRmw<u32>(Sub<u8>, instr, out_trap);
+    case O::I32AtomicRmw16SubU:  return DoAtomicRmw<u32>(Sub<u16>, instr, out_trap);
+    case O::I64AtomicRmw8SubU:   return DoAtomicRmw<u64>(Sub<u8>, instr, out_trap);
+    case O::I64AtomicRmw16SubU:  return DoAtomicRmw<u64>(Sub<u16>, instr, out_trap);
+    case O::I64AtomicRmw32SubU:  return DoAtomicRmw<u64>(Sub<u32>, instr, out_trap);
+    case O::I32AtomicRmwAnd:     return DoAtomicRmw<u32>(IntAnd<u32>, instr, out_trap);
+    case O::I64AtomicRmwAnd:     return DoAtomicRmw<u64>(IntAnd<u64>, instr, out_trap);
+    case O::I32AtomicRmw8AndU:   return DoAtomicRmw<u32>(IntAnd<u8>, instr, out_trap);
+    case O::I32AtomicRmw16AndU:  return DoAtomicRmw<u32>(IntAnd<u16>, instr, out_trap);
+    case O::I64AtomicRmw8AndU:   return DoAtomicRmw<u64>(IntAnd<u8>, instr, out_trap);
+    case O::I64AtomicRmw16AndU:  return DoAtomicRmw<u64>(IntAnd<u16>, instr, out_trap);
+    case O::I64AtomicRmw32AndU:  return DoAtomicRmw<u64>(IntAnd<u32>, instr, out_trap);
+    case O::I32AtomicRmwOr:      return DoAtomicRmw<u32>(IntOr<u32>, instr, out_trap);
+    case O::I64AtomicRmwOr:      return DoAtomicRmw<u64>(IntOr<u64>, instr, out_trap);
+    case O::I32AtomicRmw8OrU:    return DoAtomicRmw<u32>(IntOr<u8>, instr, out_trap);
+    case O::I32AtomicRmw16OrU:   return DoAtomicRmw<u32>(IntOr<u16>, instr, out_trap);
+    case O::I64AtomicRmw8OrU:    return DoAtomicRmw<u64>(IntOr<u8>, instr, out_trap);
+    case O::I64AtomicRmw16OrU:   return DoAtomicRmw<u64>(IntOr<u16>, instr, out_trap);
+    case O::I64AtomicRmw32OrU:   return DoAtomicRmw<u64>(IntOr<u32>, instr, out_trap);
+    case O::I32AtomicRmwXor:     return DoAtomicRmw<u32>(IntXor<u32>, instr, out_trap);
+    case O::I64AtomicRmwXor:     return DoAtomicRmw<u64>(IntXor<u64>, instr, out_trap);
+    case O::I32AtomicRmw8XorU:   return DoAtomicRmw<u32>(IntXor<u8>, instr, out_trap);
+    case O::I32AtomicRmw16XorU:  return DoAtomicRmw<u32>(IntXor<u16>, instr, out_trap);
+    case O::I64AtomicRmw8XorU:   return DoAtomicRmw<u64>(IntXor<u8>, instr, out_trap);
+    case O::I64AtomicRmw16XorU:  return DoAtomicRmw<u64>(IntXor<u16>, instr, out_trap);
+    case O::I64AtomicRmw32XorU:  return DoAtomicRmw<u64>(IntXor<u32>, instr, out_trap);
+    case O::I32AtomicRmwXchg:    return DoAtomicRmw<u32>(Xchg<u32>, instr, out_trap);
+    case O::I64AtomicRmwXchg:    return DoAtomicRmw<u64>(Xchg<u64>, instr, out_trap);
+    case O::I32AtomicRmw8XchgU:  return DoAtomicRmw<u32>(Xchg<u8>, instr, out_trap);
+    case O::I32AtomicRmw16XchgU: return DoAtomicRmw<u32>(Xchg<u16>, instr, out_trap);
+    case O::I64AtomicRmw8XchgU:  return DoAtomicRmw<u64>(Xchg<u8>, instr, out_trap);
+    case O::I64AtomicRmw16XchgU: return DoAtomicRmw<u64>(Xchg<u16>, instr, out_trap);
+    case O::I64AtomicRmw32XchgU: return DoAtomicRmw<u64>(Xchg<u32>, instr, out_trap);
+
+    case O::I32AtomicRmwCmpxchg:    return DoAtomicRmwCmpxchg<u32>(instr, out_trap);
+    case O::I64AtomicRmwCmpxchg:    return DoAtomicRmwCmpxchg<u64>(instr, out_trap);
+    case O::I32AtomicRmw8CmpxchgU:  return DoAtomicRmwCmpxchg<u32, u8>(instr, out_trap);
+    case O::I32AtomicRmw16CmpxchgU: return DoAtomicRmwCmpxchg<u32, u16>(instr, out_trap);
+    case O::I64AtomicRmw8CmpxchgU:  return DoAtomicRmwCmpxchg<u64, u8>(instr, out_trap);
+    case O::I64AtomicRmw16CmpxchgU: return DoAtomicRmwCmpxchg<u64, u16>(instr, out_trap);
+    case O::I64AtomicRmw32CmpxchgU: return DoAtomicRmwCmpxchg<u64, u32>(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<HostFunc>(func.get())) {
+    auto& func_type = host_func->type();
+
+    Values params;
+    PopValues(func_type.params, &params);
+    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<DefinedFunc>(func.get()), out_trap) == RunResult::Trap) {
+      return RunResult::Ok;
+    }
+  }
+  return RunResult::Ok;
+}
+
+template <typename T>
+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 <typename T, typename V>
+RunResult Thread::DoLoad(Instr instr, Trap::Ptr* out_trap) {
+  V val;
+  if (Load<V>(instr, &val, out_trap) != RunResult::Ok) {
+    return RunResult::Trap;
+  }
+  Push(static_cast<T>(val));
+  return RunResult::Ok;
+}
+
+template <typename T, typename V>
+RunResult Thread::DoStore(Instr instr, Trap::Ptr* out_trap) {
+  Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]};
+  V val = static_cast<V>(Pop<T>());
+  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 <typename R, typename T>
+RunResult Thread::DoUnop(UnopFunc<R, T> f) {
+  Push<R>(f(Pop<T>()));
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoUnop(UnopTrapFunc<R, T> f, Trap::Ptr* out_trap) {
+  T out;
+  std::string msg;
+  TRAP_IF(f(Pop<T>(), &out, &msg) == RunResult::Trap, msg);
+  Push<R>(out);
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoBinop(BinopFunc<R, T> f) {
+  auto rhs = Pop<T>();
+  auto lhs = Pop<T>();
+  Push<R>(f(lhs, rhs));
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoBinop(BinopTrapFunc<R, T> f, Trap::Ptr* out_trap) {
+  auto rhs = Pop<T>();
+  auto lhs = Pop<T>();
+  T out;
+  std::string msg;
+  TRAP_IF(f(lhs, rhs, &out, &msg) == RunResult::Trap, msg);
+  Push<R>(out);
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoConvert(Trap::Ptr* out_trap) {
+  auto val = Pop<T>();
+  if (std::is_integral<R>::value && std::is_floating_point<T>::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<R>(val), "integer overflow");
+  Push<R>(Convert<R>(val));
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoReinterpret() {
+  Push(Bitcast<R>(Pop<T>()));
+  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<u32>();
+  auto src = Pop<u32>();
+  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<u32>();
+  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<u32>();
+  auto src = Pop<u32>();
+  auto dst = Pop<u32>();
+  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<u32>();
+  auto src = Pop<u32>();
+  auto dst = Pop<u32>();
+  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<u32>();
+  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<Ref>();
+  auto index = Pop<u32>();
+  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<u32>();
+  auto ref = Pop<Ref>();
+  if (Failed(table->Grow(store_, delta, ref))) {
+    Push<s32>(-1);
+  } else {
+    Push<u32>(old_size);
+  }
+  return RunResult::Ok;
+}
+
+RunResult Thread::DoTableSize(Instr instr) {
+  Table::Ptr table{store_, inst_->tables()[instr.imm_u32]};
+  Push<u32>(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<u32>();
+  auto value = Pop<Ref>();
+  auto dst = Pop<u32>();
+  TRAP_IF(Failed(table->Fill(store_, dst, value, size)),
+          "out of bounds table access: table.fill out of bounds");
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoSimdSplat() {
+  auto val = Pop<T>();
+  R result;
+  std::fill(std::begin(result.v), std::end(result.v), val);
+  Push(result);
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoSimdExtract(Instr instr) {
+  Push<T>(Pop<R>()[instr.imm_u8]);
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoSimdReplace(Instr instr) {
+  auto val = Pop<T>();
+  auto simd = Pop<R>();
+  simd[instr.imm_u8] = val;
+  Push(simd);
+  return RunResult::Ok;
+}
+
+template <typename T> struct Simd128;
+template <> struct Simd128<s8> { using Type = s8x16; };
+template <> struct Simd128<u8> { using Type = u8x16; };
+template <> struct Simd128<s16> { using Type = s16x8; };
+template <> struct Simd128<u16> { using Type = u16x8; };
+template <> struct Simd128<s32> { using Type = s32x4; };
+template <> struct Simd128<u32> { using Type = u32x4; };
+template <> struct Simd128<s64> { using Type = s64x2; };
+template <> struct Simd128<u64> { using Type = u64x2; };
+template <> struct Simd128<f32> { using Type = f32x4; };
+template <> struct Simd128<f64> { using Type = f64x2; };
+
+template <typename R, typename T>
+RunResult Thread::DoSimdUnop(UnopFunc<R, T> f) {
+  using ST = typename Simd128<T>::Type;
+  using SR = typename Simd128<R>::Type;
+  auto val = Pop<ST>();
+  SR result;
+  std::transform(std::begin(val.v), std::end(val.v), std::begin(result.v), f);
+  Push(result);
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoSimdBinop(BinopFunc<R, T> f) {
+  using ST = typename Simd128<T>::Type;
+  using SR = typename Simd128<R>::Type;
+  static_assert(ST::lanes == SR::lanes, "SIMD lanes don't match");
+  auto rhs = Pop<ST>();
+  auto lhs = Pop<ST>();
+  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<S>();
+  auto rhs = Pop<S>();
+  auto lhs = Pop<S>();
+  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 <typename S, u8 count>
+RunResult Thread::DoSimdIsTrue() {
+  using L = typename S::LaneType;
+  auto val = Pop<S>();
+  Push(std::count_if(std::begin(val.v), std::end(val.v),
+                     [](L x) { return x != 0; }) >= count);
+  return RunResult::Ok;
+}
+
+template <typename S>
+RunResult Thread::DoSimdBitmask() {
+  auto val = Pop<S>();
+  u32 result = 0;
+  for (u8 i = 0; i < S::lanes; ++i) {
+    if (val[i] < 0) {
+      result |= 1 << i;
+    }
+  }
+  Push(result);
+  return RunResult::Ok;
+}
+
+template <typename R, typename T>
+RunResult Thread::DoSimdShift(BinopFunc<R, T> f) {
+  using ST = typename Simd128<T>::Type;
+  using SR = typename Simd128<R>::Type;
+  static_assert(ST::lanes == SR::lanes, "SIMD lanes don't match");
+  auto amount = Pop<u32>();
+  auto lhs = Pop<ST>();
+  SR result;
+  for (u8 i = 0; i < SR::lanes; ++i) {
+    result[i] = f(lhs[i], amount);
+  }
+  Push(result);
+  return RunResult::Ok;
+}
+
+template <typename S, typename T>
+RunResult Thread::DoSimdLoadSplat(Instr instr, Trap::Ptr* out_trap) {
+  using L = typename S::LaneType;
+  L val;
+  if (Load<L>(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<S>();
+  auto lhs = Pop<S>();
+  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<S>(instr.imm_v128);
+  auto rhs = Pop<S>();
+  auto lhs = Pop<S>();
+  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 <typename S, typename T>
+RunResult Thread::DoSimdNarrow() {
+  using SL = typename S::LaneType;
+  using TL = typename T::LaneType;
+  auto rhs = Pop<T>();
+  auto lhs = Pop<T>();
+  S result;
+  for (u8 i = 0; i < T::lanes; ++i) {
+    result[i] = Saturate<SL, TL>(lhs[i]);
+  }
+  for (u8 i = 0; i < T::lanes; ++i) {
+    result[T::lanes + i] = Saturate<SL, TL>(rhs[i]);
+  }
+  Push(result);
+  return RunResult::Ok;
+}
+
+template <typename S, typename T, bool low>
+RunResult Thread::DoSimdWiden() {
+  auto val = Pop<T>();
+  S result;
+  for (u8 i = 0; i < S::lanes; ++i) {
+    result[i] = val[(low ? 0 : S::lanes) + i];
+  }
+  Push(result);
+  return RunResult::Ok;
+}
+
+template <typename S, typename T>
+RunResult Thread::DoSimdLoadExtend(Instr instr, Trap::Ptr* out_trap) {
+  T val;
+  if (Load<T>(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 <typename T, typename V>
+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<T>(val));
+  return RunResult::Ok;
+}
+
+template <typename T, typename V>
+RunResult Thread::DoAtomicStore(Instr instr, Trap::Ptr* out_trap) {
+  Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]};
+  V val = static_cast<V>(Pop<T>());
+  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 <typename R, typename T>
+RunResult Thread::DoAtomicRmw(BinopFunc<T, T> f,
+                              Instr instr,
+                              Trap::Ptr* out_trap) {
+  Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]};
+  T val = static_cast<T>(Pop<R>());
+  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<R>(old));
+  return RunResult::Ok;
+}
+
+template <typename T, typename V>
+RunResult Thread::DoAtomicRmwCmpxchg(Instr instr, Trap::Ptr* out_trap) {
+  Memory::Ptr memory{store_, inst_->memories()[instr.imm_u32x2.fst]};
+  V replace = static_cast<V>(Pop<T>());
+  V expect = static_cast<V>(Pop<T>());
+  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<T>(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<u32>());
+    case ValueType::I64: return StringPrintf("%" PRIu64, val.Get<u64>());
+    case ValueType::F32: return StringPrintf("%g", val.Get<f32>());
+    case ValueType::F64: return StringPrintf("%g", val.Get<f64>());
+    case ValueType::V128: {
+      auto v = val.Get<v128>();
+      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<Ref>().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 (file)
index 0000000..95d8908
--- /dev/null
@@ -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 <cstdint>
+#include <functional>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#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 <typename T> 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<u8>;
+
+using ValueType = wabt::Type;
+using ValueTypes = std::vector<ValueType>;
+
+template <typename T> bool HasType(ValueType);
+template <typename T> 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<Ref>;
+
+template <typename T, u8 L>
+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<s8, 16>;
+using u8x16 = Simd<u8, 16>;
+using s16x8 = Simd<s16, 8>;
+using u16x8 = Simd<u16, 8>;
+using s32x4 = Simd<s32, 4>;
+using u32x4 = Simd<u32, 4>;
+using s64x2 = Simd<s64, 2>;
+using u64x2 = Simd<u64, 2>;
+using f32x4 = Simd<f32, 4>;
+using f64x2 = Simd<f64, 2>;
+
+// Used for load extend instructions.
+using s8x8 = Simd<s8, 8>;
+using u8x8 = Simd<u8, 8>;
+using s16x4 = Simd<s16, 4>;
+using u16x4 = Simd<u16, 4>;
+using s32x2 = Simd<s32, 2>;
+using u32x2 = Simd<u32, 2>;
+
+//// 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<ExternType> 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<ExternType> 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<ExternType> 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<ExternType> 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<ExternType> 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<ExternType> 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<ExternType>);
+  ImportType(const ImportType&);
+  ImportType& operator=(const ImportType&);
+
+  std::string module;
+  std::string name;
+  std::unique_ptr<ExternType> type;
+};
+
+struct ExportType {
+  explicit ExportType(std::string name, std::unique_ptr<ExternType>);
+  ExportType(const ExportType&);
+  ExportType& operator=(const ExportType&);
+
+  std::string name;
+  std::unique_ptr<ExternType> 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<LocalDesc> 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<ElemExpr> elements;
+  ValueType type;
+  SegmentMode mode;
+  Index table_index;
+  InitExpr offset;
+};
+
+struct ModuleDesc {
+  std::vector<FuncType> func_types;
+  std::vector<ImportDesc> imports;
+  std::vector<FuncDesc> funcs;
+  std::vector<TableDesc> tables;
+  std::vector<MemoryDesc> memories;
+  std::vector<GlobalDesc> globals;
+  std::vector<EventDesc> events;
+  std::vector<ExportDesc> exports;
+  std::vector<StartDesc> starts;
+  std::vector<ElemDesc> elems;
+  std::vector<DataDesc> 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 <typename T>
+class FreeList {
+ public:
+  using Index = size_t;
+
+  template <typename... Args>
+  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<T> list_;
+  std::vector<size_t> free_;
+  std::vector<bool> is_free_;
+};
+
+class Store {
+ public:
+  using ObjectList = FreeList<std::unique_ptr<Object>>;
+  using RootList = FreeList<Ref>;
+
+  explicit Store(const Features& = Features{});
+
+  bool IsValid(Ref) const;
+  bool HasValueType(Ref, ValueType) const;
+  template <typename T>
+  bool Is(Ref) const;
+
+  template <typename T, typename... Args>
+  RefPtr<T> Alloc(Args&&...);
+  template <typename T>
+  Result Get(Ref, RefPtr<T>* out);
+  template <typename T>
+  RefPtr<T> 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 <typename T>
+  friend class RefPtr;
+
+  Features features_;
+  ObjectList objects_;
+  RootList roots_;
+  std::vector<bool> marks_;
+};
+
+template <typename T>
+class RefPtr {
+ public:
+  RefPtr();
+  RefPtr(Store&, Ref);
+  RefPtr(const RefPtr&);
+  RefPtr& operator=(const RefPtr&);
+  RefPtr(RefPtr&&);
+  RefPtr& operator=(RefPtr&&);
+  ~RefPtr();
+
+  template <typename U>
+  RefPtr(const RefPtr<U>&);
+  template <typename U>
+  RefPtr& operator=(const RefPtr<U>&);
+  template <typename U>
+  RefPtr(RefPtr&&);
+  template <typename U>
+  RefPtr& operator=(RefPtr&&);
+
+  template <typename U>
+  RefPtr<U> 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 <typename U, typename V>
+  friend bool operator==(const RefPtr<U>& lhs, const RefPtr<V>& rhs);
+  template <typename U, typename V>
+  friend bool operator!=(const RefPtr<U>& lhs, const RefPtr<V>& rhs);
+
+ private:
+  template <typename U>
+  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 <typename T, u8 L>
+  static Value WABT_VECTORCALL Make(Simd<T, L>);
+
+  template <typename T>
+  T WABT_VECTORCALL Get() const;
+  template <typename T>
+  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<Value>;
+
+struct TypedValue {
+  ValueType type;
+  Value value;
+};
+using TypedValues = std::vector<TypedValue>;
+
+using Finalizer = std::function<void(Object*)>;
+
+class Object {
+ public:
+  static bool classof(const Object* obj);
+  static const char* GetTypeName() { return "Object"; }
+  using Ptr = RefPtr<Object>;
+
+  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<Foreign>;
+
+  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<Trap>;
+
+  static Trap::Ptr New(Store&,
+                       const std::string& msg,
+                       const std::vector<Frame>& trace = std::vector<Frame>());
+
+  std::string message() const;
+
+ private:
+  friend Store;
+  explicit Trap(Store&,
+                const std::string& msg,
+                const std::vector<Frame>& trace = std::vector<Frame>());
+  void Mark(Store&) override;
+
+  std::string message_;
+  std::vector<Frame> trace_;
+};
+
+class Extern : public Object {
+ public:
+  static bool classof(const Object* obj);
+  static const char* GetTypeName() { return "Foreign"; }
+  using Ptr = RefPtr<Extern>;
+
+  virtual Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) = 0;
+  virtual const ExternType& extern_type() = 0;
+
+ protected:
+  friend Store;
+  explicit Extern(ObjectKind);
+
+  template <typename T>
+  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<Func>;
+
+  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<DefinedFunc>;
+
+  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<HostFunc>;
+
+  using Callback = std::function<Result(Thread& thread,
+                                        const Values& params,
+                                        Values& results,
+                                        Trap::Ptr* out_trap)>;
+
+  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<Table>;
+
+  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<Memory>;
+
+  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 <typename T>
+  Result Load(u64 offset, u64 addend, T* out) const;
+  template <typename T>
+  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 <typename T>
+  Result AtomicLoad(u64 offset, u64 addend, T* out) const;
+  template <typename T>
+  Result AtomicStore(u64 offset, u64 addend, T);
+  template <typename T, typename F>
+  Result AtomicRmw(u64 offset, u64 addend, T, F&& func, T* out);
+  template <typename T>
+  Result AtomicRmwCmpxchg(u64 offset, u64 addend, T expect, T replace, T* out);
+
+  u64 ByteSize() const;
+  u64 PageSize() const;
+
+  // Unsafe API.
+  template <typename T>
+  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<Global>;
+
+  static Global::Ptr New(Store&, GlobalType, Value);
+
+  Result Match(Store&, const ImportType&, Trap::Ptr* out_trap) override;
+
+  Value Get() const;
+  template <typename T>
+  Result Get(T* out) const;
+  template <typename T>
+  Result WABT_VECTORCALL Set(T);
+  Result Set(Store&, Ref);
+
+  template <typename T>
+  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<Event>;
+
+  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<Instance>&);
+
+  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<Module>;
+
+  static Module::Ptr New(Store&, ModuleDesc);
+
+  const ModuleDesc& desc() const;
+  const std::vector<ImportType>& import_types() const;
+  const std::vector<ExportType>& export_types() const;
+
+ private:
+  friend Store;
+  friend Instance;
+  explicit Module(Store&, ModuleDesc);
+  void Mark(Store&) override;
+
+  ModuleDesc desc_;
+  std::vector<ImportType> import_types_;
+  std::vector<ExportType> 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<Instance>;
+
+  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<ElemSegment>& elems() const;
+  std::vector<ElemSegment>& elems();
+  const std::vector<DataSegment>& datas() const;
+  std::vector<DataSegment>& 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<ElemSegment> elems_;
+  std::vector<DataSegment> 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<Thread>;
+
+  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 <typename T>
+  T WABT_VECTORCALL Pop();
+  Value Pop();
+  u64 PopPtr(const Memory::Ptr& memory);
+
+  template <typename T>
+  void WABT_VECTORCALL Push(T);
+  void Push(Value);
+  void Push(Ref);
+
+  template <typename R, typename T>
+  using UnopFunc = R WABT_VECTORCALL(T);
+  template <typename R, typename T>
+  using UnopTrapFunc = RunResult WABT_VECTORCALL(T, R*, std::string*);
+  template <typename R, typename T>
+  using BinopFunc = R WABT_VECTORCALL(T, T);
+  template <typename R, typename T>
+  using BinopTrapFunc = RunResult WABT_VECTORCALL(T, T, R*, std::string*);
+
+  template <typename R, typename T>
+  RunResult DoUnop(UnopFunc<R, T>);
+  template <typename R, typename T>
+  RunResult DoUnop(UnopTrapFunc<R, T>, Trap::Ptr* out_trap);
+  template <typename R, typename T>
+  RunResult DoBinop(BinopFunc<R, T>);
+  template <typename R, typename T>
+  RunResult DoBinop(BinopTrapFunc<R, T>, Trap::Ptr* out_trap);
+
+  template <typename R, typename T>
+  RunResult DoConvert(Trap::Ptr* out_trap);
+  template <typename R, typename T>
+  RunResult DoReinterpret();
+
+  template <typename T>
+  RunResult Load(Instr, T* out, Trap::Ptr* out_trap);
+  template <typename T, typename V = T>
+  RunResult DoLoad(Instr, Trap::Ptr* out_trap);
+  template <typename T, typename V = T>
+  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 <typename R, typename T>
+  RunResult DoSimdSplat();
+  template <typename R, typename T>
+  RunResult DoSimdExtract(Instr);
+  template <typename R, typename T>
+  RunResult DoSimdReplace(Instr);
+
+  template <typename R, typename T>
+  RunResult DoSimdUnop(UnopFunc<R, T>);
+  template <typename R, typename T>
+  RunResult DoSimdBinop(BinopFunc<R, T>);
+  RunResult DoSimdBitSelect();
+  template <typename S, u8 count>
+  RunResult DoSimdIsTrue();
+  template <typename S>
+  RunResult DoSimdBitmask();
+  template <typename R, typename T>
+  RunResult DoSimdShift(BinopFunc<R, T>);
+  template <typename S, typename T>
+  RunResult DoSimdLoadSplat(Instr, Trap::Ptr* out_trap);
+  RunResult DoSimdSwizzle();
+  RunResult DoSimdShuffle(Instr);
+  template <typename S, typename T>
+  RunResult DoSimdNarrow();
+  template <typename S, typename T, bool low>
+  RunResult DoSimdWiden();
+  template <typename S, typename T>
+  RunResult DoSimdLoadExtend(Instr, Trap::Ptr* out_trap);
+
+  template <typename T, typename V = T>
+  RunResult DoAtomicLoad(Instr, Trap::Ptr* out_trap);
+  template <typename T, typename V = T>
+  RunResult DoAtomicStore(Instr, Trap::Ptr* out_trap);
+  template <typename R, typename T>
+  RunResult DoAtomicRmw(BinopFunc<T, T>, Instr, Trap::Ptr* out_trap);
+  template <typename T, typename V = T>
+  RunResult DoAtomicRmwCmpxchg(Instr, Trap::Ptr* out_trap);
+
+  RunResult StepInternal(Trap::Ptr* out_trap);
+
+  std::vector<Frame> frames_;
+  std::vector<Value> values_;
+  std::vector<u32> refs_;  // Index into values_.
+
+  // Cached for convenience.
+  Store& store_;
+  Instance* inst_ = nullptr;
+  Module* mod_ = nullptr;
+
+  // Tracing.
+  Stream* trace_stream_;
+  std::unique_ptr<TraceSource> 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 (file)
index 0000000..6e95667
--- /dev/null
@@ -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 <cinttypes>
+
+namespace wabt {
+namespace interp {
+
+template <typename T>
+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 <typename T>
+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<SerializedOpcode>(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<u32>(data_.size());
+}
+
+template <typename T>
+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<Opcode::Enum>(ReadAt<SerializedOpcode>(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<u32>(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<u32>(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<u32>(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<u32>(offset);
+      break;
+
+    case Opcode::TableSet:
+    case Opcode::TableGrow:
+      // Index immediate, 2 operands.
+      instr.kind = InstrKind::Imm_Index_Op_2;
+      instr.imm_u32 = ReadAt<u32>(offset);
+      break;
+
+    case Opcode::MemoryFill:
+    case Opcode::TableFill:
+      // Index immediate, 3 operands.
+      instr.kind = InstrKind::Imm_Index_Op_3;
+      instr.imm_u32 = ReadAt<u32>(offset);
+      break;
+
+    case Opcode::Call:
+    case Opcode::InterpCallImport:
+      instr.kind = InstrKind::Imm_Index_Op_N;
+      instr.imm_u32 = ReadAt<u32>(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<u32>(offset);
+      instr.imm_u32x2.snd = ReadAt<u32>(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<u32>(offset);
+      instr.imm_u32x2.snd = ReadAt<u32>(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<u32>(offset);
+      instr.imm_u32x2.snd = ReadAt<u32>(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<u32>(offset);
+      instr.imm_u32x2.snd = ReadAt<u32>(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<u32>(offset);
+      instr.imm_u32x2.snd = ReadAt<u32>(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<u32>(offset);
+      break;
+
+    case Opcode::I64Const:
+      // i64 immediate, 0 operands.
+      instr.kind = InstrKind::Imm_I64_Op_0;
+      instr.imm_u64 = ReadAt<u64>(offset);
+      break;
+
+    case Opcode::F32Const:
+      // f32 immediate, 0 operands.
+      instr.kind = InstrKind::Imm_F32_Op_0;
+      instr.imm_f32 = ReadAt<f32>(offset);
+      break;
+
+    case Opcode::F64Const:
+      // f64 immediate, 0 operands.
+      instr.kind = InstrKind::Imm_F64_Op_0;
+      instr.imm_f64 = ReadAt<f64>(offset);
+      break;
+
+    case Opcode::InterpDropKeep:
+      // i32 and i32 immediates, 0 operands.
+      instr.kind = InstrKind::Imm_I32_I32_Op_0;
+      instr.imm_u32x2.fst = ReadAt<u32>(offset);
+      instr.imm_u32x2.snd = ReadAt<u32>(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<u8>(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<u8>(offset);
+      break;
+
+    case Opcode::V128Const:
+      // v128 immediate, 0 operands.
+      instr.kind = InstrKind::Imm_V128_Op_0;
+      instr.imm_v128 = ReadAt<v128>(offset);
+      break;
+
+    case Opcode::I8X16Shuffle:
+      // v128 immediate, 2 operands.
+      instr.kind = InstrKind::Imm_V128_Op_2;
+      instr.imm_v128 = ReadAt<v128>(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 (file)
index 0000000..69079df
--- /dev/null
@@ -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 <cstdint>
+#include <vector>
+#include <string>
+
+#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<u8>;
+
+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 <typename T>
+  void WABT_VECTORCALL EmitAt(Offset, T val);
+  template <typename T>
+  void WABT_VECTORCALL EmitInternal(T val);
+
+  template <typename T>
+  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 (file)
index 0000000..008e9fd
--- /dev/null
@@ -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 (file)
index 0000000..7d9611a
--- /dev/null
@@ -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 <cassert>
+#include <iterator>
+#include <memory>
+
+#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 <typename T>
+class intrusive_list;
+
+template <typename T>
+class intrusive_list_base {
+ private:
+  friend class intrusive_list<T>;
+
+  mutable T* next_ = nullptr;
+  mutable T* prev_ = nullptr;
+};
+
+template <typename T>
+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<iterator> reverse_iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+
+  // construct/copy/destroy:
+  intrusive_list();
+  explicit intrusive_list(std::unique_ptr<T> 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 <class... Args>
+  void emplace_front(Args&&... args);
+  template <class... Args>
+  void emplace_back(Args&&... args);
+  void push_front(std::unique_ptr<T> node);
+  void push_front(T&& node);
+  void push_back(std::unique_ptr<T> node);
+  void push_back(T&& node);
+  void pop_front();
+  void pop_back();
+  std::unique_ptr<T> extract_front();
+  std::unique_ptr<T> extract_back();
+
+  template <class... Args>
+  iterator emplace(iterator pos, Args&&... args);
+  iterator insert(iterator pos, std::unique_ptr<T> node);
+  iterator insert(iterator pos, T&& node);
+  std::unique_ptr<T> 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 <typename T>
+class intrusive_list<T>::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<T>& 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<T>* list_;
+  T* node_;
+};
+
+/// const_iterator
+template <typename T>
+class intrusive_list<T>::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<T>& 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<T>* list_;
+  T* node_;
+};
+
+template <typename T>
+inline intrusive_list<T>::intrusive_list() {}
+
+template <typename T>
+inline intrusive_list<T>::intrusive_list(std::unique_ptr<T> node) {
+  push_back(std::move(node));
+}
+
+template <typename T>
+inline intrusive_list<T>::intrusive_list(T&& node) {
+  push_back(std::move(node));
+}
+
+template <typename T>
+inline intrusive_list<T>::intrusive_list(intrusive_list&& other)
+    : first_(other.first_), last_(other.last_), size_(other.size_) {
+  other.first_ = other.last_ = nullptr;
+  other.size_ = 0;
+}
+
+template <typename T>
+inline intrusive_list<T>::~intrusive_list() {
+  clear();
+}
+
+template <typename T>
+inline intrusive_list<T>& intrusive_list<T>::operator=(
+    intrusive_list<T>&& other) {
+  clear();
+  first_ = other.first_;
+  last_ = other.last_;
+  size_ = other.size_;
+  other.first_ = other.last_ = nullptr;
+  other.size_ = 0;
+  return *this;
+}
+
+template <typename T>
+inline typename intrusive_list<T>::iterator
+intrusive_list<T>::begin() noexcept {
+  return iterator(*this, first_);
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_iterator intrusive_list<T>::begin()
+    const noexcept {
+  return const_iterator(*this, first_);
+}
+
+template <typename T>
+inline typename intrusive_list<T>::iterator intrusive_list<T>::end() noexcept {
+  return iterator(*this, nullptr);
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_iterator intrusive_list<T>::end() const
+    noexcept {
+  return const_iterator(*this, nullptr);
+}
+
+template <typename T>
+inline typename intrusive_list<T>::reverse_iterator
+intrusive_list<T>::rbegin() noexcept {
+  return reverse_iterator(iterator(*this, nullptr));
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_reverse_iterator
+intrusive_list<T>::rbegin() const noexcept {
+  return const_reverse_iterator(const_iterator(*this, nullptr));
+}
+
+template <typename T>
+inline typename intrusive_list<T>::reverse_iterator
+intrusive_list<T>::rend() noexcept {
+  return reverse_iterator(iterator(*this, first_));
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_reverse_iterator
+intrusive_list<T>::rend() const noexcept {
+  return const_reverse_iterator(const_iterator(*this, first_));
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cbegin()
+    const noexcept {
+  return const_iterator(*this, first_);
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_iterator intrusive_list<T>::cend()
+    const noexcept {
+  return const_iterator(*this, nullptr);
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_reverse_iterator
+intrusive_list<T>::crbegin() const noexcept {
+  return const_reverse_iterator(const_iterator(*this, nullptr));
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_reverse_iterator
+intrusive_list<T>::crend() const noexcept {
+  return const_reverse_iterator(const_iterator(*this, first_));
+}
+
+template <typename T>
+inline typename intrusive_list<T>::size_type intrusive_list<T>::size() const
+    noexcept {
+  return size_;
+}
+
+template <typename T>
+inline bool intrusive_list<T>::empty() const noexcept {
+  return size_ == 0;
+}
+
+template <typename T>
+inline typename intrusive_list<T>::reference intrusive_list<T>::front() {
+  assert(!empty());
+  return *first_;
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_reference intrusive_list<T>::front()
+    const {
+  assert(!empty());
+  return *first_;
+}
+
+template <typename T>
+inline typename intrusive_list<T>::reference intrusive_list<T>::back() {
+  assert(!empty());
+  return *last_;
+}
+
+template <typename T>
+inline typename intrusive_list<T>::const_reference intrusive_list<T>::back()
+    const {
+  assert(!empty());
+  return *last_;
+}
+
+template <typename T>
+template <class... Args>
+inline void intrusive_list<T>::emplace_front(Args&&... args) {
+  push_front(MakeUnique<T>(std::forward<Args>(args)...));
+}
+
+template <typename T>
+template <class... Args>
+inline void intrusive_list<T>::emplace_back(Args&&... args) {
+  push_back(MakeUnique<T>(std::forward<Args>(args)...));
+}
+
+template <typename T>
+inline void intrusive_list<T>::push_front(std::unique_ptr<T> 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 <typename T>
+inline void intrusive_list<T>::push_front(T&& node) {
+  push_front(MakeUnique<T>(std::move(node)));
+}
+
+template <typename T>
+inline void intrusive_list<T>::push_back(std::unique_ptr<T> 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 <typename T>
+inline void intrusive_list<T>::push_back(T&& node) {
+  push_back(MakeUnique<T>(std::move(node)));
+}
+
+template <typename T>
+inline void intrusive_list<T>::pop_front() {
+  extract_front();
+}
+
+template <typename T>
+inline void intrusive_list<T>::pop_back() {
+  extract_back();
+}
+
+template <typename T>
+inline std::unique_ptr<T> intrusive_list<T>::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<T>(node);
+}
+
+template <typename T>
+inline std::unique_ptr<T> intrusive_list<T>::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<T>(node);
+}
+
+template <typename T>
+template <class... Args>
+inline typename intrusive_list<T>::iterator intrusive_list<T>::emplace(
+    iterator pos,
+    Args&&... args) {
+  return insert(pos, MakeUnique<T>(std::forward<Args>(args)...));
+}
+
+template <typename T>
+inline typename intrusive_list<T>::iterator intrusive_list<T>::insert(
+    iterator pos,
+    std::unique_ptr<T> 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 <typename T>
+inline typename intrusive_list<T>::iterator intrusive_list<T>::insert(
+    iterator pos,
+    T&& node) {
+  return insert(pos, MakeUnique<T>(std::move(node)));
+}
+
+template <typename T>
+inline std::unique_ptr<T> intrusive_list<T>::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<T>(node);
+}
+
+template <typename T>
+inline typename intrusive_list<T>::iterator intrusive_list<T>::erase(
+    iterator pos) {
+  iterator next = std::next(pos);
+  extract(pos);
+  return next;
+}
+
+template <typename T>
+inline typename intrusive_list<T>::iterator intrusive_list<T>::erase(
+    iterator first,
+    iterator last) {
+  while (first != last)
+    first = erase(first);
+  return first;
+}
+
+template <typename T>
+inline void intrusive_list<T>::swap(intrusive_list& other) {
+  std::swap(first_, other.first_);
+  std::swap(last_, other.last_);
+  std::swap(size_, other.size_);
+}
+
+template <typename T>
+inline void intrusive_list<T>::clear() noexcept {
+  for (T* iter = first_; iter;) {
+    T* next = iter->next_;
+    delete iter;
+    iter = next;
+  }
+  first_ = last_ = nullptr;
+  size_ = 0;
+}
+
+template <typename T>
+inline void intrusive_list<T>::splice(iterator pos, intrusive_list& other) {
+  splice(pos, other, other.begin(), other.end());
+}
+
+template <typename T>
+inline void intrusive_list<T>::splice(iterator pos, intrusive_list&& other) {
+  splice(pos, other, other.begin(), other.end());
+}
+
+template <typename T>
+inline void intrusive_list<T>::splice(iterator pos,
+                                      intrusive_list& other,
+                                      iterator it) {
+  insert(pos, other.extract(it));
+}
+
+template <typename T>
+inline void intrusive_list<T>::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 (file)
index 0000000..ef1c9a2
--- /dev/null
@@ -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 <algorithm>
+#include <array>
+#include <cassert>
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdio>
+#include <iterator>
+#include <map>
+#include <string>
+#include <vector>
+
+#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<BlockExpr>(&expr)->block.decl.sig.GetNumResults() };
+
+    case ExprType::Br:
+      return { GetLabelArity(cast<BrExpr>(&expr)->var), 1, true };
+
+    case ExprType::BrIf: {
+      Index arity = GetLabelArity(cast<BrIfExpr>(&expr)->var);
+      return { arity + 1, arity };
+    }
+
+    case ExprType::BrTable:
+      return { GetLabelArity(cast<BrTableExpr>(&expr)->default_target) + 1, 1,
+               true };
+
+    case ExprType::Call: {
+      const Var& var = cast<CallExpr>(&expr)->var;
+      return { GetFuncParamCount(var), GetFuncResultCount(var) };
+    }
+
+    case ExprType::ReturnCall: {
+      const Var& var = cast<ReturnCallExpr>(&expr)->var;
+      return { GetFuncParamCount(var), GetFuncResultCount(var), true };
+    }
+
+    case ExprType::CallIndirect: {
+      const auto* ci_expr = cast<CallIndirectExpr>(&expr);
+      return { ci_expr->decl.GetNumParams() + 1,
+               ci_expr->decl.GetNumResults() };
+    }
+
+    case ExprType::ReturnCallIndirect: {
+      const auto* rci_expr = cast<ReturnCallIndirectExpr>(&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<IfExpr>(&expr)->true_.decl.sig.GetNumResults() };
+
+    case ExprType::Loop:
+      return { 0, cast<LoopExpr>(&expr)->block.decl.sig.GetNumResults() };
+
+    case ExprType::Nop:
+      return { 0, 0 };
+
+    case ExprType::Return:
+      return
+        { static_cast<Index>(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<ThrowExpr>(&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<TryExpr>(&expr)->block.decl.sig.GetNumResults() };
+
+    case ExprType::Ternary:
+      return { 3, 1 };
+
+    case ExprType::SimdLaneOp: {
+      const Opcode opcode = cast<SimdLaneOpExpr>(&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 (file)
index 0000000..226e81a
--- /dev/null
@@ -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<Label> label_stack_;
+};
+
+}  // namespace wabt
+
+#endif /* WABT_IR_UTIL_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.cc
new file mode 100644 (file)
index 0000000..c74b98e
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ * 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.h"
+
+#include <cassert>
+#include <cstddef>
+#include <numeric>
+
+#include "src/cast.h"
+
+namespace {
+
+const char* ExprTypeName[] = {
+  "AtomicFence",
+  "AtomicLoad",
+  "AtomicRmw",
+  "AtomicRmwCmpxchg",
+  "AtomicStore",
+  "AtomicNotify",
+  "AtomicWait",
+  "Binary",
+  "Block",
+  "Br",
+  "BrIf",
+  "BrTable",
+  "Call",
+  "CallIndirect",
+  "Compare",
+  "Const",
+  "Convert",
+  "Drop",
+  "GlobalGet",
+  "GlobalSet",
+  "If",
+  "Load",
+  "LocalGet",
+  "LocalSet",
+  "LocalTee",
+  "Loop",
+  "MemoryCopy",
+  "DataDrop",
+  "MemoryFill",
+  "MemoryGrow",
+  "MemoryInit",
+  "MemorySize",
+  "Nop",
+  "RefIsNull",
+  "RefFunc",
+  "RefNull",
+  "Rethrow",
+  "Return",
+  "ReturnCall",
+  "ReturnCallIndirect",
+  "Select",
+  "SimdLaneOp",
+  "SimdShuffleOp",
+  "LoadSplat",
+  "Store",
+  "TableCopy",
+  "ElemDrop",
+  "TableInit",
+  "TableGet",
+  "TableGrow",
+  "TableSize",
+  "TableSet",
+  "TableFill",
+  "Ternary",
+  "Throw",
+  "Try",
+  "Unary",
+  "Unreachable",
+};
+
+}  // end of anonymous namespace
+
+namespace wabt {
+
+const char* GetExprTypeName(ExprType type) {
+  static_assert(WABT_ENUM_COUNT(ExprType) == WABT_ARRAY_SIZE(ExprTypeName),
+                "Malformed ExprTypeName array");
+  return ExprTypeName[size_t(type)];
+}
+
+const char* GetExprTypeName(const Expr& expr) {
+  return GetExprTypeName(expr.type());
+}
+
+bool FuncSignature::operator==(const FuncSignature& rhs) const {
+  return param_types == rhs.param_types && result_types == rhs.result_types;
+}
+
+const Export* Module::GetExport(string_view name) const {
+  Index index = export_bindings.FindIndex(name);
+  if (index >= exports.size()) {
+    return nullptr;
+  }
+  return exports[index];
+}
+
+Index Module::GetFuncIndex(const Var& var) const {
+  return func_bindings.FindIndex(var);
+}
+
+Index Module::GetGlobalIndex(const Var& var) const {
+  return global_bindings.FindIndex(var);
+}
+
+Index Module::GetTableIndex(const Var& var) const {
+  return table_bindings.FindIndex(var);
+}
+
+Index Module::GetMemoryIndex(const Var& var) const {
+  return memory_bindings.FindIndex(var);
+}
+
+Index Module::GetFuncTypeIndex(const Var& var) const {
+  return type_bindings.FindIndex(var);
+}
+
+Index Module::GetEventIndex(const Var& var) const {
+  return event_bindings.FindIndex(var);
+}
+
+Index Module::GetDataSegmentIndex(const Var& var) const {
+  return data_segment_bindings.FindIndex(var);
+}
+
+Index Module::GetElemSegmentIndex(const Var& var) const {
+  return elem_segment_bindings.FindIndex(var);
+}
+
+bool Module::IsImport(ExternalKind kind, const Var& var) const {
+  switch (kind) {
+    case ExternalKind::Func:
+      return GetFuncIndex(var) < num_func_imports;
+
+    case ExternalKind::Global:
+      return GetGlobalIndex(var) < num_global_imports;
+
+    case ExternalKind::Memory:
+      return GetMemoryIndex(var) < num_memory_imports;
+
+    case ExternalKind::Table:
+      return GetTableIndex(var) < num_table_imports;
+
+    case ExternalKind::Event:
+      return GetEventIndex(var) < num_event_imports;
+
+    default:
+      return false;
+  }
+}
+
+void LocalTypes::Set(const TypeVector& types) {
+  decls_.clear();
+  if (types.empty()) {
+    return;
+  }
+
+  Type type = types[0];
+  Index count = 1;
+  for (Index i = 1; i < types.size(); ++i) {
+    if (types[i] != type) {
+      decls_.emplace_back(type, count);
+      type = types[i];
+      count = 1;
+    } else {
+      ++count;
+    }
+  }
+  decls_.emplace_back(type, count);
+}
+
+Index LocalTypes::size() const {
+  return std::accumulate(
+      decls_.begin(), decls_.end(), 0,
+      [](Index sum, const Decl& decl) { return sum + decl.second; });
+}
+
+Type LocalTypes::operator[](Index i) const {
+  Index count = 0;
+  for (auto decl: decls_) {
+    if (i < count + decl.second) {
+      return decl.first;
+    }
+    count += decl.second;
+  }
+  assert(i < count);
+  return Type::Any;
+}
+
+Type Func::GetLocalType(Index index) const {
+  Index num_params = decl.GetNumParams();
+  if (index < num_params) {
+    return GetParamType(index);
+  } else {
+    index -= num_params;
+    assert(index < local_types.size());
+    return local_types[index];
+  }
+}
+
+Type Func::GetLocalType(const Var& var) const {
+  return GetLocalType(GetLocalIndex(var));
+}
+
+Index Func::GetLocalIndex(const Var& var) const {
+  if (var.is_index()) {
+    return var.index();
+  }
+  return bindings.FindIndex(var);
+}
+
+const Func* Module::GetFunc(const Var& var) const {
+  return const_cast<Module*>(this)->GetFunc(var);
+}
+
+Func* Module::GetFunc(const Var& var) {
+  Index index = func_bindings.FindIndex(var);
+  if (index >= funcs.size()) {
+    return nullptr;
+  }
+  return funcs[index];
+}
+
+const Global* Module::GetGlobal(const Var& var) const {
+  return const_cast<Module*>(this)->GetGlobal(var);
+}
+
+Global* Module::GetGlobal(const Var& var) {
+  Index index = global_bindings.FindIndex(var);
+  if (index >= globals.size()) {
+    return nullptr;
+  }
+  return globals[index];
+}
+
+const Table* Module::GetTable(const Var& var) const {
+  return const_cast<Module*>(this)->GetTable(var);
+}
+
+Table* Module::GetTable(const Var& var) {
+  Index index = table_bindings.FindIndex(var);
+  if (index >= tables.size()) {
+    return nullptr;
+  }
+  return tables[index];
+}
+
+const Memory* Module::GetMemory(const Var& var) const {
+  return const_cast<Module*>(this)->GetMemory(var);
+}
+
+Memory* Module::GetMemory(const Var& var) {
+  Index index = memory_bindings.FindIndex(var);
+  if (index >= memories.size()) {
+    return nullptr;
+  }
+  return memories[index];
+}
+
+Event* Module::GetEvent(const Var& var) const {
+  Index index = GetEventIndex(var);
+  if (index >= events.size()) {
+    return nullptr;
+  }
+  return events[index];
+}
+
+const DataSegment* Module::GetDataSegment(const Var& var) const {
+  return const_cast<Module*>(this)->GetDataSegment(var);
+}
+
+DataSegment* Module::GetDataSegment(const Var& var) {
+  Index index = data_segment_bindings.FindIndex(var);
+  if (index >= data_segments.size()) {
+    return nullptr;
+  }
+  return data_segments[index];
+}
+
+const ElemSegment* Module::GetElemSegment(const Var& var) const {
+  return const_cast<Module*>(this)->GetElemSegment(var);
+}
+
+ElemSegment* Module::GetElemSegment(const Var& var) {
+  Index index = elem_segment_bindings.FindIndex(var);
+  if (index >= elem_segments.size()) {
+    return nullptr;
+  }
+  return elem_segments[index];
+}
+
+const FuncType* Module::GetFuncType(const Var& var) const {
+  return const_cast<Module*>(this)->GetFuncType(var);
+}
+
+FuncType* Module::GetFuncType(const Var& var) {
+  Index index = type_bindings.FindIndex(var);
+  if (index >= types.size()) {
+    return nullptr;
+  }
+  return dyn_cast<FuncType>(types[index]);
+}
+
+Index Module::GetFuncTypeIndex(const FuncSignature& sig) const {
+  for (size_t i = 0; i < types.size(); ++i) {
+    if (auto* func_type = dyn_cast<FuncType>(types[i])) {
+      if (func_type->sig == sig) {
+        return i;
+      }
+    }
+  }
+  return kInvalidIndex;
+}
+
+Index Module::GetFuncTypeIndex(const FuncDeclaration& decl) const {
+  if (decl.has_func_type) {
+    return GetFuncTypeIndex(decl.type_var);
+  } else {
+    return GetFuncTypeIndex(decl.sig);
+  }
+}
+
+void Module::AppendField(std::unique_ptr<DataSegmentModuleField> field) {
+  DataSegment& data_segment = field->data_segment;
+  if (!data_segment.name.empty()) {
+    data_segment_bindings.emplace(data_segment.name,
+                                  Binding(field->loc, data_segments.size()));
+  }
+  data_segments.push_back(&data_segment);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<ElemSegmentModuleField> field) {
+  ElemSegment& elem_segment = field->elem_segment;
+  if (!elem_segment.name.empty()) {
+    elem_segment_bindings.emplace(elem_segment.name,
+                                  Binding(field->loc, elem_segments.size()));
+  }
+  elem_segments.push_back(&elem_segment);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<EventModuleField> field) {
+  Event& event = field->event;
+  if (!event.name.empty()) {
+    event_bindings.emplace(event.name, Binding(field->loc, events.size()));
+  }
+  events.push_back(&event);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<ExportModuleField> field) {
+  // Exported names are allowed to be empty.
+  Export& export_ = field->export_;
+  export_bindings.emplace(export_.name, Binding(field->loc, exports.size()));
+  exports.push_back(&export_);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<FuncModuleField> field) {
+  Func& func = field->func;
+  if (!func.name.empty()) {
+    func_bindings.emplace(func.name, Binding(field->loc, funcs.size()));
+  }
+  funcs.push_back(&func);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<TypeModuleField> field) {
+  TypeEntry& type = *field->type;
+  if (!type.name.empty()) {
+    type_bindings.emplace(type.name, Binding(field->loc, types.size()));
+  }
+  types.push_back(&type);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<GlobalModuleField> field) {
+  Global& global = field->global;
+  if (!global.name.empty()) {
+    global_bindings.emplace(global.name, Binding(field->loc, globals.size()));
+  }
+  globals.push_back(&global);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<ImportModuleField> field) {
+  Import* import = field->import.get();
+  const std::string* name = nullptr;
+  BindingHash* bindings = nullptr;
+  Index index = kInvalidIndex;
+
+  switch (import->kind()) {
+    case ExternalKind::Func: {
+      Func& func = cast<FuncImport>(import)->func;
+      name = &func.name;
+      bindings = &func_bindings;
+      index = funcs.size();
+      funcs.push_back(&func);
+      ++num_func_imports;
+      break;
+    }
+
+    case ExternalKind::Table: {
+      Table& table = cast<TableImport>(import)->table;
+      name = &table.name;
+      bindings = &table_bindings;
+      index = tables.size();
+      tables.push_back(&table);
+      ++num_table_imports;
+      break;
+    }
+
+    case ExternalKind::Memory: {
+      Memory& memory = cast<MemoryImport>(import)->memory;
+      name = &memory.name;
+      bindings = &memory_bindings;
+      index = memories.size();
+      memories.push_back(&memory);
+      ++num_memory_imports;
+      break;
+    }
+
+    case ExternalKind::Global: {
+      Global& global = cast<GlobalImport>(import)->global;
+      name = &global.name;
+      bindings = &global_bindings;
+      index = globals.size();
+      globals.push_back(&global);
+      ++num_global_imports;
+      break;
+    }
+
+    case ExternalKind::Event: {
+      Event& event = cast<EventImport>(import)->event;
+      name = &event.name;
+      bindings = &event_bindings;
+      index = events.size();
+      events.push_back(&event);
+      ++num_event_imports;
+      break;
+    }
+  }
+
+  assert(name && bindings && index != kInvalidIndex);
+  if (!name->empty()) {
+    bindings->emplace(*name, Binding(field->loc, index));
+  }
+  imports.push_back(import);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<MemoryModuleField> field) {
+  Memory& memory = field->memory;
+  if (!memory.name.empty()) {
+    memory_bindings.emplace(memory.name, Binding(field->loc, memories.size()));
+  }
+  memories.push_back(&memory);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<StartModuleField> field) {
+  starts.push_back(&field->start);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<TableModuleField> field) {
+  Table& table = field->table;
+  if (!table.name.empty()) {
+    table_bindings.emplace(table.name, Binding(field->loc, tables.size()));
+  }
+  tables.push_back(&table);
+  fields.push_back(std::move(field));
+}
+
+void Module::AppendField(std::unique_ptr<ModuleField> field) {
+  switch (field->type()) {
+    case ModuleFieldType::Func:
+      AppendField(cast<FuncModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Global:
+      AppendField(cast<GlobalModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Import:
+      AppendField(cast<ImportModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Export:
+      AppendField(cast<ExportModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Type:
+      AppendField(cast<TypeModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Table:
+      AppendField(cast<TableModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::ElemSegment:
+      AppendField(cast<ElemSegmentModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Memory:
+      AppendField(cast<MemoryModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::DataSegment:
+      AppendField(cast<DataSegmentModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Start:
+      AppendField(cast<StartModuleField>(std::move(field)));
+      break;
+
+    case ModuleFieldType::Event:
+      AppendField(cast<EventModuleField>(std::move(field)));
+      break;
+  }
+}
+
+void Module::AppendFields(ModuleFieldList* fields) {
+  while (!fields->empty())
+    AppendField(std::unique_ptr<ModuleField>(fields->extract_front()));
+}
+
+const Module* Script::GetFirstModule() const {
+  return const_cast<Script*>(this)->GetFirstModule();
+}
+
+Module* Script::GetFirstModule() {
+  for (const std::unique_ptr<Command>& command : commands) {
+    if (auto* module_command = dyn_cast<ModuleCommand>(command.get())) {
+      return &module_command->module;
+    }
+  }
+  return nullptr;
+}
+
+const Module* Script::GetModule(const Var& var) const {
+  Index index = module_bindings.FindIndex(var);
+  if (index >= commands.size()) {
+    return nullptr;
+  }
+  auto* command = cast<ModuleCommand>(commands[index].get());
+  return &command->module;
+}
+
+void MakeTypeBindingReverseMapping(
+    size_t num_types,
+    const BindingHash& bindings,
+    std::vector<std::string>* out_reverse_mapping) {
+  out_reverse_mapping->clear();
+  out_reverse_mapping->resize(num_types);
+  for (const auto& pair : bindings) {
+    assert(static_cast<size_t>(pair.second.index) <
+           out_reverse_mapping->size());
+    (*out_reverse_mapping)[pair.second.index] = pair.first;
+  }
+}
+
+Var::Var(Index index, const Location& loc)
+    : loc(loc), type_(VarType::Index), index_(index) {}
+
+Var::Var(string_view name, const Location& loc)
+    : loc(loc), type_(VarType::Name), name_(name) {}
+
+Var::Var(Var&& rhs) : Var(kInvalidIndex) {
+  *this = std::move(rhs);
+}
+
+Var::Var(const Var& rhs) : Var(kInvalidIndex) {
+  *this = rhs;
+}
+
+Var& Var::operator=(Var&& rhs) {
+  loc = rhs.loc;
+  if (rhs.is_index()) {
+    set_index(rhs.index_);
+  } else {
+    set_name(rhs.name_);
+  }
+  return *this;
+}
+
+Var& Var::operator=(const Var& rhs) {
+  loc = rhs.loc;
+  if (rhs.is_index()) {
+    set_index(rhs.index_);
+  } else {
+    set_name(rhs.name_);
+  }
+  return *this;
+}
+
+Var::~Var() {
+  Destroy();
+}
+
+void Var::set_index(Index index) {
+  Destroy();
+  type_ = VarType::Index;
+  index_ = index;
+}
+
+void Var::set_name(std::string&& name) {
+  Destroy();
+  type_ = VarType::Name;
+  Construct(name_, std::move(name));
+}
+
+void Var::set_name(string_view name) {
+  set_name(name.to_string());
+}
+
+void Var::Destroy() {
+  if (is_name()) {
+    Destruct(name_);
+  }
+}
+
+uint8_t ElemSegment::GetFlags(const Module* module) const {
+  uint8_t flags = 0;
+
+  bool all_ref_func = elem_type == Type::FuncRef;
+
+  switch (kind) {
+    case SegmentKind::Active: {
+      Index table_index = module->GetTableIndex(table_var);
+      if (table_index != 0) {
+        flags |= SegExplicitIndex;
+      }
+      break;
+    }
+
+    case SegmentKind::Passive:
+      flags |= SegPassive;
+      break;
+
+    case SegmentKind::Declared:
+      flags |= SegDeclared;
+      break;
+  }
+
+  all_ref_func = all_ref_func &&
+                 std::all_of(elem_exprs.begin(), elem_exprs.end(),
+                             [](const ElemExpr& elem_expr) {
+                               return elem_expr.kind == ElemExprKind::RefFunc;
+                             });
+  if (!all_ref_func) {
+    flags |= SegUseElemExprs;
+  }
+
+  return flags;
+}
+
+uint8_t DataSegment::GetFlags(const Module* module) const {
+  uint8_t flags = 0;
+
+  if (kind == SegmentKind::Passive) {
+    flags |= SegPassive;
+  }
+
+  Index memory_index = module->GetMemoryIndex(memory_var);
+  if (memory_index != 0) {
+    flags |= SegExplicitIndex;
+  }
+
+  return flags;
+}
+
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/ir.h
new file mode 100644 (file)
index 0000000..6742aee
--- /dev/null
@@ -0,0 +1,1307 @@
+/*
+ * 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_H_
+#define WABT_IR_H_
+
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <type_traits>
+#include <vector>
+
+#include "src/binding-hash.h"
+#include "src/common.h"
+#include "src/intrusive-list.h"
+#include "src/opcode.h"
+#include "src/string-view.h"
+
+namespace wabt {
+
+struct Module;
+
+enum class VarType {
+  Index,
+  Name,
+};
+
+struct Var {
+  explicit Var(Index index = kInvalidIndex, const Location& loc = Location());
+  explicit Var(string_view name, const Location& loc = Location());
+  Var(Var&&);
+  Var(const Var&);
+  Var& operator=(const Var&);
+  Var& operator=(Var&&);
+  ~Var();
+
+  VarType type() const { return type_; }
+  bool is_index() const { return type_ == VarType::Index; }
+  bool is_name() const { return type_ == VarType::Name; }
+
+  Index index() const { assert(is_index()); return index_; }
+  const std::string& name() const { assert(is_name()); return name_; }
+
+  void set_index(Index);
+  void set_name(std::string&&);
+  void set_name(string_view);
+
+  Location loc;
+
+ private:
+  void Destroy();
+
+  VarType type_;
+  union {
+    Index index_;
+    std::string name_;
+  };
+};
+typedef std::vector<Var> VarVector;
+
+struct Const {
+  static constexpr uintptr_t kRefNullBits = ~uintptr_t(0);
+
+  Const() : Const(Type::I32, uint32_t(0)) {}
+
+  static Const I32(uint32_t val = 0, const Location& loc = Location()) {
+    return Const(Type::I32, val, loc);
+  }
+  static Const I64(uint64_t val = 0, const Location& loc = Location()) {
+    return Const(Type::I64, val, loc);
+  }
+  static Const F32(uint32_t val = 0, const Location& loc = Location()) {
+    return Const(Type::F32, val, loc);
+  }
+  static Const F64(uint64_t val = 0, const Location& loc = Location()) {
+    return Const(Type::F64, val, loc);
+  }
+  static Const V128(v128 val, const Location& loc = Location()) {
+    return Const(Type::V128, val, loc);
+  }
+
+  Type type() const { return type_; }
+  Type lane_type() const { assert(type_ == Type::V128); return lane_type_; }
+
+  int lane_count() const {
+    switch (lane_type()) {
+      case Type::I8:  return 16;
+      case Type::I16: return 8;
+      case Type::I32: return 4;
+      case Type::I64: return 2;
+      case Type::F32: return 4;
+      case Type::F64: return 2;
+      default: WABT_UNREACHABLE;
+    }
+  }
+
+  uint32_t u32() const { return data_.u32(0); }
+  uint64_t u64() const { return data_.u64(0); }
+  uint32_t f32_bits() const { return data_.f32_bits(0); }
+  uint64_t f64_bits() const { return data_.f64_bits(0); }
+  uintptr_t ref_bits() const { return data_.To<uintptr_t>(0); }
+  v128 vec128() const { return data_; }
+
+  template <typename T>
+  T v128_lane(int lane) const { return data_.To<T>(lane); }
+
+  void set_u32(uint32_t x) { From(Type::I32, x); }
+  void set_u64(uint64_t x) { From(Type::I64, x); }
+  void set_f32(uint32_t x) { From(Type::F32, x); }
+  void set_f64(uint64_t x) { From(Type::F64, x); }
+
+  void set_v128_u8(int lane, uint8_t x) { set_v128_lane(lane, Type::I8, x); }
+  void set_v128_u16(int lane, uint16_t x) { set_v128_lane(lane, Type::I16, x); }
+  void set_v128_u32(int lane, uint32_t x) { set_v128_lane(lane, Type::I32, x); }
+  void set_v128_u64(int lane, uint64_t x) { set_v128_lane(lane, Type::I64, x); }
+  void set_v128_f32(int lane, uint32_t x) { set_v128_lane(lane, Type::F32, x); }
+  void set_v128_f64(int lane, uint64_t x) { set_v128_lane(lane, Type::F64, x); }
+
+  // Only used for expectations. (e.g. wast assertions)
+  void set_f32(ExpectedNan nan) { set_f32(0); set_expected_nan(0, nan); }
+  void set_f64(ExpectedNan nan) { set_f64(0); set_expected_nan(0, nan); }
+  void set_funcref()            { From<uintptr_t>(Type::FuncRef, 0); }
+  void set_externref(uintptr_t x) { From(Type::ExternRef, x); }
+  void set_null(Type type)      { From<uintptr_t>(type, kRefNullBits); }
+
+  bool is_expected_nan(int lane = 0) const {
+    return expected_nan(lane) != ExpectedNan::None;
+  }
+
+  ExpectedNan expected_nan(int lane = 0) const {
+    return lane < 4 ? nan_[lane] : ExpectedNan::None;
+  }
+
+  void set_expected_nan(int lane, ExpectedNan nan) {
+    if (lane < 4) {
+      nan_[lane] = nan;
+    }
+  }
+
+  // v128 support
+  Location loc;
+
+ private:
+  template <typename T>
+  void set_v128_lane(int lane, Type lane_type, T x) {
+    lane_type_ = lane_type;
+    From(Type::V128, x, lane);
+    set_expected_nan(lane, ExpectedNan::None);
+  }
+
+  template <typename T>
+  Const(Type type, T data, const Location& loc = Location()) : loc(loc) {
+    From<T>(type, data);
+  }
+
+  template <typename T>
+  void From(Type type, T data, int lane = 0) {
+    static_assert(sizeof(T) <= sizeof(data_), "Invalid cast!");
+    assert((lane + 1) * sizeof(T) <= sizeof(data_));
+    type_ = type;
+    data_.From<T>(lane, data);
+    set_expected_nan(lane, ExpectedNan::None);
+  }
+
+  Type type_;
+  Type lane_type_;    // Only valid if type_ == Type::V128.
+  v128 data_;
+  ExpectedNan nan_[4];
+};
+typedef std::vector<Const> ConstVector;
+
+struct FuncSignature {
+  TypeVector param_types;
+  TypeVector result_types;
+
+  Index GetNumParams() const { return param_types.size(); }
+  Index GetNumResults() const { return result_types.size(); }
+  Type GetParamType(Index index) const { return param_types[index]; }
+  Type GetResultType(Index index) const { return result_types[index]; }
+
+  bool operator==(const FuncSignature&) const;
+};
+
+enum class TypeEntryKind {
+  Func,
+  Struct,
+  Array,
+};
+
+class TypeEntry {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(TypeEntry);
+
+  virtual ~TypeEntry() = default;
+
+  TypeEntryKind kind() const { return kind_; }
+
+  Location loc;
+  std::string name;
+
+ protected:
+  explicit TypeEntry(TypeEntryKind kind,
+                     string_view name = string_view(),
+                     const Location& loc = Location())
+      : loc(loc), name(name.to_string()), kind_(kind) {}
+
+  TypeEntryKind kind_;
+};
+
+class FuncType : public TypeEntry {
+ public:
+  static bool classof(const TypeEntry* entry) {
+    return entry->kind() == TypeEntryKind::Func;
+  }
+
+  explicit FuncType(string_view name = string_view())
+      : TypeEntry(TypeEntryKind::Func, name) {}
+
+  Index GetNumParams() const { return sig.GetNumParams(); }
+  Index GetNumResults() const { return sig.GetNumResults(); }
+  Type GetParamType(Index index) const { return sig.GetParamType(index); }
+  Type GetResultType(Index index) const { return sig.GetResultType(index); }
+
+  FuncSignature sig;
+};
+
+struct Field {
+  std::string name;
+  Type type = Type::Void;
+  bool mutable_ = false;
+};
+
+class StructType : public TypeEntry {
+ public:
+  static bool classof(const TypeEntry* entry) {
+    return entry->kind() == TypeEntryKind::Struct;
+  }
+
+  explicit StructType(string_view name = string_view())
+      : TypeEntry(TypeEntryKind::Struct) {}
+
+  std::vector<Field> fields;
+};
+
+class ArrayType : public TypeEntry {
+ public:
+  static bool classof(const TypeEntry* entry) {
+    return entry->kind() == TypeEntryKind::Array;
+  }
+
+  explicit ArrayType(string_view name = string_view())
+      : TypeEntry(TypeEntryKind::Array) {}
+
+  Field field;
+};
+
+struct FuncDeclaration {
+  Index GetNumParams() const { return sig.GetNumParams(); }
+  Index GetNumResults() const { return sig.GetNumResults(); }
+  Type GetParamType(Index index) const { return sig.GetParamType(index); }
+  Type GetResultType(Index index) const { return sig.GetResultType(index); }
+
+  bool has_func_type = false;
+  Var type_var;
+  FuncSignature sig;
+};
+
+enum class ExprType {
+  AtomicLoad,
+  AtomicRmw,
+  AtomicRmwCmpxchg,
+  AtomicStore,
+  AtomicNotify,
+  AtomicFence,
+  AtomicWait,
+  Binary,
+  Block,
+  Br,
+  BrIf,
+  BrTable,
+  Call,
+  CallIndirect,
+  Compare,
+  Const,
+  Convert,
+  Drop,
+  GlobalGet,
+  GlobalSet,
+  If,
+  Load,
+  LocalGet,
+  LocalSet,
+  LocalTee,
+  Loop,
+  MemoryCopy,
+  DataDrop,
+  MemoryFill,
+  MemoryGrow,
+  MemoryInit,
+  MemorySize,
+  Nop,
+  RefIsNull,
+  RefFunc,
+  RefNull,
+  Rethrow,
+  Return,
+  ReturnCall,
+  ReturnCallIndirect,
+  Select,
+  SimdLaneOp,
+  SimdShuffleOp,
+  LoadSplat,
+  Store,
+  TableCopy,
+  ElemDrop,
+  TableInit,
+  TableGet,
+  TableGrow,
+  TableSize,
+  TableSet,
+  TableFill,
+  Ternary,
+  Throw,
+  Try,
+  Unary,
+  Unreachable,
+
+  First = AtomicLoad,
+  Last = Unreachable
+};
+
+const char* GetExprTypeName(ExprType type);
+
+class Expr;
+typedef intrusive_list<Expr> ExprList;
+
+typedef FuncDeclaration BlockDeclaration;
+
+struct Block {
+  Block() = default;
+  explicit Block(ExprList exprs) : exprs(std::move(exprs)) {}
+
+  std::string label;
+  BlockDeclaration decl;
+  ExprList exprs;
+  Location end_loc;
+};
+
+struct Catch {
+  explicit Catch(const Location& loc = Location()) : loc(loc) {}
+  explicit Catch(const Var& var, const Location& loc = Location())
+      : loc(loc), var(var) {}
+  Location loc;
+  Var var;
+  ExprList exprs;
+  bool IsCatchAll() const {
+    return var.is_index() && var.index() == kInvalidIndex;
+  }
+};
+typedef std::vector<Catch> CatchVector;
+
+enum class TryKind {
+  Invalid,
+  Catch,
+  Unwind,
+  Delegate
+};
+
+class Expr : public intrusive_list_base<Expr> {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(Expr);
+  Expr() = delete;
+  virtual ~Expr() = default;
+
+  ExprType type() const { return type_; }
+
+  Location loc;
+
+ protected:
+  explicit Expr(ExprType type, const Location& loc = Location())
+      : loc(loc), type_(type) {}
+
+  ExprType type_;
+};
+
+const char* GetExprTypeName(const Expr& expr);
+
+template <ExprType TypeEnum>
+class ExprMixin : public Expr {
+ public:
+  static bool classof(const Expr* expr) { return expr->type() == TypeEnum; }
+
+  explicit ExprMixin(const Location& loc = Location()) : Expr(TypeEnum, loc) {}
+};
+
+typedef ExprMixin<ExprType::Drop> DropExpr;
+typedef ExprMixin<ExprType::MemoryGrow> MemoryGrowExpr;
+typedef ExprMixin<ExprType::MemorySize> MemorySizeExpr;
+typedef ExprMixin<ExprType::MemoryCopy> MemoryCopyExpr;
+typedef ExprMixin<ExprType::MemoryFill> MemoryFillExpr;
+typedef ExprMixin<ExprType::Nop> NopExpr;
+typedef ExprMixin<ExprType::Return> ReturnExpr;
+typedef ExprMixin<ExprType::Unreachable> UnreachableExpr;
+
+template <ExprType TypeEnum>
+class RefTypeExpr : public ExprMixin<TypeEnum> {
+ public:
+  RefTypeExpr(Type type, const Location& loc = Location())
+      : ExprMixin<TypeEnum>(loc), type(type) {}
+
+  Type type;
+};
+
+typedef RefTypeExpr<ExprType::RefNull> RefNullExpr;
+typedef ExprMixin<ExprType::RefIsNull> RefIsNullExpr;
+
+template <ExprType TypeEnum>
+class OpcodeExpr : public ExprMixin<TypeEnum> {
+ public:
+  OpcodeExpr(Opcode opcode, const Location& loc = Location())
+      : ExprMixin<TypeEnum>(loc), opcode(opcode) {}
+
+  Opcode opcode;
+};
+
+typedef OpcodeExpr<ExprType::Binary> BinaryExpr;
+typedef OpcodeExpr<ExprType::Compare> CompareExpr;
+typedef OpcodeExpr<ExprType::Convert> ConvertExpr;
+typedef OpcodeExpr<ExprType::Unary> UnaryExpr;
+typedef OpcodeExpr<ExprType::Ternary> TernaryExpr;
+
+class SimdLaneOpExpr : public ExprMixin<ExprType::SimdLaneOp> {
+ public:
+  SimdLaneOpExpr(Opcode opcode, uint64_t val, const Location& loc = Location())
+      : ExprMixin<ExprType::SimdLaneOp>(loc), opcode(opcode), val(val) {}
+
+  Opcode opcode;
+  uint64_t val;
+};
+
+class SimdShuffleOpExpr : public ExprMixin<ExprType::SimdShuffleOp> {
+ public:
+  SimdShuffleOpExpr(Opcode opcode, v128 val, const Location& loc = Location())
+      : ExprMixin<ExprType::SimdShuffleOp>(loc), opcode(opcode), val(val) {}
+
+  Opcode opcode;
+  v128 val;
+};
+
+template <ExprType TypeEnum>
+class VarExpr : public ExprMixin<TypeEnum> {
+ public:
+  VarExpr(const Var& var, const Location& loc = Location())
+      : ExprMixin<TypeEnum>(loc), var(var) {}
+
+  Var var;
+};
+
+typedef VarExpr<ExprType::Br> BrExpr;
+typedef VarExpr<ExprType::BrIf> BrIfExpr;
+typedef VarExpr<ExprType::Call> CallExpr;
+typedef VarExpr<ExprType::RefFunc> RefFuncExpr;
+typedef VarExpr<ExprType::GlobalGet> GlobalGetExpr;
+typedef VarExpr<ExprType::GlobalSet> GlobalSetExpr;
+typedef VarExpr<ExprType::LocalGet> LocalGetExpr;
+typedef VarExpr<ExprType::LocalSet> LocalSetExpr;
+typedef VarExpr<ExprType::LocalTee> LocalTeeExpr;
+typedef VarExpr<ExprType::ReturnCall> ReturnCallExpr;
+typedef VarExpr<ExprType::Throw> ThrowExpr;
+typedef VarExpr<ExprType::Rethrow> RethrowExpr;
+
+typedef VarExpr<ExprType::MemoryInit> MemoryInitExpr;
+typedef VarExpr<ExprType::DataDrop> DataDropExpr;
+typedef VarExpr<ExprType::ElemDrop> ElemDropExpr;
+typedef VarExpr<ExprType::TableGet> TableGetExpr;
+typedef VarExpr<ExprType::TableSet> TableSetExpr;
+typedef VarExpr<ExprType::TableGrow> TableGrowExpr;
+typedef VarExpr<ExprType::TableSize> TableSizeExpr;
+typedef VarExpr<ExprType::TableFill> TableFillExpr;
+
+class SelectExpr : public ExprMixin<ExprType::Select> {
+ public:
+  SelectExpr(TypeVector type, const Location& loc = Location())
+      : ExprMixin<ExprType::Select>(loc), result_type(type) {}
+  TypeVector result_type;
+};
+
+class TableInitExpr : public ExprMixin<ExprType::TableInit> {
+ public:
+  TableInitExpr(const Var& segment_index,
+                const Var& table_index,
+                const Location& loc = Location())
+      : ExprMixin<ExprType::TableInit>(loc),
+        segment_index(segment_index),
+        table_index(table_index) {}
+
+  Var segment_index;
+  Var table_index;
+};
+
+class TableCopyExpr : public ExprMixin<ExprType::TableCopy> {
+ public:
+  TableCopyExpr(const Var& dst,
+                const Var& src,
+                const Location& loc = Location())
+      : ExprMixin<ExprType::TableCopy>(loc), dst_table(dst), src_table(src) {}
+
+  Var dst_table;
+  Var src_table;
+};
+
+class CallIndirectExpr : public ExprMixin<ExprType::CallIndirect> {
+ public:
+  explicit CallIndirectExpr(const Location& loc = Location())
+      : ExprMixin<ExprType::CallIndirect>(loc) {}
+
+  FuncDeclaration decl;
+  Var table;
+};
+
+class ReturnCallIndirectExpr : public ExprMixin<ExprType::ReturnCallIndirect> {
+ public:
+  explicit ReturnCallIndirectExpr(const Location &loc = Location())
+      : ExprMixin<ExprType::ReturnCallIndirect>(loc) {}
+
+  FuncDeclaration decl;
+  Var table;
+};
+
+template <ExprType TypeEnum>
+class BlockExprBase : public ExprMixin<TypeEnum> {
+ public:
+  explicit BlockExprBase(const Location& loc = Location())
+      : ExprMixin<TypeEnum>(loc) {}
+
+  Block block;
+};
+
+typedef BlockExprBase<ExprType::Block> BlockExpr;
+typedef BlockExprBase<ExprType::Loop> LoopExpr;
+
+class IfExpr : public ExprMixin<ExprType::If> {
+ public:
+  explicit IfExpr(const Location& loc = Location())
+      : ExprMixin<ExprType::If>(loc) {}
+
+  Block true_;
+  ExprList false_;
+  Location false_end_loc;
+};
+
+class TryExpr : public ExprMixin<ExprType::Try> {
+ public:
+  explicit TryExpr(const Location& loc = Location())
+      : ExprMixin<ExprType::Try>(loc), kind(TryKind::Invalid) {}
+
+  TryKind kind;
+  Block block;
+  CatchVector catches;
+  ExprList unwind;
+  Var delegate_target;
+};
+
+class BrTableExpr : public ExprMixin<ExprType::BrTable> {
+ public:
+  BrTableExpr(const Location& loc = Location())
+      : ExprMixin<ExprType::BrTable>(loc) {}
+
+  VarVector targets;
+  Var default_target;
+};
+
+class ConstExpr : public ExprMixin<ExprType::Const> {
+ public:
+  ConstExpr(const Const& c, const Location& loc = Location())
+      : ExprMixin<ExprType::Const>(loc), const_(c) {}
+
+  Const const_;
+};
+
+// TODO(binji): Rename this, it is used for more than loads/stores now.
+template <ExprType TypeEnum>
+class LoadStoreExpr : public ExprMixin<TypeEnum> {
+ public:
+  LoadStoreExpr(Opcode opcode,
+                Address align,
+                Address offset,
+                const Location& loc = Location())
+      : ExprMixin<TypeEnum>(loc),
+        opcode(opcode),
+        align(align),
+        offset(offset) {}
+
+  Opcode opcode;
+  Address align;
+  Address offset;
+};
+
+typedef LoadStoreExpr<ExprType::Load> LoadExpr;
+typedef LoadStoreExpr<ExprType::Store> StoreExpr;
+typedef LoadStoreExpr<ExprType::AtomicLoad> AtomicLoadExpr;
+typedef LoadStoreExpr<ExprType::AtomicStore> AtomicStoreExpr;
+typedef LoadStoreExpr<ExprType::AtomicRmw> AtomicRmwExpr;
+typedef LoadStoreExpr<ExprType::AtomicRmwCmpxchg> AtomicRmwCmpxchgExpr;
+typedef LoadStoreExpr<ExprType::AtomicWait> AtomicWaitExpr;
+typedef LoadStoreExpr<ExprType::AtomicNotify> AtomicNotifyExpr;
+typedef LoadStoreExpr<ExprType::LoadSplat> LoadSplatExpr;
+
+class AtomicFenceExpr : public ExprMixin<ExprType::AtomicFence> {
+ public:
+  explicit AtomicFenceExpr(uint32_t consistency_model,
+                           const Location& loc = Location())
+      : ExprMixin<ExprType::AtomicFence>(loc),
+        consistency_model(consistency_model) {}
+
+  uint32_t consistency_model;
+};
+
+struct Event {
+  explicit Event(string_view name) : name(name.to_string()) {}
+
+  std::string name;
+  FuncDeclaration decl;
+};
+
+class LocalTypes {
+ public:
+  typedef std::pair<Type, Index> Decl;
+  typedef std::vector<Decl> Decls;
+
+  struct const_iterator {
+    const_iterator(Decls::const_iterator decl, Index index)
+        : decl(decl), index(index) {}
+    Type operator*() const { return decl->first; }
+    const_iterator& operator++();
+    const_iterator operator++(int);
+
+    Decls::const_iterator decl;
+    Index index;
+  };
+
+  void Set(const TypeVector&);
+
+  const Decls& decls() const { return decls_; }
+
+  void AppendDecl(Type type, Index count) {
+    if (count != 0) {
+      decls_.emplace_back(type, count);
+    }
+  }
+
+  Index size() const;
+  Type operator[](Index) const;
+
+  const_iterator begin() const { return {decls_.begin(), 0}; }
+  const_iterator end() const { return {decls_.end(), 0}; }
+
+ private:
+  Decls decls_;
+};
+
+inline LocalTypes::const_iterator& LocalTypes::const_iterator::operator++() {
+  ++index;
+  if (index >= decl->second) {
+    ++decl;
+    index = 0;
+  }
+  return *this;
+}
+
+inline LocalTypes::const_iterator LocalTypes::const_iterator::operator++(int) {
+  const_iterator result = *this;
+  operator++();
+  return result;
+}
+
+inline bool operator==(const LocalTypes::const_iterator& lhs,
+                       const LocalTypes::const_iterator& rhs) {
+  return lhs.decl == rhs.decl && lhs.index == rhs.index;
+}
+
+inline bool operator!=(const LocalTypes::const_iterator& lhs,
+                       const LocalTypes::const_iterator& rhs) {
+  return !operator==(lhs, rhs);
+}
+
+struct Func {
+  explicit Func(string_view name) : name(name.to_string()) {}
+
+  Type GetParamType(Index index) const { return decl.GetParamType(index); }
+  Type GetResultType(Index index) const { return decl.GetResultType(index); }
+  Type GetLocalType(Index index) const;
+  Type GetLocalType(const Var& var) const;
+  Index GetNumParams() const { return decl.GetNumParams(); }
+  Index GetNumLocals() const { return local_types.size(); }
+  Index GetNumParamsAndLocals() const {
+    return GetNumParams() + GetNumLocals();
+  }
+  Index GetNumResults() const { return decl.GetNumResults(); }
+  Index GetLocalIndex(const Var&) const;
+
+  std::string name;
+  FuncDeclaration decl;
+  LocalTypes local_types;
+  BindingHash bindings;
+  ExprList exprs;
+};
+
+struct Global {
+  explicit Global(string_view name) : name(name.to_string()) {}
+
+  std::string name;
+  Type type = Type::Void;
+  bool mutable_ = false;
+  ExprList init_expr;
+};
+
+struct Table {
+  explicit Table(string_view name)
+      : name(name.to_string()), elem_type(Type::FuncRef) {}
+
+  std::string name;
+  Limits elem_limits;
+  Type elem_type;
+};
+
+enum class ElemExprKind {
+  RefNull,
+  RefFunc,
+};
+
+struct ElemExpr {
+  ElemExpr() : kind(ElemExprKind::RefNull), type(Type::FuncRef) {}
+  explicit ElemExpr(Var var) : kind(ElemExprKind::RefFunc), var(var) {}
+  explicit ElemExpr(Type type) : kind(ElemExprKind::RefNull), type(type) {}
+
+  ElemExprKind kind;
+  Var var;    // Only used when kind == RefFunc.
+  Type type;  // Only used when kind == RefNull
+};
+
+typedef std::vector<ElemExpr> ElemExprVector;
+
+struct ElemSegment {
+  explicit ElemSegment(string_view name) : name(name.to_string()) {}
+  uint8_t GetFlags(const Module*) const;
+
+  SegmentKind kind = SegmentKind::Active;
+  std::string name;
+  Var table_var;
+  Type elem_type;
+  ExprList offset;
+  ElemExprVector elem_exprs;
+};
+
+struct Memory {
+  explicit Memory(string_view name) : name(name.to_string()) {}
+
+  std::string name;
+  Limits page_limits;
+};
+
+struct DataSegment {
+  explicit DataSegment(string_view name) : name(name.to_string()) {}
+  uint8_t GetFlags(const Module*) const;
+
+  SegmentKind kind = SegmentKind::Active;
+  std::string name;
+  Var memory_var;
+  ExprList offset;
+  std::vector<uint8_t> data;
+};
+
+class Import {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(Import);
+  Import() = delete;
+  virtual ~Import() = default;
+
+  ExternalKind kind() const { return kind_; }
+
+  std::string module_name;
+  std::string field_name;
+
+ protected:
+  Import(ExternalKind kind) : kind_(kind) {}
+
+  ExternalKind kind_;
+};
+
+template <ExternalKind TypeEnum>
+class ImportMixin : public Import {
+ public:
+  static bool classof(const Import* import) {
+    return import->kind() == TypeEnum;
+  }
+
+  ImportMixin() : Import(TypeEnum) {}
+};
+
+class FuncImport : public ImportMixin<ExternalKind::Func> {
+ public:
+  explicit FuncImport(string_view name = string_view())
+      : ImportMixin<ExternalKind::Func>(), func(name) {}
+
+  Func func;
+};
+
+class TableImport : public ImportMixin<ExternalKind::Table> {
+ public:
+  explicit TableImport(string_view name = string_view())
+      : ImportMixin<ExternalKind::Table>(), table(name) {}
+
+  Table table;
+};
+
+class MemoryImport : public ImportMixin<ExternalKind::Memory> {
+ public:
+  explicit MemoryImport(string_view name = string_view())
+      : ImportMixin<ExternalKind::Memory>(), memory(name) {}
+
+  Memory memory;
+};
+
+class GlobalImport : public ImportMixin<ExternalKind::Global> {
+ public:
+  explicit GlobalImport(string_view name = string_view())
+      : ImportMixin<ExternalKind::Global>(), global(name) {}
+
+  Global global;
+};
+
+class EventImport : public ImportMixin<ExternalKind::Event> {
+ public:
+  explicit EventImport(string_view name = string_view())
+      : ImportMixin<ExternalKind::Event>(), event(name) {}
+
+  Event event;
+};
+
+struct Export {
+  std::string name;
+  ExternalKind kind;
+  Var var;
+};
+
+enum class ModuleFieldType {
+  Func,
+  Global,
+  Import,
+  Export,
+  Type,
+  Table,
+  ElemSegment,
+  Memory,
+  DataSegment,
+  Start,
+  Event
+};
+
+class ModuleField : public intrusive_list_base<ModuleField> {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(ModuleField);
+  ModuleField() = delete;
+  virtual ~ModuleField() = default;
+
+  ModuleFieldType type() const { return type_; }
+
+  Location loc;
+
+ protected:
+  ModuleField(ModuleFieldType type, const Location& loc)
+      : loc(loc), type_(type) {}
+
+  ModuleFieldType type_;
+};
+
+typedef intrusive_list<ModuleField> ModuleFieldList;
+
+template <ModuleFieldType TypeEnum>
+class ModuleFieldMixin : public ModuleField {
+ public:
+  static bool classof(const ModuleField* field) {
+    return field->type() == TypeEnum;
+  }
+
+  explicit ModuleFieldMixin(const Location& loc) : ModuleField(TypeEnum, loc) {}
+};
+
+class FuncModuleField : public ModuleFieldMixin<ModuleFieldType::Func> {
+ public:
+  explicit FuncModuleField(const Location& loc = Location(),
+                           string_view name = string_view())
+      : ModuleFieldMixin<ModuleFieldType::Func>(loc), func(name) {}
+
+  Func func;
+};
+
+class GlobalModuleField : public ModuleFieldMixin<ModuleFieldType::Global> {
+ public:
+  explicit GlobalModuleField(const Location& loc = Location(),
+                             string_view name = string_view())
+      : ModuleFieldMixin<ModuleFieldType::Global>(loc), global(name) {}
+
+  Global global;
+};
+
+class ImportModuleField : public ModuleFieldMixin<ModuleFieldType::Import> {
+ public:
+  explicit ImportModuleField(const Location& loc = Location())
+      : ModuleFieldMixin<ModuleFieldType::Import>(loc) {}
+  explicit ImportModuleField(std::unique_ptr<Import> import,
+                             const Location& loc = Location())
+      : ModuleFieldMixin<ModuleFieldType::Import>(loc),
+        import(std::move(import)) {}
+
+  std::unique_ptr<Import> import;
+};
+
+class ExportModuleField : public ModuleFieldMixin<ModuleFieldType::Export> {
+ public:
+  explicit ExportModuleField(const Location& loc = Location())
+      : ModuleFieldMixin<ModuleFieldType::Export>(loc) {}
+
+  Export export_;
+};
+
+class TypeModuleField : public ModuleFieldMixin<ModuleFieldType::Type> {
+ public:
+  explicit TypeModuleField(const Location& loc = Location())
+      : ModuleFieldMixin<ModuleFieldType::Type>(loc) {}
+
+  std::unique_ptr<TypeEntry> type;
+};
+
+class TableModuleField : public ModuleFieldMixin<ModuleFieldType::Table> {
+ public:
+  explicit TableModuleField(const Location& loc = Location(),
+                            string_view name = string_view())
+      : ModuleFieldMixin<ModuleFieldType::Table>(loc), table(name) {}
+
+  Table table;
+};
+
+class ElemSegmentModuleField
+    : public ModuleFieldMixin<ModuleFieldType::ElemSegment> {
+ public:
+  explicit ElemSegmentModuleField(const Location& loc = Location(),
+                                  string_view name = string_view())
+      : ModuleFieldMixin<ModuleFieldType::ElemSegment>(loc),
+        elem_segment(name) {}
+
+  ElemSegment elem_segment;
+};
+
+class MemoryModuleField : public ModuleFieldMixin<ModuleFieldType::Memory> {
+ public:
+  explicit MemoryModuleField(const Location& loc = Location(),
+                             string_view name = string_view())
+      : ModuleFieldMixin<ModuleFieldType::Memory>(loc), memory(name) {}
+
+  Memory memory;
+};
+
+class DataSegmentModuleField
+    : public ModuleFieldMixin<ModuleFieldType::DataSegment> {
+ public:
+  explicit DataSegmentModuleField(const Location& loc = Location(),
+                                  string_view name = string_view())
+      : ModuleFieldMixin<ModuleFieldType::DataSegment>(loc),
+        data_segment(name) {}
+
+  DataSegment data_segment;
+};
+
+class EventModuleField : public ModuleFieldMixin<ModuleFieldType::Event> {
+ public:
+  explicit EventModuleField(const Location& loc = Location(),
+                            string_view name = string_view())
+      : ModuleFieldMixin<ModuleFieldType::Event>(loc), event(name) {}
+
+  Event event;
+};
+
+class StartModuleField : public ModuleFieldMixin<ModuleFieldType::Start> {
+ public:
+  explicit StartModuleField(Var start = Var(), const Location& loc = Location())
+      : ModuleFieldMixin<ModuleFieldType::Start>(loc), start(start) {}
+
+  Var start;
+};
+
+struct Module {
+  Index GetFuncTypeIndex(const Var&) const;
+  Index GetFuncTypeIndex(const FuncDeclaration&) const;
+  Index GetFuncTypeIndex(const FuncSignature&) const;
+  const FuncType* GetFuncType(const Var&) const;
+  FuncType* GetFuncType(const Var&);
+  Index GetFuncIndex(const Var&) const;
+  const Func* GetFunc(const Var&) const;
+  Func* GetFunc(const Var&);
+  Index GetTableIndex(const Var&) const;
+  const Table* GetTable(const Var&) const;
+  Table* GetTable(const Var&);
+  Index GetMemoryIndex(const Var&) const;
+  const Memory* GetMemory(const Var&) const;
+  Memory* GetMemory(const Var&);
+  Index GetGlobalIndex(const Var&) const;
+  const Global* GetGlobal(const Var&) const;
+  Global* GetGlobal(const Var&);
+  const Export* GetExport(string_view) const;
+  Event* GetEvent(const Var&) const;
+  Index GetEventIndex(const Var&) const;
+  const DataSegment* GetDataSegment(const Var&) const;
+  DataSegment* GetDataSegment(const Var&);
+  Index GetDataSegmentIndex(const Var&) const;
+  const ElemSegment* GetElemSegment(const Var&) const;
+  ElemSegment* GetElemSegment(const Var&);
+  Index GetElemSegmentIndex(const Var&) const;
+
+  bool IsImport(ExternalKind kind, const Var&) const;
+  bool IsImport(const Export& export_) const {
+    return IsImport(export_.kind, export_.var);
+  }
+
+  // TODO(binji): move this into a builder class?
+  void AppendField(std::unique_ptr<DataSegmentModuleField>);
+  void AppendField(std::unique_ptr<ElemSegmentModuleField>);
+  void AppendField(std::unique_ptr<EventModuleField>);
+  void AppendField(std::unique_ptr<ExportModuleField>);
+  void AppendField(std::unique_ptr<FuncModuleField>);
+  void AppendField(std::unique_ptr<TypeModuleField>);
+  void AppendField(std::unique_ptr<GlobalModuleField>);
+  void AppendField(std::unique_ptr<ImportModuleField>);
+  void AppendField(std::unique_ptr<MemoryModuleField>);
+  void AppendField(std::unique_ptr<StartModuleField>);
+  void AppendField(std::unique_ptr<TableModuleField>);
+  void AppendField(std::unique_ptr<ModuleField>);
+  void AppendFields(ModuleFieldList*);
+
+  Location loc;
+  std::string name;
+  ModuleFieldList fields;
+
+  Index num_event_imports = 0;
+  Index num_func_imports = 0;
+  Index num_table_imports = 0;
+  Index num_memory_imports = 0;
+  Index num_global_imports = 0;
+
+  // Cached for convenience; the pointers are shared with values that are
+  // stored in either ModuleField or Import.
+  std::vector<Event*> events;
+  std::vector<Func*> funcs;
+  std::vector<Global*> globals;
+  std::vector<Import*> imports;
+  std::vector<Export*> exports;
+  std::vector<TypeEntry*> types;
+  std::vector<Table*> tables;
+  std::vector<ElemSegment*> elem_segments;
+  std::vector<Memory*> memories;
+  std::vector<DataSegment*> data_segments;
+  std::vector<Var*> starts;
+
+  BindingHash event_bindings;
+  BindingHash func_bindings;
+  BindingHash global_bindings;
+  BindingHash export_bindings;
+  BindingHash type_bindings;
+  BindingHash table_bindings;
+  BindingHash memory_bindings;
+  BindingHash data_segment_bindings;
+  BindingHash elem_segment_bindings;
+};
+
+enum class ScriptModuleType {
+  Text,
+  Binary,
+  Quoted,
+};
+
+// A ScriptModule is a module that may not yet be decoded. This allows for text
+// and binary parsing errors to be deferred until validation time.
+class ScriptModule {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(ScriptModule);
+  ScriptModule() = delete;
+  virtual ~ScriptModule() = default;
+
+  ScriptModuleType type() const { return type_; }
+  virtual const Location& location() const = 0;
+
+ protected:
+  explicit ScriptModule(ScriptModuleType type) : type_(type) {}
+
+  ScriptModuleType type_;
+};
+
+template <ScriptModuleType TypeEnum>
+class ScriptModuleMixin : public ScriptModule {
+ public:
+  static bool classof(const ScriptModule* script_module) {
+    return script_module->type() == TypeEnum;
+  }
+
+  ScriptModuleMixin() : ScriptModule(TypeEnum) {}
+};
+
+class TextScriptModule : public ScriptModuleMixin<ScriptModuleType::Text> {
+ public:
+  const Location& location() const override { return module.loc; }
+
+  Module module;
+};
+
+template <ScriptModuleType TypeEnum>
+class DataScriptModule : public ScriptModuleMixin<TypeEnum> {
+ public:
+  const Location& location() const override { return loc; }
+
+  Location loc;
+  std::string name;
+  std::vector<uint8_t> data;
+};
+
+typedef DataScriptModule<ScriptModuleType::Binary> BinaryScriptModule;
+typedef DataScriptModule<ScriptModuleType::Quoted> QuotedScriptModule;
+
+enum class ActionType {
+  Invoke,
+  Get,
+};
+
+class Action {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(Action);
+  Action() = delete;
+  virtual ~Action() = default;
+
+  ActionType type() const { return type_; }
+
+  Location loc;
+  Var module_var;
+  std::string name;
+
+ protected:
+  explicit Action(ActionType type, const Location& loc = Location())
+      : loc(loc), type_(type) {}
+
+  ActionType type_;
+};
+
+typedef std::unique_ptr<Action> ActionPtr;
+
+template <ActionType TypeEnum>
+class ActionMixin : public Action {
+ public:
+  static bool classof(const Action* action) {
+    return action->type() == TypeEnum;
+  }
+
+  explicit ActionMixin(const Location& loc = Location())
+      : Action(TypeEnum, loc) {}
+};
+
+class GetAction : public ActionMixin<ActionType::Get> {
+ public:
+  explicit GetAction(const Location& loc = Location())
+      : ActionMixin<ActionType::Get>(loc) {}
+};
+
+class InvokeAction : public ActionMixin<ActionType::Invoke> {
+ public:
+  explicit InvokeAction(const Location& loc = Location())
+      : ActionMixin<ActionType::Invoke>(loc) {}
+
+  ConstVector args;
+};
+
+enum class CommandType {
+  Module,
+  Action,
+  Register,
+  AssertMalformed,
+  AssertInvalid,
+  AssertUnlinkable,
+  AssertUninstantiable,
+  AssertReturn,
+  AssertTrap,
+  AssertExhaustion,
+
+  First = Module,
+  Last = AssertExhaustion,
+};
+static const int kCommandTypeCount = WABT_ENUM_COUNT(CommandType);
+
+class Command {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(Command);
+  Command() = delete;
+  virtual ~Command() = default;
+
+  CommandType type;
+
+ protected:
+  explicit Command(CommandType type) : type(type) {}
+};
+
+template <CommandType TypeEnum>
+class CommandMixin : public Command {
+ public:
+  static bool classof(const Command* cmd) { return cmd->type == TypeEnum; }
+  CommandMixin() : Command(TypeEnum) {}
+};
+
+class ModuleCommand : public CommandMixin<CommandType::Module> {
+ public:
+  Module module;
+};
+
+template <CommandType TypeEnum>
+class ActionCommandBase : public CommandMixin<TypeEnum> {
+ public:
+  ActionPtr action;
+};
+
+typedef ActionCommandBase<CommandType::Action> ActionCommand;
+
+class RegisterCommand : public CommandMixin<CommandType::Register> {
+ public:
+  RegisterCommand(string_view module_name, const Var& var)
+      : module_name(module_name), var(var) {}
+
+  std::string module_name;
+  Var var;
+};
+
+class AssertReturnCommand : public CommandMixin<CommandType::AssertReturn> {
+ public:
+  ActionPtr action;
+  ConstVector expected;
+};
+
+template <CommandType TypeEnum>
+class AssertTrapCommandBase : public CommandMixin<TypeEnum> {
+ public:
+  ActionPtr action;
+  std::string text;
+};
+
+typedef AssertTrapCommandBase<CommandType::AssertTrap> AssertTrapCommand;
+typedef AssertTrapCommandBase<CommandType::AssertExhaustion>
+    AssertExhaustionCommand;
+
+template <CommandType TypeEnum>
+class AssertModuleCommand : public CommandMixin<TypeEnum> {
+ public:
+  std::unique_ptr<ScriptModule> module;
+  std::string text;
+};
+
+typedef AssertModuleCommand<CommandType::AssertMalformed>
+    AssertMalformedCommand;
+typedef AssertModuleCommand<CommandType::AssertInvalid> AssertInvalidCommand;
+typedef AssertModuleCommand<CommandType::AssertUnlinkable>
+    AssertUnlinkableCommand;
+typedef AssertModuleCommand<CommandType::AssertUninstantiable>
+    AssertUninstantiableCommand;
+
+typedef std::unique_ptr<Command> CommandPtr;
+typedef std::vector<CommandPtr> CommandPtrVector;
+
+struct Script {
+  WABT_DISALLOW_COPY_AND_ASSIGN(Script);
+  Script() = default;
+
+  const Module* GetFirstModule() const;
+  Module* GetFirstModule();
+  const Module* GetModule(const Var&) const;
+
+  CommandPtrVector commands;
+  BindingHash module_bindings;
+};
+
+void MakeTypeBindingReverseMapping(
+    size_t num_types,
+    const BindingHash& bindings,
+    std::vector<std::string>* out_reverse_mapping);
+
+}  // namespace wabt
+
+#endif /* WABT_IR_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.cc
new file mode 100644 (file)
index 0000000..044aaf0
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * 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/leb128.h"
+
+#include <type_traits>
+
+#include "src/stream.h"
+
+#define MAX_U32_LEB128_BYTES 5
+#define MAX_U64_LEB128_BYTES 10
+
+namespace wabt {
+
+Offset U32Leb128Length(uint32_t value) {
+  uint32_t size = 0;
+  do {
+    value >>= 7;
+    size++;
+  } while (value != 0);
+  return size;
+}
+
+#define LEB128_LOOP_UNTIL(end_cond) \
+  do {                              \
+    uint8_t byte = value & 0x7f;    \
+    value >>= 7;                    \
+    if (end_cond) {                 \
+      data[length++] = byte;        \
+      break;                        \
+    } else {                        \
+      data[length++] = byte | 0x80; \
+    }                               \
+  } while (1)
+
+Offset WriteFixedU32Leb128At(Stream* stream,
+                             Offset offset,
+                             uint32_t value,
+                             const char* desc) {
+  uint8_t data[MAX_U32_LEB128_BYTES];
+  Offset length =
+      WriteFixedU32Leb128Raw(data, data + MAX_U32_LEB128_BYTES, value);
+  stream->WriteDataAt(offset, data, length, desc);
+  return length;
+}
+
+void WriteU32Leb128(Stream* stream, uint32_t value, const char* desc) {
+  uint8_t data[MAX_U32_LEB128_BYTES];
+  Offset length = 0;
+  LEB128_LOOP_UNTIL(value == 0);
+  stream->WriteData(data, length, desc);
+}
+
+void WriteFixedU32Leb128(Stream* stream, uint32_t value, const char* desc) {
+  uint8_t data[MAX_U32_LEB128_BYTES];
+  Offset length =
+      WriteFixedU32Leb128Raw(data, data + MAX_U32_LEB128_BYTES, value);
+  stream->WriteData(data, length, desc);
+}
+
+// returns the length of the leb128.
+Offset WriteU32Leb128At(Stream* stream,
+                        Offset offset,
+                        uint32_t value,
+                        const char* desc) {
+  uint8_t data[MAX_U32_LEB128_BYTES];
+  Offset length = 0;
+  LEB128_LOOP_UNTIL(value == 0);
+  stream->WriteDataAt(offset, data, length, desc);
+  return length;
+}
+
+Offset WriteU32Leb128Raw(uint8_t* dest, uint8_t* dest_end, uint32_t value) {
+  uint8_t data[MAX_U32_LEB128_BYTES];
+  Offset length = 0;
+  LEB128_LOOP_UNTIL(value == 0);
+  if (static_cast<Offset>(dest_end - dest) < length) {
+    return 0;
+  }
+  memcpy(dest, data, length);
+  return length;
+}
+
+Offset WriteFixedU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value) {
+  if (end - data < MAX_U32_LEB128_BYTES) {
+    return 0;
+  }
+  data[0] = (value & 0x7f) | 0x80;
+  data[1] = ((value >> 7) & 0x7f) | 0x80;
+  data[2] = ((value >> 14) & 0x7f) | 0x80;
+  data[3] = ((value >> 21) & 0x7f) | 0x80;
+  data[4] = ((value >> 28) & 0x0f);
+  return MAX_U32_LEB128_BYTES;
+}
+
+static void WriteS32Leb128(Stream* stream, int32_t value, const char* desc) {
+  uint8_t data[MAX_U32_LEB128_BYTES];
+  Offset length = 0;
+  if (value < 0) {
+    LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40));
+  } else {
+    LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40));
+  }
+
+  stream->WriteData(data, length, desc);
+}
+
+static void WriteS64Leb128(Stream* stream, int64_t value, const char* desc) {
+  uint8_t data[MAX_U64_LEB128_BYTES];
+  Offset length = 0;
+  if (value < 0) {
+    LEB128_LOOP_UNTIL(value == -1 && (byte & 0x40));
+  } else {
+    LEB128_LOOP_UNTIL(value == 0 && !(byte & 0x40));
+  }
+
+  stream->WriteData(data, length, desc);
+}
+
+void WriteS32Leb128(Stream* stream, uint32_t value, const char* desc) {
+  WriteS32Leb128(stream, Bitcast<int32_t>(value), desc);
+}
+
+void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc) {
+  WriteS64Leb128(stream, Bitcast<int64_t>(value), desc);
+}
+
+void WriteFixedS32Leb128(Stream* stream, uint32_t value, const char* desc) {
+  uint8_t data[MAX_U32_LEB128_BYTES];
+  data[0] = (value & 0x7f) | 0x80;
+  data[1] = ((value >> 7) & 0x7f) | 0x80;
+  data[2] = ((value >> 14) & 0x7f) | 0x80;
+  data[3] = ((value >> 21) & 0x7f) | 0x80;
+  // The last byte needs to be sign-extended.
+  data[4] = ((value >> 28) & 0x0f);
+  if (static_cast<int32_t>(value) < 0) {
+    data[4] |= 0x70;
+  }
+  stream->WriteData(data, MAX_U32_LEB128_BYTES, desc);
+}
+
+#undef LEB128_LOOP_UNTIL
+
+#define BYTE_AT(type, i, shift) ((static_cast<type>(p[i]) & 0x7f) << (shift))
+
+#define LEB128_1(type) (BYTE_AT(type, 0, 0))
+#define LEB128_2(type) (BYTE_AT(type, 1, 7) | LEB128_1(type))
+#define LEB128_3(type) (BYTE_AT(type, 2, 14) | LEB128_2(type))
+#define LEB128_4(type) (BYTE_AT(type, 3, 21) | LEB128_3(type))
+#define LEB128_5(type) (BYTE_AT(type, 4, 28) | LEB128_4(type))
+#define LEB128_6(type) (BYTE_AT(type, 5, 35) | LEB128_5(type))
+#define LEB128_7(type) (BYTE_AT(type, 6, 42) | LEB128_6(type))
+#define LEB128_8(type) (BYTE_AT(type, 7, 49) | LEB128_7(type))
+#define LEB128_9(type) (BYTE_AT(type, 8, 56) | LEB128_8(type))
+#define LEB128_10(type) (BYTE_AT(type, 9, 63) | LEB128_9(type))
+
+#define SHIFT_AMOUNT(type, sign_bit) (sizeof(type) * 8 - 1 - (sign_bit))
+#define SIGN_EXTEND(type, value, sign_bit)                       \
+  (static_cast<type>((value) << SHIFT_AMOUNT(type, sign_bit)) >> \
+   SHIFT_AMOUNT(type, sign_bit))
+
+size_t ReadU32Leb128(const uint8_t* p,
+                     const uint8_t* end,
+                     uint32_t* out_value) {
+  if (p < end && (p[0] & 0x80) == 0) {
+    *out_value = LEB128_1(uint32_t);
+    return 1;
+  } else if (p + 1 < end && (p[1] & 0x80) == 0) {
+    *out_value = LEB128_2(uint32_t);
+    return 2;
+  } else if (p + 2 < end && (p[2] & 0x80) == 0) {
+    *out_value = LEB128_3(uint32_t);
+    return 3;
+  } else if (p + 3 < end && (p[3] & 0x80) == 0) {
+    *out_value = LEB128_4(uint32_t);
+    return 4;
+  } else if (p + 4 < end && (p[4] & 0x80) == 0) {
+    // The top bits set represent values > 32 bits.
+    if (p[4] & 0xf0) {
+      return 0;
+    }
+    *out_value = LEB128_5(uint32_t);
+    return 5;
+  } else {
+    // past the end.
+    *out_value = 0;
+    return 0;
+  }
+}
+
+size_t ReadU64Leb128(const uint8_t* p,
+                     const uint8_t* end,
+                     uint64_t* out_value) {
+  if (p < end && (p[0] & 0x80) == 0) {
+    *out_value = LEB128_1(uint64_t);
+    return 1;
+  } else if (p + 1 < end && (p[1] & 0x80) == 0) {
+    *out_value = LEB128_2(uint64_t);
+    return 2;
+  } else if (p + 2 < end && (p[2] & 0x80) == 0) {
+    *out_value = LEB128_3(uint64_t);
+    return 3;
+  } else if (p + 3 < end && (p[3] & 0x80) == 0) {
+    *out_value = LEB128_4(uint64_t);
+    return 4;
+  } else if (p + 4 < end && (p[4] & 0x80) == 0) {
+    *out_value = LEB128_5(uint64_t);
+    return 5;
+  } else if (p + 5 < end && (p[5] & 0x80) == 0) {
+    *out_value = LEB128_6(uint64_t);
+    return 6;
+  } else if (p + 6 < end && (p[6] & 0x80) == 0) {
+    *out_value = LEB128_7(uint64_t);
+    return 7;
+  } else if (p + 7 < end && (p[7] & 0x80) == 0) {
+    *out_value = LEB128_8(uint64_t);
+    return 8;
+  } else if (p + 8 < end && (p[8] & 0x80) == 0) {
+    *out_value = LEB128_9(uint64_t);
+    return 9;
+  } else if (p + 9 < end && (p[9] & 0x80) == 0) {
+    // The top bits set represent values > 32 bits.
+    if (p[9] & 0xf0) {
+      return 0;
+    }
+    *out_value = LEB128_10(uint64_t);
+    return 10;
+  } else {
+    // past the end.
+    *out_value = 0;
+    return 0;
+  }
+}
+
+size_t ReadS32Leb128(const uint8_t* p,
+                     const uint8_t* end,
+                     uint32_t* out_value) {
+  if (p < end && (p[0] & 0x80) == 0) {
+    uint32_t result = LEB128_1(uint32_t);
+    *out_value = SIGN_EXTEND(int32_t, result, 6);
+    return 1;
+  } else if (p + 1 < end && (p[1] & 0x80) == 0) {
+    uint32_t result = LEB128_2(uint32_t);
+    *out_value = SIGN_EXTEND(int32_t, result, 13);
+    return 2;
+  } else if (p + 2 < end && (p[2] & 0x80) == 0) {
+    uint32_t result = LEB128_3(uint32_t);
+    *out_value = SIGN_EXTEND(int32_t, result, 20);
+    return 3;
+  } else if (p + 3 < end && (p[3] & 0x80) == 0) {
+    uint32_t result = LEB128_4(uint32_t);
+    *out_value = SIGN_EXTEND(int32_t, result, 27);
+    return 4;
+  } else if (p + 4 < end && (p[4] & 0x80) == 0) {
+    // The top bits should be a sign-extension of the sign bit.
+    bool sign_bit_set = (p[4] & 0x8);
+    int top_bits = p[4] & 0xf0;
+    if ((sign_bit_set && top_bits != 0x70) ||
+        (!sign_bit_set && top_bits != 0)) {
+      return 0;
+    }
+    uint32_t result = LEB128_5(uint32_t);
+    *out_value = result;
+    return 5;
+  } else {
+    // Past the end.
+    return 0;
+  }
+}
+
+size_t ReadS64Leb128(const uint8_t* p,
+                     const uint8_t* end,
+                     uint64_t* out_value) {
+  if (p < end && (p[0] & 0x80) == 0) {
+    uint64_t result = LEB128_1(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 6);
+    return 1;
+  } else if (p + 1 < end && (p[1] & 0x80) == 0) {
+    uint64_t result = LEB128_2(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 13);
+    return 2;
+  } else if (p + 2 < end && (p[2] & 0x80) == 0) {
+    uint64_t result = LEB128_3(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 20);
+    return 3;
+  } else if (p + 3 < end && (p[3] & 0x80) == 0) {
+    uint64_t result = LEB128_4(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 27);
+    return 4;
+  } else if (p + 4 < end && (p[4] & 0x80) == 0) {
+    uint64_t result = LEB128_5(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 34);
+    return 5;
+  } else if (p + 5 < end && (p[5] & 0x80) == 0) {
+    uint64_t result = LEB128_6(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 41);
+    return 6;
+  } else if (p + 6 < end && (p[6] & 0x80) == 0) {
+    uint64_t result = LEB128_7(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 48);
+    return 7;
+  } else if (p + 7 < end && (p[7] & 0x80) == 0) {
+    uint64_t result = LEB128_8(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 55);
+    return 8;
+  } else if (p + 8 < end && (p[8] & 0x80) == 0) {
+    uint64_t result = LEB128_9(uint64_t);
+    *out_value = SIGN_EXTEND(int64_t, result, 62);
+    return 9;
+  } else if (p + 9 < end && (p[9] & 0x80) == 0) {
+    // The top bits should be a sign-extension of the sign bit.
+    bool sign_bit_set = (p[9] & 0x1);
+    int top_bits = p[9] & 0xfe;
+    if ((sign_bit_set && top_bits != 0x7e) ||
+        (!sign_bit_set && top_bits != 0)) {
+      return 0;
+    }
+    uint64_t result = LEB128_10(uint64_t);
+    *out_value = result;
+    return 10;
+  } else {
+    // Past the end.
+    return 0;
+  }
+}
+
+#undef BYTE_AT
+#undef LEB128_1
+#undef LEB128_2
+#undef LEB128_3
+#undef LEB128_4
+#undef LEB128_5
+#undef LEB128_6
+#undef LEB128_7
+#undef LEB128_8
+#undef LEB128_9
+#undef LEB128_10
+#undef SHIFT_AMOUNT
+#undef SIGN_EXTEND
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/leb128.h
new file mode 100644 (file)
index 0000000..5bf4e46
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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_LEB128_H_
+#define WABT_LEB128_H_
+
+#include <cstdint>
+
+#include "src/common.h"
+
+namespace wabt {
+
+class Stream;
+
+// Returns the length of the leb128.
+Offset U32Leb128Length(uint32_t value);
+
+void WriteU32Leb128(Stream* stream, uint32_t value, const char* desc);
+void WriteS32Leb128(Stream* stream, uint32_t value, const char* desc);
+void WriteS64Leb128(Stream* stream, uint64_t value, const char* desc);
+void WriteFixedS32Leb128(Stream* stream, uint32_t value, const char* desc);
+void WriteFixedU32Leb128(Stream* stream, uint32_t value, const char* desc);
+
+Offset WriteU32Leb128At(Stream* stream,
+                        Offset offset,
+                        uint32_t value,
+                        const char* desc);
+
+Offset WriteFixedU32Leb128At(Stream* stream,
+                             Offset offset,
+                             uint32_t value,
+                             const char* desc);
+
+Offset WriteU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value);
+Offset WriteFixedU32Leb128Raw(uint8_t* data, uint8_t* end, uint32_t value);
+
+// Convenience functions for writing enums as LEB128s.
+template <typename T>
+void WriteU32Leb128(Stream* stream, T value, const char* desc) {
+  WriteU32Leb128(stream, static_cast<uint32_t>(value), desc);
+}
+
+template <typename T>
+void WriteS32Leb128(Stream* stream, T value, const char* desc) {
+  WriteS32Leb128(stream, static_cast<uint32_t>(value), desc);
+}
+
+// Returns the length of the leb128.
+size_t ReadU32Leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value);
+size_t ReadU64Leb128(const uint8_t* p, const uint8_t* end, uint64_t* out_value);
+size_t ReadS32Leb128(const uint8_t* p, const uint8_t* end, uint32_t* out_value);
+size_t ReadS64Leb128(const uint8_t* p, const uint8_t* end, uint64_t* out_value);
+
+}  // namespace wabt
+
+#endif  // WABT_LEB128_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-keywords.txt b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-keywords.txt
new file mode 100644 (file)
index 0000000..b62c28b
--- /dev/null
@@ -0,0 +1,585 @@
+struct TokenInfo {
+  TokenInfo(const char* name) : name(name) {}
+  TokenInfo(const char* name, TokenType token_type)
+      : name(name), token_type(token_type) {}
+  TokenInfo(const char* name, Type value_type)
+      : name(name), token_type(TokenType::ValueType), value_type(value_type) {}
+  TokenInfo(const char* name, Type value_type, TokenType token_type)
+      : name(name), token_type(token_type), value_type(value_type) {}
+  TokenInfo(const char* name, TokenType token_type, Opcode opcode)
+      : name(name), token_type(token_type), opcode(opcode) {}
+
+  const char* name;
+  TokenType token_type;
+  union {
+    Type value_type;
+    Opcode opcode;
+  };
+};
+%%
+array, Type::Array, TokenType::Array
+assert_exhaustion, TokenType::AssertExhaustion
+assert_invalid, TokenType::AssertInvalid
+assert_malformed, TokenType::AssertMalformed
+assert_return, TokenType::AssertReturn
+assert_trap, TokenType::AssertTrap
+assert_unlinkable, TokenType::AssertUnlinkable
+atomic.fence, TokenType::AtomicFence, Opcode::AtomicFence
+binary, TokenType::Bin
+block, TokenType::Block, Opcode::Block
+br_if, TokenType::BrIf, Opcode::BrIf
+br_table, TokenType::BrTable, Opcode::BrTable
+br, TokenType::Br, Opcode::Br
+call_indirect, TokenType::CallIndirect, Opcode::CallIndirect
+call, TokenType::Call, Opcode::Call
+catch, TokenType::Catch, Opcode::Catch
+catch_all, TokenType::CatchAll, Opcode::CatchAll
+current_memory, TokenType::MemorySize, Opcode::MemorySize
+data.drop, TokenType::DataDrop, Opcode::DataDrop
+data, TokenType::Data
+declare, TokenType::Declare
+delegate, TokenType::Delegate
+do, TokenType::Do
+drop, TokenType::Drop, Opcode::Drop
+elem.drop, TokenType::ElemDrop, Opcode::ElemDrop
+elem, TokenType::Elem
+else, TokenType::Else, Opcode::Else
+end, TokenType::End, Opcode::End
+event, TokenType::Event
+extern, Type::ExternRef, TokenType::Extern
+externref, Type::ExternRef
+export, TokenType::Export
+f32.abs, TokenType::Unary, Opcode::F32Abs
+f32.add, TokenType::Binary, Opcode::F32Add
+f32.ceil, TokenType::Unary, Opcode::F32Ceil
+f32.const, TokenType::Const, Opcode::F32Const
+f32.convert_i32_s, TokenType::Convert, Opcode::F32ConvertI32S
+f32.convert_i32_u, TokenType::Convert, Opcode::F32ConvertI32U
+f32.convert_i64_s, TokenType::Convert, Opcode::F32ConvertI64S
+f32.convert_i64_u, TokenType::Convert, Opcode::F32ConvertI64U
+f32.copysign, TokenType::Binary, Opcode::F32Copysign
+f32.demote_f64, TokenType::Convert, Opcode::F32DemoteF64
+f32.div, TokenType::Binary, Opcode::F32Div
+f32.eq, TokenType::Compare, Opcode::F32Eq
+f32.floor, TokenType::Unary, Opcode::F32Floor
+f32.ge, TokenType::Compare, Opcode::F32Ge
+f32.gt, TokenType::Compare, Opcode::F32Gt
+f32.le, TokenType::Compare, Opcode::F32Le
+f32.load, TokenType::Load, Opcode::F32Load
+f32.lt, TokenType::Compare, Opcode::F32Lt
+f32.max, TokenType::Binary, Opcode::F32Max
+f32.min, TokenType::Binary, Opcode::F32Min
+f32.mul, TokenType::Binary, Opcode::F32Mul
+f32.nearest, TokenType::Unary, Opcode::F32Nearest
+f32.neg, TokenType::Unary, Opcode::F32Neg
+f32.ne, TokenType::Compare, Opcode::F32Ne
+f32.reinterpret_i32, TokenType::Convert, Opcode::F32ReinterpretI32
+f32.sqrt, TokenType::Unary, Opcode::F32Sqrt
+f32.store, TokenType::Store, Opcode::F32Store
+f32.sub, TokenType::Binary, Opcode::F32Sub
+f32.trunc, TokenType::Unary, Opcode::F32Trunc
+f32, Type::F32
+f32x4.abs, TokenType::Unary, Opcode::F32X4Abs
+f32x4.add, TokenType::Binary, Opcode::F32X4Add
+f32x4.ceil, TokenType::Unary, Opcode::F32X4Ceil
+f32x4.convert_i32x4_s, TokenType::Unary, Opcode::F32X4ConvertI32X4S
+f32x4.convert_i32x4_u, TokenType::Unary, Opcode::F32X4ConvertI32X4U
+f32x4.div, TokenType::Binary, Opcode::F32X4Div
+f32x4.eq, TokenType::Compare, Opcode::F32X4Eq
+f32x4.extract_lane, TokenType::SimdLaneOp, Opcode::F32X4ExtractLane
+f32x4.floor, TokenType::Unary, Opcode::F32X4Floor
+f32x4.ge, TokenType::Compare, Opcode::F32X4Ge
+f32x4.gt, TokenType::Compare, Opcode::F32X4Gt
+f32x4.le, TokenType::Compare, Opcode::F32X4Le
+f32x4.lt, TokenType::Compare, Opcode::F32X4Lt
+f32x4.max, TokenType::Binary, Opcode::F32X4Max
+f32x4.min, TokenType::Binary, Opcode::F32X4Min
+f32x4.mul, TokenType::Binary, Opcode::F32X4Mul
+f32x4.nearest, TokenType::Unary, Opcode::F32X4Nearest
+f32x4.neg, TokenType::Unary, Opcode::F32X4Neg
+f32x4.ne, TokenType::Compare, Opcode::F32X4Ne
+f32x4.pmax, TokenType::Binary, Opcode::F32X4PMax
+f32x4.pmin, TokenType::Binary, Opcode::F32X4PMin
+f32x4.replace_lane, TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane
+f32x4.splat, TokenType::Unary, Opcode::F32X4Splat
+f32x4.sqrt, TokenType::Unary, Opcode::F32X4Sqrt
+f32x4.sub, TokenType::Binary, Opcode::F32X4Sub
+f32x4.trunc, TokenType::Unary, Opcode::F32X4Trunc
+f32x4, TokenType::F32X4
+f64.abs, TokenType::Unary, Opcode::F64Abs
+f64.add, TokenType::Binary, Opcode::F64Add
+f64.ceil, TokenType::Unary, Opcode::F64Ceil
+f64.const, TokenType::Const, Opcode::F64Const
+f64.convert_i32_s, TokenType::Convert, Opcode::F64ConvertI32S
+f64.convert_i32_u, TokenType::Convert, Opcode::F64ConvertI32U
+f64.convert_i64_s, TokenType::Convert, Opcode::F64ConvertI64S
+f64.convert_i64_u, TokenType::Convert, Opcode::F64ConvertI64U
+f64.copysign, TokenType::Binary, Opcode::F64Copysign
+f64.div, TokenType::Binary, Opcode::F64Div
+f64.eq, TokenType::Compare, Opcode::F64Eq
+f64.floor, TokenType::Unary, Opcode::F64Floor
+f64.ge, TokenType::Compare, Opcode::F64Ge
+f64.gt, TokenType::Compare, Opcode::F64Gt
+f64.le, TokenType::Compare, Opcode::F64Le
+f64.load, TokenType::Load, Opcode::F64Load
+f64.lt, TokenType::Compare, Opcode::F64Lt
+f64.max, TokenType::Binary, Opcode::F64Max
+f64.min, TokenType::Binary, Opcode::F64Min
+f64.mul, TokenType::Binary, Opcode::F64Mul
+f64.nearest, TokenType::Unary, Opcode::F64Nearest
+f64.neg, TokenType::Unary, Opcode::F64Neg
+f64.ne, TokenType::Compare, Opcode::F64Ne
+f64.promote_f32, TokenType::Convert, Opcode::F64PromoteF32
+f64.reinterpret_i64, TokenType::Convert, Opcode::F64ReinterpretI64
+f64.sqrt, TokenType::Unary, Opcode::F64Sqrt
+f64.store, TokenType::Store, Opcode::F64Store
+f64.sub, TokenType::Binary, Opcode::F64Sub
+f64.trunc, TokenType::Unary, Opcode::F64Trunc
+f64, Type::F64
+f64x2.abs, TokenType::Unary, Opcode::F64X2Abs
+f64x2.add, TokenType::Binary, Opcode::F64X2Add
+f64x2.ceil, TokenType::Unary, Opcode::F64X2Ceil
+f64x2.div, TokenType::Binary, Opcode::F64X2Div
+f64x2.eq, TokenType::Compare, Opcode::F64X2Eq
+f64x2.extract_lane, TokenType::SimdLaneOp, Opcode::F64X2ExtractLane
+f64x2.floor, TokenType::Unary, Opcode::F64X2Floor
+f64x2.ge, TokenType::Compare, Opcode::F64X2Ge
+f64x2.gt, TokenType::Compare, Opcode::F64X2Gt
+f64x2.le, TokenType::Compare, Opcode::F64X2Le
+f64x2.lt, TokenType::Compare, Opcode::F64X2Lt
+f64x2.max, TokenType::Binary, Opcode::F64X2Max
+f64x2.min, TokenType::Binary, Opcode::F64X2Min
+f64x2.mul, TokenType::Binary, Opcode::F64X2Mul
+f64x2.nearest, TokenType::Unary, Opcode::F64X2Nearest
+f64x2.neg, TokenType::Unary, Opcode::F64X2Neg
+f64x2.ne, TokenType::Compare, Opcode::F64X2Ne
+f64x2.pmax, TokenType::Binary, Opcode::F64X2PMax
+f64x2.pmin, TokenType::Binary, Opcode::F64X2PMin
+f64x2.replace_lane, TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane
+f64x2.splat, TokenType::Unary, Opcode::F64X2Splat
+f64x2.sqrt, TokenType::Unary, Opcode::F64X2Sqrt
+f64x2.sub, TokenType::Binary, Opcode::F64X2Sub
+f64x2.trunc, TokenType::Unary, Opcode::F64X2Trunc
+f64x2, TokenType::F64X2
+field, TokenType::Field
+funcref, Type::FuncRef
+func, Type::FuncRef, TokenType::Func
+get, TokenType::Get
+global.get, TokenType::GlobalGet, Opcode::GlobalGet
+global.set, TokenType::GlobalSet, Opcode::GlobalSet
+global, TokenType::Global
+grow_memory, TokenType::MemoryGrow, Opcode::MemoryGrow
+i16x8.abs, TokenType::Unary, Opcode::I16X8Abs
+i16x8.add_sat_s, TokenType::Binary, Opcode::I16X8AddSatS
+i16x8.add_sat_u, TokenType::Binary, Opcode::I16X8AddSatU
+i16x8.add, TokenType::Binary, Opcode::I16X8Add
+i16x8.all_true, TokenType::Unary, Opcode::I16X8AllTrue
+i16x8.any_true, TokenType::Unary, Opcode::I16X8AnyTrue
+i16x8.avgr_u, TokenType::Binary, Opcode::I16X8AvgrU
+i16x8.bitmask, TokenType::Unary, Opcode::I16X8Bitmask
+i16x8.eq, TokenType::Compare, Opcode::I16X8Eq
+i16x8.extract_lane_s, TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS
+i16x8.extract_lane_u, TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU
+i16x8.ge_s, TokenType::Compare, Opcode::I16X8GeS
+i16x8.ge_u, TokenType::Compare, Opcode::I16X8GeU
+i16x8.gt_s, TokenType::Compare, Opcode::I16X8GtS
+i16x8.gt_u, TokenType::Compare, Opcode::I16X8GtU
+i16x8.le_s, TokenType::Compare, Opcode::I16X8LeS
+i16x8.le_u, TokenType::Compare, Opcode::I16X8LeU
+v128.load8x8_s, TokenType::Load, Opcode::V128Load8X8S
+v128.load8x8_u, TokenType::Load, Opcode::V128Load8X8U
+i16x8.lt_s, TokenType::Compare, Opcode::I16X8LtS
+i16x8.lt_u, TokenType::Compare, Opcode::I16X8LtU
+i16x8.max_s, TokenType::Binary, Opcode::I16X8MaxS
+i16x8.max_u, TokenType::Binary, Opcode::I16X8MaxU
+i16x8.min_s, TokenType::Binary, Opcode::I16X8MinS
+i16x8.min_u, TokenType::Binary, Opcode::I16X8MinU
+i16x8.mul, TokenType::Binary, Opcode::I16X8Mul
+i16x8.narrow_i32x4_s, TokenType::Binary, Opcode::I16X8NarrowI32X4S
+i16x8.narrow_i32x4_u, TokenType::Binary, Opcode::I16X8NarrowI32X4U
+i16x8.neg, TokenType::Unary, Opcode::I16X8Neg
+i16x8.ne, TokenType::Compare, Opcode::I16X8Ne
+i16x8.replace_lane, TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane
+i16x8.shl, TokenType::Binary, Opcode::I16X8Shl
+i16x8.shr_s, TokenType::Binary, Opcode::I16X8ShrS
+i16x8.shr_u, TokenType::Binary, Opcode::I16X8ShrU
+i16x8.splat, TokenType::Unary, Opcode::I16X8Splat
+i16x8.sub_sat_s, TokenType::Binary, Opcode::I16X8SubSatS
+i16x8.sub_sat_u, TokenType::Binary, Opcode::I16X8SubSatU
+i16x8.sub, TokenType::Binary, Opcode::I16X8Sub
+i16x8, TokenType::I16X8
+i16x8.widen_high_i8x16_s, TokenType::Unary, Opcode::I16X8WidenHighI8X16S
+i16x8.widen_high_i8x16_u, TokenType::Unary, Opcode::I16X8WidenHighI8X16U
+i16x8.widen_low_i8x16_s, TokenType::Unary, Opcode::I16X8WidenLowI8X16S
+i16x8.widen_low_i8x16_u, TokenType::Unary, Opcode::I16X8WidenLowI8X16U
+i32.add, TokenType::Binary, Opcode::I32Add
+i32.and, TokenType::Binary, Opcode::I32And
+i32.atomic.load16_u, TokenType::AtomicLoad, Opcode::I32AtomicLoad16U
+i32.atomic.load8_u, TokenType::AtomicLoad, Opcode::I32AtomicLoad8U
+i32.atomic.load, TokenType::AtomicLoad, Opcode::I32AtomicLoad
+i32.atomic.rmw16.add_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU
+i32.atomic.rmw16.and_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU
+i32.atomic.rmw16.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU
+i32.atomic.rmw16.or_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU
+i32.atomic.rmw16.sub_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU
+i32.atomic.rmw16.xchg_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU
+i32.atomic.rmw16.xor_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU
+i32.atomic.rmw8.add_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU
+i32.atomic.rmw8.and_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU
+i32.atomic.rmw8.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU
+i32.atomic.rmw8.or_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU
+i32.atomic.rmw8.sub_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU
+i32.atomic.rmw8.xchg_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU
+i32.atomic.rmw8.xor_u, TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU
+i32.atomic.rmw.add, TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd
+i32.atomic.rmw.and, TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd
+i32.atomic.rmw.cmpxchg, TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg
+i32.atomic.rmw.or, TokenType::AtomicRmw, Opcode::I32AtomicRmwOr
+i32.atomic.rmw.sub, TokenType::AtomicRmw, Opcode::I32AtomicRmwSub
+i32.atomic.rmw.xchg, TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg
+i32.atomic.rmw.xor, TokenType::AtomicRmw, Opcode::I32AtomicRmwXor
+i32.atomic.store16, TokenType::AtomicStore, Opcode::I32AtomicStore16
+i32.atomic.store8, TokenType::AtomicStore, Opcode::I32AtomicStore8
+i32.atomic.store, TokenType::AtomicStore, Opcode::I32AtomicStore
+i32.clz, TokenType::Unary, Opcode::I32Clz
+i32.const, TokenType::Const, Opcode::I32Const
+i32.ctz, TokenType::Unary, Opcode::I32Ctz
+i32.div_s, TokenType::Binary, Opcode::I32DivS
+i32.div_u, TokenType::Binary, Opcode::I32DivU
+i32.eq, TokenType::Compare, Opcode::I32Eq
+i32.eqz, TokenType::Convert, Opcode::I32Eqz
+i32.extend16_s, TokenType::Unary, Opcode::I32Extend16S
+i32.extend8_s, TokenType::Unary, Opcode::I32Extend8S
+i32.ge_s, TokenType::Compare, Opcode::I32GeS
+i32.ge_u, TokenType::Compare, Opcode::I32GeU
+i32.gt_s, TokenType::Compare, Opcode::I32GtS
+i32.gt_u, TokenType::Compare, Opcode::I32GtU
+i32.le_s, TokenType::Compare, Opcode::I32LeS
+i32.le_u, TokenType::Compare, Opcode::I32LeU
+i32.load16_s, TokenType::Load, Opcode::I32Load16S
+i32.load16_u, TokenType::Load, Opcode::I32Load16U
+i32.load8_s, TokenType::Load, Opcode::I32Load8S
+i32.load8_u, TokenType::Load, Opcode::I32Load8U
+i32.load, TokenType::Load, Opcode::I32Load
+i32.lt_s, TokenType::Compare, Opcode::I32LtS
+i32.lt_u, TokenType::Compare, Opcode::I32LtU
+i32.mul, TokenType::Binary, Opcode::I32Mul
+i32.ne, TokenType::Compare, Opcode::I32Ne
+i32.or, TokenType::Binary, Opcode::I32Or
+i32.popcnt, TokenType::Unary, Opcode::I32Popcnt
+i32.reinterpret_f32, TokenType::Convert, Opcode::I32ReinterpretF32
+i32.rem_s, TokenType::Binary, Opcode::I32RemS
+i32.rem_u, TokenType::Binary, Opcode::I32RemU
+i32.rotl, TokenType::Binary, Opcode::I32Rotl
+i32.rotr, TokenType::Binary, Opcode::I32Rotr
+i32.shl, TokenType::Binary, Opcode::I32Shl
+i32.shr_s, TokenType::Binary, Opcode::I32ShrS
+i32.shr_u, TokenType::Binary, Opcode::I32ShrU
+i32.store16, TokenType::Store, Opcode::I32Store16
+i32.store8, TokenType::Store, Opcode::I32Store8
+i32.store, TokenType::Store, Opcode::I32Store
+i32.sub, TokenType::Binary, Opcode::I32Sub
+i32.trunc_f32_s, TokenType::Convert, Opcode::I32TruncF32S
+i32.trunc_f32_u, TokenType::Convert, Opcode::I32TruncF32U
+i32.trunc_f64_s, TokenType::Convert, Opcode::I32TruncF64S
+i32.trunc_f64_u, TokenType::Convert, Opcode::I32TruncF64U
+i32.trunc_sat_f32_s, TokenType::Convert, Opcode::I32TruncSatF32S
+i32.trunc_sat_f32_u, TokenType::Convert, Opcode::I32TruncSatF32U
+i32.trunc_sat_f64_s, TokenType::Convert, Opcode::I32TruncSatF64S
+i32.trunc_sat_f64_u, TokenType::Convert, Opcode::I32TruncSatF64U
+i32, Type::I32
+i32.wrap_i64, TokenType::Convert, Opcode::I32WrapI64
+i32x4.abs, TokenType::Unary, Opcode::I32X4Abs
+i32x4.add, TokenType::Binary, Opcode::I32X4Add
+i32x4.all_true, TokenType::Unary, Opcode::I32X4AllTrue
+i32x4.any_true, TokenType::Unary, Opcode::I32X4AnyTrue
+i32x4.bitmask, TokenType::Unary, Opcode::I32X4Bitmask
+i32x4.eq, TokenType::Compare, Opcode::I32X4Eq
+i32x4.extract_lane, TokenType::SimdLaneOp, Opcode::I32X4ExtractLane
+i32x4.ge_s, TokenType::Compare, Opcode::I32X4GeS
+i32x4.ge_u, TokenType::Compare, Opcode::I32X4GeU
+i32x4.gt_s, TokenType::Compare, Opcode::I32X4GtS
+i32x4.gt_u, TokenType::Compare, Opcode::I32X4GtU
+i32x4.le_s, TokenType::Compare, Opcode::I32X4LeS
+i32x4.le_u, TokenType::Compare, Opcode::I32X4LeU
+v128.load16x4_s, TokenType::Load, Opcode::V128Load16X4S
+v128.load16x4_u, TokenType::Load, Opcode::V128Load16X4U
+i32x4.lt_s, TokenType::Compare, Opcode::I32X4LtS
+i32x4.lt_u, TokenType::Compare, Opcode::I32X4LtU
+i32x4.max_s, TokenType::Binary, Opcode::I32X4MaxS
+i32x4.max_u, TokenType::Binary, Opcode::I32X4MaxU
+i32x4.min_s, TokenType::Binary, Opcode::I32X4MinS
+i32x4.min_u, TokenType::Binary, Opcode::I32X4MinU
+i32x4.mul, TokenType::Binary, Opcode::I32X4Mul
+i32x4.neg, TokenType::Unary, Opcode::I32X4Neg
+i32x4.ne, TokenType::Compare, Opcode::I32X4Ne
+i32x4.replace_lane, TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane
+i32x4.shl, TokenType::Binary, Opcode::I32X4Shl
+i32x4.shr_s, TokenType::Binary, Opcode::I32X4ShrS
+i32x4.shr_u, TokenType::Binary, Opcode::I32X4ShrU
+i32x4.splat, TokenType::Unary, Opcode::I32X4Splat
+i32x4.sub, TokenType::Binary, Opcode::I32X4Sub
+i32x4, TokenType::I32X4
+i32x4.trunc_sat_f32x4_s, TokenType::Unary, Opcode::I32X4TruncSatF32X4S
+i32x4.trunc_sat_f32x4_u, TokenType::Unary, Opcode::I32X4TruncSatF32X4U
+i32x4.widen_high_i16x8_s, TokenType::Unary, Opcode::I32X4WidenHighI16X8S
+i32x4.widen_high_i16x8_u, TokenType::Unary, Opcode::I32X4WidenHighI16X8U
+i32x4.widen_low_i16x8_s, TokenType::Unary, Opcode::I32X4WidenLowI16X8S
+i32x4.widen_low_i16x8_u, TokenType::Unary, Opcode::I32X4WidenLowI16X8U
+i32.xor, TokenType::Binary, Opcode::I32Xor
+i64.add, TokenType::Binary, Opcode::I64Add
+i64.and, TokenType::Binary, Opcode::I64And
+i64.atomic.load16_u, TokenType::AtomicLoad, Opcode::I64AtomicLoad16U
+i64.atomic.load32_u, TokenType::AtomicLoad, Opcode::I64AtomicLoad32U
+i64.atomic.load8_u, TokenType::AtomicLoad, Opcode::I64AtomicLoad8U
+i64.atomic.load, TokenType::AtomicLoad, Opcode::I64AtomicLoad
+i64.atomic.rmw16.add_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU
+i64.atomic.rmw16.and_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU
+i64.atomic.rmw16.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU
+i64.atomic.rmw16.or_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU
+i64.atomic.rmw16.sub_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU
+i64.atomic.rmw16.xchg_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU
+i64.atomic.rmw16.xor_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU
+i64.atomic.rmw32.add_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU
+i64.atomic.rmw32.and_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU
+i64.atomic.rmw32.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU
+i64.atomic.rmw32.or_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU
+i64.atomic.rmw32.sub_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU
+i64.atomic.rmw32.xchg_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU
+i64.atomic.rmw32.xor_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU
+i64.atomic.rmw8.add_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU
+i64.atomic.rmw8.and_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU
+i64.atomic.rmw8.cmpxchg_u, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU
+i64.atomic.rmw8.or_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU
+i64.atomic.rmw8.sub_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU
+i64.atomic.rmw8.xchg_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU
+i64.atomic.rmw8.xor_u, TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU
+i64.atomic.rmw.add, TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd
+i64.atomic.rmw.and, TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd
+i64.atomic.rmw.cmpxchg, TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg
+i64.atomic.rmw.or, TokenType::AtomicRmw, Opcode::I64AtomicRmwOr
+i64.atomic.rmw.sub, TokenType::AtomicRmw, Opcode::I64AtomicRmwSub
+i64.atomic.rmw.xchg, TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg
+i64.atomic.rmw.xor, TokenType::AtomicRmw, Opcode::I64AtomicRmwXor
+i64.atomic.store16, TokenType::AtomicStore, Opcode::I64AtomicStore16
+i64.atomic.store32, TokenType::AtomicStore, Opcode::I64AtomicStore32
+i64.atomic.store8, TokenType::AtomicStore, Opcode::I64AtomicStore8
+i64.atomic.store, TokenType::AtomicStore, Opcode::I64AtomicStore
+i64.clz, TokenType::Unary, Opcode::I64Clz
+i64.const, TokenType::Const, Opcode::I64Const
+i64.ctz, TokenType::Unary, Opcode::I64Ctz
+i64.div_s, TokenType::Binary, Opcode::I64DivS
+i64.div_u, TokenType::Binary, Opcode::I64DivU
+i64.eq, TokenType::Compare, Opcode::I64Eq
+i64.eqz, TokenType::Convert, Opcode::I64Eqz
+i64.extend16_s, TokenType::Unary, Opcode::I64Extend16S
+i64.extend32_s, TokenType::Unary, Opcode::I64Extend32S
+i64.extend8_s, TokenType::Unary, Opcode::I64Extend8S
+i64.extend_i32_s, TokenType::Convert, Opcode::I64ExtendI32S
+i64.extend_i32_u, TokenType::Convert, Opcode::I64ExtendI32U
+i64.ge_s, TokenType::Compare, Opcode::I64GeS
+i64.ge_u, TokenType::Compare, Opcode::I64GeU
+i64.gt_s, TokenType::Compare, Opcode::I64GtS
+i64.gt_u, TokenType::Compare, Opcode::I64GtU
+i64.le_s, TokenType::Compare, Opcode::I64LeS
+i64.le_u, TokenType::Compare, Opcode::I64LeU
+i64.load16_s, TokenType::Load, Opcode::I64Load16S
+i64.load16_u, TokenType::Load, Opcode::I64Load16U
+i64.load32_s, TokenType::Load, Opcode::I64Load32S
+i64.load32_u, TokenType::Load, Opcode::I64Load32U
+i64.load8_s, TokenType::Load, Opcode::I64Load8S
+i64.load8_u, TokenType::Load, Opcode::I64Load8U
+i64.load, TokenType::Load, Opcode::I64Load
+i64.lt_s, TokenType::Compare, Opcode::I64LtS
+i64.lt_u, TokenType::Compare, Opcode::I64LtU
+i64.mul, TokenType::Binary, Opcode::I64Mul
+i64.ne, TokenType::Compare, Opcode::I64Ne
+i64.or, TokenType::Binary, Opcode::I64Or
+i64.popcnt, TokenType::Unary, Opcode::I64Popcnt
+i64.reinterpret_f64, TokenType::Convert, Opcode::I64ReinterpretF64
+i64.rem_s, TokenType::Binary, Opcode::I64RemS
+i64.rem_u, TokenType::Binary, Opcode::I64RemU
+i64.rotl, TokenType::Binary, Opcode::I64Rotl
+i64.rotr, TokenType::Binary, Opcode::I64Rotr
+i64.shl, TokenType::Binary, Opcode::I64Shl
+i64.shr_s, TokenType::Binary, Opcode::I64ShrS
+i64.shr_u, TokenType::Binary, Opcode::I64ShrU
+i64.store16, TokenType::Store, Opcode::I64Store16
+i64.store32, TokenType::Store, Opcode::I64Store32
+i64.store8, TokenType::Store, Opcode::I64Store8
+i64.store, TokenType::Store, Opcode::I64Store
+i64.sub, TokenType::Binary, Opcode::I64Sub
+i64.trunc_f32_s, TokenType::Convert, Opcode::I64TruncF32S
+i64.trunc_f32_u, TokenType::Convert, Opcode::I64TruncF32U
+i64.trunc_f64_s, TokenType::Convert, Opcode::I64TruncF64S
+i64.trunc_f64_u, TokenType::Convert, Opcode::I64TruncF64U
+i64.trunc_sat_f32_s, TokenType::Convert, Opcode::I64TruncSatF32S
+i64.trunc_sat_f32_u, TokenType::Convert, Opcode::I64TruncSatF32U
+i64.trunc_sat_f64_s, TokenType::Convert, Opcode::I64TruncSatF64S
+i64.trunc_sat_f64_u, TokenType::Convert, Opcode::I64TruncSatF64U
+i64, Type::I64
+i64x2.add, TokenType::Binary, Opcode::I64X2Add
+i64x2.extract_lane, TokenType::SimdLaneOp, Opcode::I64X2ExtractLane
+v128.load32x2_s, TokenType::Load, Opcode::V128Load32X2S
+v128.load32x2_u, TokenType::Load, Opcode::V128Load32X2U
+i64x2.mul, TokenType::Binary, Opcode::I64X2Mul
+i64x2.neg, TokenType::Unary, Opcode::I64X2Neg
+i64x2.replace_lane, TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane
+i64x2.shl, TokenType::Binary, Opcode::I64X2Shl
+i64x2.shr_s, TokenType::Binary, Opcode::I64X2ShrS
+i64x2.shr_u, TokenType::Binary, Opcode::I64X2ShrU
+i64x2.splat, TokenType::Unary, Opcode::I64X2Splat
+i64x2.sub, TokenType::Binary, Opcode::I64X2Sub
+i64x2, TokenType::I64X2
+i64.xor, TokenType::Binary, Opcode::I64Xor
+i8x16.abs, TokenType::Unary, Opcode::I8X16Abs
+i8x16.add_sat_s, TokenType::Binary, Opcode::I8X16AddSatS
+i8x16.add_sat_u, TokenType::Binary, Opcode::I8X16AddSatU
+i8x16.add, TokenType::Binary, Opcode::I8X16Add
+i8x16.all_true, TokenType::Unary, Opcode::I8X16AllTrue
+i8x16.any_true, TokenType::Unary, Opcode::I8X16AnyTrue
+i8x16.avgr_u, TokenType::Binary, Opcode::I8X16AvgrU
+i8x16.bitmask, TokenType::Unary, Opcode::I8X16Bitmask
+i8x16.eq, TokenType::Compare, Opcode::I8X16Eq
+i8x16.extract_lane_s, TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS
+i8x16.extract_lane_u, TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU
+i8x16.ge_s, TokenType::Compare, Opcode::I8X16GeS
+i8x16.ge_u, TokenType::Compare, Opcode::I8X16GeU
+i8x16.gt_s, TokenType::Compare, Opcode::I8X16GtS
+i8x16.gt_u, TokenType::Compare, Opcode::I8X16GtU
+i8x16.le_s, TokenType::Compare, Opcode::I8X16LeS
+i8x16.le_u, TokenType::Compare, Opcode::I8X16LeU
+i8x16.lt_s, TokenType::Compare, Opcode::I8X16LtS
+i8x16.lt_u, TokenType::Compare, Opcode::I8X16LtU
+i8x16.max_s, TokenType::Binary, Opcode::I8X16MaxS
+i8x16.max_u, TokenType::Binary, Opcode::I8X16MaxU
+i8x16.min_s, TokenType::Binary, Opcode::I8X16MinS
+i8x16.min_u, TokenType::Binary, Opcode::I8X16MinU
+i8x16.narrow_i16x8_s, TokenType::Binary, Opcode::I8X16NarrowI16X8S
+i8x16.narrow_i16x8_u, TokenType::Binary, Opcode::I8X16NarrowI16X8U
+i8x16.neg, TokenType::Unary, Opcode::I8X16Neg
+i8x16.ne, TokenType::Compare, Opcode::I8X16Ne
+i8x16.replace_lane, TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane
+i8x16.shl, TokenType::Binary, Opcode::I8X16Shl
+i8x16.shr_s, TokenType::Binary, Opcode::I8X16ShrS
+i8x16.shr_u, TokenType::Binary, Opcode::I8X16ShrU
+i8x16.splat, TokenType::Unary, Opcode::I8X16Splat
+i8x16.sub_sat_s, TokenType::Binary, Opcode::I8X16SubSatS
+i8x16.sub_sat_u, TokenType::Binary, Opcode::I8X16SubSatU
+i8x16.sub, TokenType::Binary, Opcode::I8X16Sub
+i8x16, TokenType::I8X16
+if, TokenType::If, Opcode::If
+import, TokenType::Import
+input, TokenType::Input
+invoke, TokenType::Invoke
+item, TokenType::Item
+local.get, TokenType::LocalGet, Opcode::LocalGet
+local.set, TokenType::LocalSet, Opcode::LocalSet
+local.tee, TokenType::LocalTee, Opcode::LocalTee
+local, TokenType::Local
+loop, TokenType::Loop, Opcode::Loop
+memory.atomic.notify, TokenType::AtomicNotify, Opcode::MemoryAtomicNotify
+memory.atomic.wait32, TokenType::AtomicWait, Opcode::MemoryAtomicWait32
+memory.atomic.wait64, TokenType::AtomicWait, Opcode::MemoryAtomicWait64
+memory.copy, TokenType::MemoryCopy, Opcode::MemoryCopy
+memory.fill, TokenType::MemoryFill, Opcode::MemoryFill
+memory.grow, TokenType::MemoryGrow, Opcode::MemoryGrow
+memory.init, TokenType::MemoryInit, Opcode::MemoryInit
+memory.size, TokenType::MemorySize, Opcode::MemorySize
+memory, TokenType::Memory
+module, TokenType::Module
+mut, TokenType::Mut
+nan:arithmetic, TokenType::NanArithmetic
+nan:canonical, TokenType::NanCanonical
+nop, TokenType::Nop, Opcode::Nop
+offset, TokenType::Offset
+output, TokenType::Output
+param, TokenType::Param
+quote, TokenType::Quote
+ref.extern, TokenType::RefExtern
+ref.func, TokenType::RefFunc, Opcode::RefFunc
+ref.is_null, TokenType::RefIsNull, Opcode::RefIsNull
+ref.null, TokenType::RefNull, Opcode::RefNull
+register, TokenType::Register
+result, TokenType::Result
+rethrow, TokenType::Rethrow, Opcode::Rethrow
+return_call_indirect, TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect
+return_call, TokenType::ReturnCall, Opcode::ReturnCall
+return, TokenType::Return, Opcode::Return
+select, TokenType::Select, Opcode::Select
+shared, TokenType::Shared
+start, TokenType::Start
+struct, Type::Struct, TokenType::Struct
+table.copy, TokenType::TableCopy, Opcode::TableCopy
+table.fill, TokenType::TableFill, Opcode::TableFill
+table.get, TokenType::TableGet, Opcode::TableGet
+table.grow, TokenType::TableGrow, Opcode::TableGrow
+table.init, TokenType::TableInit, Opcode::TableInit
+table.set, TokenType::TableSet, Opcode::TableSet
+table.size, TokenType::TableSize, Opcode::TableSize
+table, TokenType::Table
+then, TokenType::Then
+throw, TokenType::Throw, Opcode::Throw
+try, TokenType::Try, Opcode::Try
+type, TokenType::Type
+unreachable, TokenType::Unreachable, Opcode::Unreachable
+v128.andnot, TokenType::Binary, Opcode::V128Andnot
+v128.and, TokenType::Binary, Opcode::V128And
+v128.bitselect, TokenType::Ternary, Opcode::V128BitSelect
+v128.const, TokenType::Const, Opcode::V128Const
+v128.load, TokenType::Load, Opcode::V128Load
+v128.not, TokenType::Unary, Opcode::V128Not
+v128.or, TokenType::Binary, Opcode::V128Or
+v128.store, TokenType::Store, Opcode::V128Store
+v128, Type::V128
+v128.xor, TokenType::Binary, Opcode::V128Xor
+v128.load16_splat, TokenType::Load, Opcode::V128Load16Splat
+v128.load32_splat, TokenType::Load, Opcode::V128Load32Splat
+v128.load64_splat, TokenType::Load, Opcode::V128Load64Splat
+v128.load8_splat, TokenType::Load, Opcode::V128Load8Splat
+i8x16.shuffle, TokenType::SimdShuffleOp, Opcode::I8X16Shuffle
+i8x16.swizzle, TokenType::Binary, Opcode::I8X16Swizzle
+# Deprecated names.
+atomic.notify, TokenType::AtomicNotify, Opcode::MemoryAtomicNotify
+i32.atomic.wait, TokenType::AtomicWait, Opcode::MemoryAtomicWait32
+i64.atomic.wait, TokenType::AtomicWait, Opcode::MemoryAtomicWait64
+anyfunc, Type::FuncRef
+f32.convert_s/i32, TokenType::Convert, Opcode::F32ConvertI32S
+f32.convert_s/i64, TokenType::Convert, Opcode::F32ConvertI64S
+f32.convert_u/i32, TokenType::Convert, Opcode::F32ConvertI32U
+f32.convert_u/i64, TokenType::Convert, Opcode::F32ConvertI64U
+f32.demote/f64, TokenType::Convert, Opcode::F32DemoteF64
+f32.reinterpret/i32, TokenType::Convert, Opcode::F32ReinterpretI32
+f64.convert_s/i32, TokenType::Convert, Opcode::F64ConvertI32S
+f64.convert_s/i64, TokenType::Convert, Opcode::F64ConvertI64S
+f64.convert_u/i32, TokenType::Convert, Opcode::F64ConvertI32U
+f64.convert_u/i64, TokenType::Convert, Opcode::F64ConvertI64U
+f64.promote/f32, TokenType::Convert, Opcode::F64PromoteF32
+f64.reinterpret/i64, TokenType::Convert, Opcode::F64ReinterpretI64
+get_global, TokenType::GlobalGet, Opcode::GlobalGet
+get_local, TokenType::LocalGet, Opcode::LocalGet
+i32.reinterpret/f32, TokenType::Convert, Opcode::I32ReinterpretF32
+i32.trunc_s/f32, TokenType::Convert, Opcode::I32TruncF32S
+i32.trunc_s/f64, TokenType::Convert, Opcode::I32TruncF64S
+i32.trunc_s:sat/f32, TokenType::Convert, Opcode::I32TruncSatF32S
+i32.trunc_s:sat/f64, TokenType::Convert, Opcode::I32TruncSatF64S
+i32.trunc_u/f32, TokenType::Convert, Opcode::I32TruncF32U
+i32.trunc_u/f64, TokenType::Convert, Opcode::I32TruncF64U
+i32.trunc_u:sat/f32, TokenType::Convert, Opcode::I32TruncSatF32U
+i32.trunc_u:sat/f64, TokenType::Convert, Opcode::I32TruncSatF64U
+i32.wrap/i64, TokenType::Convert, Opcode::I32WrapI64
+i64.extend_s/i32, TokenType::Convert, Opcode::I64ExtendI32S
+i64.extend_u/i32, TokenType::Convert, Opcode::I64ExtendI32U
+i64.reinterpret/f64, TokenType::Convert, Opcode::I64ReinterpretF64
+i64.trunc_s/f32, TokenType::Convert, Opcode::I64TruncF32S
+i64.trunc_s/f64, TokenType::Convert, Opcode::I64TruncF64S
+i64.trunc_s:sat/f32, TokenType::Convert, Opcode::I64TruncSatF32S
+i64.trunc_s:sat/f64, TokenType::Convert, Opcode::I64TruncSatF64S
+i64.trunc_u/f32, TokenType::Convert, Opcode::I64TruncF32U
+i64.trunc_u/f64, TokenType::Convert, Opcode::I64TruncF64U
+i64.trunc_u:sat/f32, TokenType::Convert, Opcode::I64TruncSatF32U
+i64.trunc_u:sat/f64, TokenType::Convert, Opcode::I64TruncSatF64U
+set_global, TokenType::GlobalSet, Opcode::GlobalSet
+set_local, TokenType::LocalSet, Opcode::LocalSet
+tee_local, TokenType::LocalTee, Opcode::LocalTee
+unwind, TokenType::Unwind, Opcode::Unwind
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.cc
new file mode 100644 (file)
index 0000000..833cb90
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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/lexer-source-line-finder.h"
+
+#include <algorithm>
+
+#include "src/lexer-source.h"
+
+namespace wabt {
+
+LexerSourceLineFinder::LexerSourceLineFinder(
+    std::unique_ptr<LexerSource> source)
+    : source_(std::move(source)),
+      next_line_start_(0),
+      last_cr_(false),
+      eof_(false) {
+  source_->Seek(0);
+  // Line 0 should not be used; but it makes indexing simpler.
+  line_ranges_.emplace_back(0, 0);
+}
+
+Result LexerSourceLineFinder::GetSourceLine(const Location& loc,
+                                            Offset max_line_length,
+                                            SourceLine* out_source_line) {
+  ColumnRange column_range(loc.first_column, loc.last_column);
+  OffsetRange original;
+  CHECK_RESULT(GetLineOffsets(loc.line, &original));
+
+  OffsetRange clamped =
+      ClampSourceLineOffsets(original, column_range, max_line_length);
+  bool has_start_ellipsis = original.start != clamped.start;
+  bool has_end_ellipsis = original.end != clamped.end;
+
+  out_source_line->column_offset = clamped.start - original.start;
+
+  if (has_start_ellipsis) {
+    out_source_line->line += "...";
+    clamped.start += 3;
+  }
+  if (has_end_ellipsis) {
+    clamped.end -= 3;
+  }
+
+  std::vector<char> read_line;
+  CHECK_RESULT(source_->ReadRange(clamped, &read_line));
+  out_source_line->line.append(read_line.begin(), read_line.end());
+
+  if (has_end_ellipsis) {
+    out_source_line->line += "...";
+  }
+
+  return Result::Ok;
+}
+
+bool LexerSourceLineFinder::IsLineCached(int line) const {
+  return static_cast<size_t>(line) < line_ranges_.size();
+}
+
+OffsetRange LexerSourceLineFinder::GetCachedLine(int line) const {
+  assert(IsLineCached(line));
+  return line_ranges_[line];
+}
+
+Result LexerSourceLineFinder::GetLineOffsets(int find_line,
+                                             OffsetRange* out_range) {
+  if (IsLineCached(find_line)) {
+    *out_range = GetCachedLine(find_line);
+    return Result::Ok;
+  }
+
+  const size_t kBufferSize = 1 << 16;
+  std::vector<char> buffer(kBufferSize);
+
+  assert(!line_ranges_.empty());
+  Offset buffer_file_offset = 0;
+  while (!IsLineCached(find_line) && !eof_) {
+    CHECK_RESULT(source_->Tell(&buffer_file_offset));
+    size_t read_size = source_->Fill(buffer.data(), buffer.size());
+    if (read_size < buffer.size()) {
+      eof_ = true;
+    }
+
+    for (auto iter = buffer.begin(), end = iter + read_size; iter < end;
+         ++iter) {
+      if (*iter == '\n') {
+        // Don't include \n or \r in the line range.
+        Offset line_offset =
+            buffer_file_offset + (iter - buffer.begin()) - last_cr_;
+        line_ranges_.emplace_back(next_line_start_, line_offset);
+        next_line_start_ = line_offset + last_cr_ + 1;
+      }
+      last_cr_ = *iter == '\r';
+    }
+
+    if (eof_) {
+      // Add the final line as an empty range.
+      Offset end = buffer_file_offset + read_size;
+      line_ranges_.emplace_back(next_line_start_, end);
+    }
+  }
+
+  if (IsLineCached(find_line)) {
+    *out_range = GetCachedLine(find_line);
+    return Result::Ok;
+  } else {
+    assert(eof_);
+    return Result::Error;
+  }
+}
+
+// static
+OffsetRange LexerSourceLineFinder::ClampSourceLineOffsets(
+    OffsetRange offset_range,
+    ColumnRange column_range,
+    Offset max_line_length) {
+  Offset line_length = offset_range.size();
+  if (line_length > max_line_length) {
+    size_t column_count = column_range.size();
+    size_t center_on;
+    if (column_count > max_line_length) {
+      // The column range doesn't fit, just center on first_column.
+      center_on = column_range.start - 1;
+    } else {
+      // the entire range fits, display it all in the center.
+      center_on = (column_range.start + column_range.end) / 2 - 1;
+    }
+    if (center_on > max_line_length / 2) {
+      offset_range.start += center_on - max_line_length / 2;
+    }
+    offset_range.start =
+        std::min(offset_range.start, offset_range.end - max_line_length);
+    offset_range.end = offset_range.start + max_line_length;
+  }
+
+  return offset_range;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source-line-finder.h
new file mode 100644 (file)
index 0000000..baf87b4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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_LEXER_SOURCE_LINE_FINDER_H_
+#define WABT_LEXER_SOURCE_LINE_FINDER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "src/common.h"
+#include "src/lexer-source.h"
+#include "src/range.h"
+
+namespace wabt {
+
+class LexerSourceLineFinder {
+ public:
+  struct SourceLine {
+    std::string line;
+    int column_offset;
+  };
+
+  explicit LexerSourceLineFinder(std::unique_ptr<LexerSource>);
+
+  Result GetSourceLine(const Location& loc,
+                       Offset max_line_length,
+                       SourceLine* out_source_line);
+  Result GetLineOffsets(int line, OffsetRange* out_offsets);
+
+ private:
+  static OffsetRange ClampSourceLineOffsets(OffsetRange line_offset_range,
+                                            ColumnRange column_range,
+                                            Offset max_line_length);
+
+  bool IsLineCached(int line) const;
+  OffsetRange GetCachedLine(int line) const;
+
+  std::unique_ptr<LexerSource> source_;
+  std::vector<OffsetRange> line_ranges_;
+  Offset next_line_start_;
+  bool last_cr_;  // Last read character was a '\r' (carriage return).
+  bool eof_;
+};
+
+}  // namespace wabt
+
+#endif  // WABT_LEXER_SOURCE_LINE_FINDER_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.cc
new file mode 100644 (file)
index 0000000..896a52e
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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/lexer-source.h"
+
+#include <algorithm>
+
+namespace wabt {
+
+LexerSource::LexerSource(const void* data, Offset size)
+    : data_(data), size_(size), read_offset_(0) {}
+
+std::unique_ptr<LexerSource> LexerSource::Clone() {
+  LexerSource* result = new LexerSource(data_, size_);
+  result->read_offset_ = read_offset_;
+  return std::unique_ptr<LexerSource>(result);
+}
+
+Result LexerSource::Tell(Offset* out_offset) {
+  *out_offset = read_offset_;
+  return Result::Ok;
+}
+
+size_t LexerSource::Fill(void* dest, Offset size) {
+  Offset read_size = std::min(size, size_ - read_offset_);
+  if (read_size > 0) {
+    const void* src = static_cast<const char*>(data_) + read_offset_;
+    memcpy(dest, src, read_size);
+    read_offset_ += read_size;
+  }
+  return read_size;
+}
+
+Result LexerSource::Seek(Offset offset) {
+  if (offset < size_) {
+    read_offset_ = offset;
+    return Result::Ok;
+  }
+  return Result::Error;
+}
+
+Result LexerSource::ReadRange(OffsetRange range, std::vector<char>* out_data) {
+  OffsetRange clamped = range;
+  clamped.start = std::min(clamped.start, size_);
+  clamped.end = std::min(clamped.end, size_);
+  if (clamped.size()) {
+    out_data->resize(clamped.size());
+    const void* src = static_cast<const char*>(data_) + clamped.start;
+    memcpy(out_data->data(), src, clamped.size());
+  }
+  return Result::Ok;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/lexer-source.h
new file mode 100644 (file)
index 0000000..d49d5c6
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * 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_LEXER_SOURCE_H_
+#define WABT_LEXER_SOURCE_H_
+
+#include <cstddef>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "src/common.h"
+#include "src/range.h"
+
+namespace wabt {
+
+class LexerSource {
+ public:
+  LexerSource(const void* data, Offset size);
+
+  std::unique_ptr<LexerSource> Clone();
+  Result Tell(Offset* out_offset);
+  size_t Fill(void* dest, size_t size);
+  Result ReadRange(OffsetRange, std::vector<char>* out_data);
+  Result Seek(Offset offset);
+
+  WABT_DISALLOW_COPY_AND_ASSIGN(LexerSource);
+
+  const void* data() { return data_; }
+  Offset size() { return size_; }
+
+ private:
+  const void* data_;
+  Offset size_;
+  Offset read_offset_;
+};
+
+}  // namespace wabt
+
+#endif  // WABT_LEXER_SOURCE_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.cc
new file mode 100644 (file)
index 0000000..0061772
--- /dev/null
@@ -0,0 +1,830 @@
+/*
+ * 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/literal.h"
+
+#include <cassert>
+#include <cerrno>
+#include <cinttypes>
+#include <cmath>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <type_traits>
+
+namespace wabt {
+
+namespace {
+
+template <typename T>
+struct FloatTraitsBase {};
+
+// The "PlusOne" values are used because normal IEEE floats have an implicit
+// leading one, so they have an additional bit of precision.
+
+template <>
+struct FloatTraitsBase<float> {
+  typedef uint32_t Uint;
+  static constexpr int kBits = sizeof(Uint) * 8;
+  static constexpr int kSigBits = 23;
+  static constexpr float kHugeVal = HUGE_VALF;
+  static constexpr int kMaxHexBufferSize = WABT_MAX_FLOAT_HEX;
+
+  static float Strto(const char* s, char** endptr) { return strtof(s, endptr); }
+};
+
+template <>
+struct FloatTraitsBase<double> {
+  typedef uint64_t Uint;
+  static constexpr int kBits = sizeof(Uint) * 8;
+  static constexpr int kSigBits = 52;
+  static constexpr float kHugeVal = HUGE_VAL;
+  static constexpr int kMaxHexBufferSize = WABT_MAX_DOUBLE_HEX;
+
+  static double Strto(const char* s, char** endptr) {
+    return strtod(s, endptr);
+  }
+};
+
+template <typename T>
+struct FloatTraits : FloatTraitsBase<T> {
+  typedef typename FloatTraitsBase<T>::Uint Uint;
+  using FloatTraitsBase<T>::kBits;
+  using FloatTraitsBase<T>::kSigBits;
+
+  static constexpr int kExpBits = kBits - kSigBits - 1;
+  static constexpr int kSignShift = kBits - 1;
+  static constexpr Uint kSigMask = (Uint(1) << kSigBits) - 1;
+  static constexpr int kSigPlusOneBits = kSigBits + 1;
+  static constexpr Uint kSigPlusOneMask = (Uint(1) << kSigPlusOneBits) - 1;
+  static constexpr int kExpMask = (1 << kExpBits) - 1;
+  static constexpr int kMaxExp = 1 << (kExpBits - 1);
+  static constexpr int kMinExp = -kMaxExp + 1;
+  static constexpr int kExpBias = -kMinExp;
+  static constexpr Uint kQuietNanTag = Uint(1) << (kSigBits - 1);
+};
+
+template <typename T>
+class FloatParser {
+ public:
+  typedef FloatTraits<T> Traits;
+  typedef typename Traits::Uint Uint;
+  typedef T Float;
+
+  static Result Parse(LiteralType,
+                      const char* s,
+                      const char* end,
+                      Uint* out_bits);
+
+ private:
+  static bool StringStartsWith(const char* start,
+                               const char* end,
+                               const char* prefix);
+  static Uint Make(bool sign, int exp, Uint sig);
+  static Uint ShiftAndRoundToNearest(Uint significand,
+                                     int shift,
+                                     bool seen_trailing_non_zero);
+
+  static Result ParseFloat(const char* s, const char* end, Uint* out_bits);
+  static Result ParseNan(const char* s, const char* end, Uint* out_bits);
+  static Result ParseHex(const char* s, const char* end, Uint* out_bits);
+  static void ParseInfinity(const char* s, const char* end, Uint* out_bits);
+};
+
+template <typename T>
+class FloatWriter {
+ public:
+  typedef FloatTraits<T> Traits;
+  typedef typename Traits::Uint Uint;
+
+  static void WriteHex(char* out, size_t size, Uint bits);
+};
+
+// Return 1 if the non-NULL-terminated string starting with |start| and ending
+// with |end| starts with the NULL-terminated string |prefix|.
+template <typename T>
+// static
+bool FloatParser<T>::StringStartsWith(const char* start,
+                                      const char* end,
+                                      const char* prefix) {
+  while (start < end && *prefix) {
+    if (*start != *prefix) {
+      return false;
+    }
+    start++;
+    prefix++;
+  }
+  return *prefix == 0;
+}
+
+// static
+template <typename T>
+Result FloatParser<T>::ParseFloat(const char* s,
+                                  const char* end,
+                                  Uint* out_bits) {
+  // Here is the normal behavior for strtof/strtod:
+  //
+  // input     | errno  |   output   |
+  // ---------------------------------
+  // overflow  | ERANGE | +-HUGE_VAL |
+  // underflow | ERANGE |        0.0 |
+  // otherwise |      0 |      value |
+  //
+  // So normally we need to clear errno before calling strto{f,d}, and check
+  // afterward whether it was set to ERANGE.
+  //
+  // glibc seems to have a bug where
+  // strtof("340282356779733661637539395458142568448") will return HUGE_VAL,
+  // but will not set errno to ERANGE. Since this function is only called when
+  // we know that we have parsed a "normal" number (i.e. not "inf"), we know
+  // that if we ever get HUGE_VAL, it must be overflow.
+  //
+  // The WebAssembly spec also ignores underflow, so we don't need to check for
+  // ERANGE at all.
+
+  // WebAssembly floats can contain underscores, but strto* can't parse those,
+  // so remove them first.
+  assert(s <= end);
+  const size_t kBufferSize = end - s + 1;  // +1 for \0.
+  char* buffer = static_cast<char*>(alloca(kBufferSize));
+  auto buffer_end =
+      std::copy_if(s, end, buffer, [](char c) -> bool { return c != '_'; });
+  assert(buffer_end < buffer + kBufferSize);
+  *buffer_end = 0;
+
+  char* endptr;
+  Float value = Traits::Strto(buffer, &endptr);
+  if (endptr != buffer_end ||
+      (value == Traits::kHugeVal || value == -Traits::kHugeVal)) {
+    return Result::Error;
+  }
+
+  memcpy(out_bits, &value, sizeof(value));
+  return Result::Ok;
+}
+
+// static
+template <typename T>
+typename FloatParser<T>::Uint FloatParser<T>::Make(bool sign,
+                                                   int exp,
+                                                   Uint sig) {
+  assert(exp >= Traits::kMinExp && exp <= Traits::kMaxExp);
+  assert(sig <= Traits::kSigMask);
+  return (Uint(sign) << Traits::kSignShift) |
+         (Uint(exp + Traits::kExpBias) << Traits::kSigBits) | sig;
+}
+
+// static
+template <typename T>
+typename FloatParser<T>::Uint FloatParser<T>::ShiftAndRoundToNearest(
+    Uint significand,
+    int shift,
+    bool seen_trailing_non_zero) {
+  assert(shift > 0);
+  // Round ties to even.
+  if ((significand & (Uint(1) << shift)) || seen_trailing_non_zero) {
+    significand += Uint(1) << (shift - 1);
+  }
+  significand >>= shift;
+  return significand;
+}
+
+// static
+template <typename T>
+Result FloatParser<T>::ParseNan(const char* s,
+                                const char* end,
+                                Uint* out_bits) {
+  bool is_neg = false;
+  if (*s == '-') {
+    is_neg = true;
+    s++;
+  } else if (*s == '+') {
+    s++;
+  }
+  assert(StringStartsWith(s, end, "nan"));
+  s += 3;
+
+  Uint tag;
+  if (s != end) {
+    tag = 0;
+    assert(StringStartsWith(s, end, ":0x"));
+    s += 3;
+
+    for (; s < end; ++s) {
+      if (*s == '_') {
+        continue;
+      }
+      uint32_t digit;
+      CHECK_RESULT(ParseHexdigit(*s, &digit));
+      tag = tag * 16 + digit;
+      // Check for overflow.
+      if (tag > Traits::kSigMask) {
+        return Result::Error;
+      }
+    }
+
+    // NaN cannot have a zero tag, that is reserved for infinity.
+    if (tag == 0) {
+      return Result::Error;
+    }
+  } else {
+    tag = Traits::kQuietNanTag;
+  }
+
+  *out_bits = Make(is_neg, Traits::kMaxExp, tag);
+  return Result::Ok;
+}
+
+// static
+template <typename T>
+Result FloatParser<T>::ParseHex(const char* s,
+                                const char* end,
+                                Uint* out_bits) {
+  bool is_neg = false;
+  if (*s == '-') {
+    is_neg = true;
+    s++;
+  } else if (*s == '+') {
+    s++;
+  }
+  assert(StringStartsWith(s, end, "0x"));
+  s += 2;
+
+  // Loop over the significand; everything up to the 'p'.
+  // This code is a bit nasty because we want to support extra zeroes anywhere
+  // without having to use many significand bits.
+  // e.g.
+  // 0x00000001.0p0 => significand = 1, significand_exponent = 0
+  // 0x10000000.0p0 => significand = 1, significand_exponent = 28
+  // 0x0.000001p0 => significand = 1, significand_exponent = -24
+  bool seen_dot = false;
+  bool seen_trailing_non_zero = false;
+  Uint significand = 0;
+  int significand_exponent = 0;  // Exponent adjustment due to dot placement.
+  for (; s < end; ++s) {
+    uint32_t digit;
+    if (*s == '_') {
+      continue;
+    } else if (*s == '.') {
+      seen_dot = true;
+    } else if (Succeeded(ParseHexdigit(*s, &digit))) {
+      if (Traits::kBits - Clz(significand) <= Traits::kSigPlusOneBits) {
+        significand = (significand << 4) + digit;
+        if (seen_dot) {
+          significand_exponent -= 4;
+        }
+      } else {
+        if (!seen_trailing_non_zero && digit != 0) {
+          seen_trailing_non_zero = true;
+        }
+        if (!seen_dot) {
+          significand_exponent += 4;
+        }
+      }
+    } else {
+      break;
+    }
+  }
+
+  if (significand == 0) {
+    // 0 or -0.
+    *out_bits = Make(is_neg, Traits::kMinExp, 0);
+    return Result::Ok;
+  }
+
+  int exponent = 0;
+  bool exponent_is_neg = false;
+  if (s < end) {
+    assert(*s == 'p' || *s == 'P');
+    s++;
+    // Exponent is always positive, but significand_exponent is signed.
+    // significand_exponent_add is negated if exponent will be negative, so it
+    // can be easily summed to see if the exponent is too large (see below).
+    int significand_exponent_add = 0;
+    if (*s == '-') {
+      exponent_is_neg = true;
+      significand_exponent_add = -significand_exponent;
+      s++;
+    } else if (*s == '+') {
+      s++;
+      significand_exponent_add = significand_exponent;
+    }
+
+    for (; s < end; ++s) {
+      if (*s == '_') {
+        continue;
+      }
+
+      uint32_t digit = (*s - '0');
+      assert(digit <= 9);
+      exponent = exponent * 10 + digit;
+      if (exponent + significand_exponent_add >= Traits::kMaxExp) {
+        break;
+      }
+    }
+  }
+
+  if (exponent_is_neg) {
+    exponent = -exponent;
+  }
+
+  int significand_bits = Traits::kBits - Clz(significand);
+  // -1 for the implicit 1 bit of the significand.
+  exponent += significand_exponent + significand_bits - 1;
+
+  if (exponent <= Traits::kMinExp) {
+    // Maybe subnormal.
+    auto update_seen_trailing_non_zero = [&](int shift) {
+      assert(shift > 0);
+      auto mask = (Uint(1) << (shift - 1)) - 1;
+      seen_trailing_non_zero |= (significand & mask) != 0;
+    };
+
+    // Normalize significand.
+    if (significand_bits > Traits::kSigBits) {
+      int shift = significand_bits - Traits::kSigBits;
+      update_seen_trailing_non_zero(shift);
+      significand >>= shift;
+    } else if (significand_bits < Traits::kSigBits) {
+      significand <<= (Traits::kSigBits - significand_bits);
+    }
+
+    int shift = Traits::kMinExp - exponent;
+    if (shift <= Traits::kSigBits) {
+      if (shift) {
+        update_seen_trailing_non_zero(shift);
+        significand =
+            ShiftAndRoundToNearest(significand, shift, seen_trailing_non_zero) &
+            Traits::kSigMask;
+      }
+      exponent = Traits::kMinExp;
+
+      if (significand != 0) {
+        *out_bits = Make(is_neg, exponent, significand);
+        return Result::Ok;
+      }
+    }
+
+    // Not subnormal, too small; return 0 or -0.
+    *out_bits = Make(is_neg, Traits::kMinExp, 0);
+  } else {
+    // Maybe Normal value.
+    if (significand_bits > Traits::kSigPlusOneBits) {
+      significand = ShiftAndRoundToNearest(
+          significand, significand_bits - Traits::kSigPlusOneBits,
+          seen_trailing_non_zero);
+      if (significand > Traits::kSigPlusOneMask) {
+        exponent++;
+      }
+    } else if (significand_bits < Traits::kSigPlusOneBits) {
+      significand <<= (Traits::kSigPlusOneBits - significand_bits);
+    }
+
+    if (exponent >= Traits::kMaxExp) {
+      // Would be inf or -inf, but the spec doesn't allow rounding hex-floats to
+      // infinity.
+      return Result::Error;
+    }
+
+    *out_bits = Make(is_neg, exponent, significand & Traits::kSigMask);
+  }
+
+  return Result::Ok;
+}
+
+// static
+template <typename T>
+void FloatParser<T>::ParseInfinity(const char* s,
+                                   const char* end,
+                                   Uint* out_bits) {
+  bool is_neg = false;
+  if (*s == '-') {
+    is_neg = true;
+    s++;
+  } else if (*s == '+') {
+    s++;
+  }
+  assert(StringStartsWith(s, end, "inf"));
+  *out_bits = Make(is_neg, Traits::kMaxExp, 0);
+}
+
+// static
+template <typename T>
+Result FloatParser<T>::Parse(LiteralType literal_type,
+                             const char* s,
+                             const char* end,
+                             Uint* out_bits) {
+#if COMPILER_IS_MSVC
+  if (literal_type == LiteralType::Int && StringStartsWith(s, end, "0x")) {
+    // Some MSVC crt implementation of strtof doesn't support hex strings
+    literal_type = LiteralType::Hexfloat;
+  }
+#endif
+  switch (literal_type) {
+    case LiteralType::Int:
+    case LiteralType::Float:
+      return ParseFloat(s, end, out_bits);
+
+    case LiteralType::Hexfloat:
+      return ParseHex(s, end, out_bits);
+
+    case LiteralType::Infinity:
+      ParseInfinity(s, end, out_bits);
+      return Result::Ok;
+
+    case LiteralType::Nan:
+      return ParseNan(s, end, out_bits);
+  }
+
+  WABT_UNREACHABLE;
+}
+
+// static
+template <typename T>
+void FloatWriter<T>::WriteHex(char* out, size_t size, Uint bits) {
+  static constexpr int kNumNybbles = Traits::kBits / 4;
+  static constexpr int kTopNybbleShift = Traits::kBits - 4;
+  static constexpr Uint kTopNybble = Uint(0xf) << kTopNybbleShift;
+  static const char s_hex_digits[] = "0123456789abcdef";
+
+  char buffer[Traits::kMaxHexBufferSize];
+  char* p = buffer;
+  bool is_neg = (bits >> Traits::kSignShift);
+  int exp = ((bits >> Traits::kSigBits) & Traits::kExpMask) - Traits::kExpBias;
+  Uint sig = bits & Traits::kSigMask;
+
+  if (is_neg) {
+    *p++ = '-';
+  }
+  if (exp == Traits::kMaxExp) {
+    // Infinity or nan.
+    if (sig == 0) {
+      strcpy(p, "inf");
+      p += 3;
+    } else {
+      strcpy(p, "nan");
+      p += 3;
+      if (sig != Traits::kQuietNanTag) {
+        strcpy(p, ":0x");
+        p += 3;
+        // Skip leading zeroes.
+        int num_nybbles = kNumNybbles;
+        while ((sig & kTopNybble) == 0) {
+          sig <<= 4;
+          num_nybbles--;
+        }
+        while (num_nybbles) {
+          Uint nybble = (sig >> kTopNybbleShift) & 0xf;
+          *p++ = s_hex_digits[nybble];
+          sig <<= 4;
+          --num_nybbles;
+        }
+      }
+    }
+  } else {
+    bool is_zero = sig == 0 && exp == Traits::kMinExp;
+    strcpy(p, "0x");
+    p += 2;
+    *p++ = is_zero ? '0' : '1';
+
+    // Shift sig up so the top 4-bits are at the top of the Uint.
+    sig <<= Traits::kBits - Traits::kSigBits;
+
+    if (sig) {
+      if (exp == Traits::kMinExp) {
+        // Subnormal; shift the significand up, and shift out the implicit 1.
+        Uint leading_zeroes = Clz(sig);
+        if (leading_zeroes < Traits::kSignShift) {
+          sig <<= leading_zeroes + 1;
+        } else {
+          sig = 0;
+        }
+        exp -= leading_zeroes;
+      }
+
+      *p++ = '.';
+      while (sig) {
+        int nybble = (sig >> kTopNybbleShift) & 0xf;
+        *p++ = s_hex_digits[nybble];
+        sig <<= 4;
+      }
+    }
+    *p++ = 'p';
+    if (is_zero) {
+      strcpy(p, "+0");
+      p += 2;
+    } else {
+      if (exp < 0) {
+        *p++ = '-';
+        exp = -exp;
+      } else {
+        *p++ = '+';
+      }
+      if (exp >= 1000) {
+        *p++ = '1';
+      }
+      if (exp >= 100) {
+        *p++ = '0' + (exp / 100) % 10;
+      }
+      if (exp >= 10) {
+        *p++ = '0' + (exp / 10) % 10;
+      }
+      *p++ = '0' + exp % 10;
+    }
+  }
+
+  size_t len = p - buffer;
+  if (len >= size) {
+    len = size - 1;
+  }
+  memcpy(out, buffer, len);
+  out[len] = '\0';
+}
+
+}  // end anonymous namespace
+
+Result ParseHexdigit(char c, uint32_t* out) {
+  if (static_cast<unsigned int>(c - '0') <= 9) {
+    *out = c - '0';
+    return Result::Ok;
+  } else if (static_cast<unsigned int>(c - 'a') < 6) {
+    *out = 10 + (c - 'a');
+    return Result::Ok;
+  } else if (static_cast<unsigned int>(c - 'A') < 6) {
+    *out = 10 + (c - 'A');
+    return Result::Ok;
+  }
+  return Result::Error;
+}
+
+Result ParseUint64(const char* s, const char* end, uint64_t* out) {
+  if (s == end) {
+    return Result::Error;
+  }
+  uint64_t value = 0;
+  if (*s == '0' && s + 1 < end && s[1] == 'x') {
+    s += 2;
+    if (s == end) {
+      return Result::Error;
+    }
+    constexpr uint64_t kMaxDiv16 = UINT64_MAX / 16;
+    constexpr uint64_t kMaxMod16 = UINT64_MAX % 16;
+    for (; s < end; ++s) {
+      uint32_t digit;
+      if (*s == '_') {
+        continue;
+      }
+      CHECK_RESULT(ParseHexdigit(*s, &digit));
+      // Check for overflow.
+      if (value > kMaxDiv16 || (value == kMaxDiv16 && digit > kMaxMod16)) {
+        return Result::Error;
+      }
+      value = value * 16 + digit;
+    }
+  } else {
+    constexpr uint64_t kMaxDiv10 = UINT64_MAX / 10;
+    constexpr uint64_t kMaxMod10 = UINT64_MAX % 10;
+    for (; s < end; ++s) {
+      if (*s == '_') {
+        continue;
+      }
+      uint32_t digit = (*s - '0');
+      if (digit > 9) {
+        return Result::Error;
+      }
+      // Check for overflow.
+      if (value > kMaxDiv10 || (value == kMaxDiv10 && digit > kMaxMod10)) {
+        return Result::Error;
+      }
+      value = value * 10 + digit;
+    }
+  }
+  if (s != end) {
+    return Result::Error;
+  }
+  *out = value;
+  return Result::Ok;
+}
+
+Result ParseInt64(const char* s,
+                  const char* end,
+                  uint64_t* out,
+                  ParseIntType parse_type) {
+  bool has_sign = false;
+  if (*s == '-' || *s == '+') {
+    if (parse_type == ParseIntType::UnsignedOnly) {
+      return Result::Error;
+    }
+    if (*s == '-') {
+      has_sign = true;
+    }
+    s++;
+  }
+  uint64_t value = 0;
+  Result result = ParseUint64(s, end, &value);
+  if (has_sign) {
+    // abs(INT64_MIN) == INT64_MAX + 1.
+    if (value > static_cast<uint64_t>(INT64_MAX) + 1) {
+      return Result::Error;
+    }
+    value = UINT64_MAX - value + 1;
+  }
+  *out = value;
+  return result;
+}
+
+namespace {
+uint32_t AddWithCarry(uint32_t x, uint32_t y, uint32_t* carry) {
+  // Increments *carry if the addition overflows, otherwise leaves carry alone.
+  if ((0xffffffff - x) < y) ++*carry;
+  return x + y;
+}
+
+void Mul10(v128* v) {
+  // Multiply-by-10 decomposes into (x << 3) + (x << 1). We implement those
+  // operations with carrying from smaller quads of the v128 to the larger
+  // quads.
+
+  constexpr uint32_t kTopThreeBits = 0xe0000000;
+  constexpr uint32_t kTopBit = 0x80000000;
+
+  uint32_t carry_into_v1 =
+      ((v->u32(0) & kTopThreeBits) >> 29) + ((v->u32(0) & kTopBit) >> 31);
+  v->set_u32(0, AddWithCarry(v->u32(0) << 3, v->u32(0) << 1, &carry_into_v1));
+  uint32_t carry_into_v2 =
+      ((v->u32(1) & kTopThreeBits) >> 29) + ((v->u32(1) & kTopBit) >> 31);
+  v->set_u32(1, AddWithCarry(v->u32(1) << 3, v->u32(1) << 1, &carry_into_v2));
+  v->set_u32(1, AddWithCarry(v->u32(1), carry_into_v1, &carry_into_v2));
+  uint32_t carry_into_v3 =
+      ((v->u32(2) & kTopThreeBits) >> 29) + ((v->u32(2) & kTopBit) >> 31);
+  v->set_u32(2, AddWithCarry(v->u32(2) << 3, v->u32(2) << 1, &carry_into_v3));
+  v->set_u32(2, AddWithCarry(v->u32(2), carry_into_v2, &carry_into_v3));
+  v->set_u32(3, v->u32(3) * 10 + carry_into_v3);
+}
+}
+
+Result ParseUint128(const char* s,
+                    const char* end,
+                    v128* out) {
+  if (s == end) {
+    return Result::Error;
+  }
+
+  out->set_zero();
+
+  while (true) {
+    uint32_t digit = (*s - '0');
+    if (digit > 9) {
+      return Result::Error;
+    }
+
+    uint32_t carry_into_v1 = 0;
+    uint32_t carry_into_v2 = 0;
+    uint32_t carry_into_v3 = 0;
+    uint32_t overflow = 0;
+    out->set_u32(0, AddWithCarry(out->u32(0), digit, &carry_into_v1));
+    out->set_u32(1, AddWithCarry(out->u32(1), carry_into_v1, &carry_into_v2));
+    out->set_u32(2, AddWithCarry(out->u32(2), carry_into_v2, &carry_into_v3));
+    out->set_u32(3, AddWithCarry(out->u32(3), carry_into_v3, &overflow));
+    if (overflow) {
+      return Result::Error;
+    }
+
+    ++s;
+
+    if (s == end) {
+      break;
+    }
+
+    Mul10(out);
+  }
+  return Result::Ok;
+}
+
+template <typename U>
+Result ParseInt(const char* s,
+                const char* end,
+                U* out,
+                ParseIntType parse_type) {
+  typedef typename std::make_signed<U>::type S;
+  uint64_t value;
+  bool has_sign = false;
+  if (*s == '-' || *s == '+') {
+    if (parse_type == ParseIntType::UnsignedOnly) {
+      return Result::Error;
+    }
+    if (*s == '-') {
+      has_sign = true;
+    }
+    s++;
+  }
+  CHECK_RESULT(ParseUint64(s, end, &value));
+
+  if (has_sign) {
+    // abs(INTN_MIN) == INTN_MAX + 1.
+    if (value > static_cast<uint64_t>(std::numeric_limits<S>::max()) + 1) {
+      return Result::Error;
+    }
+    value = std::numeric_limits<U>::max() - value + 1;
+  } else {
+    if (value > static_cast<uint64_t>(std::numeric_limits<U>::max())) {
+      return Result::Error;
+    }
+  }
+  *out = static_cast<U>(value);
+  return Result::Ok;
+}
+
+Result ParseInt8(const char* s,
+                 const char* end,
+                 uint8_t* out,
+                 ParseIntType parse_type) {
+  return ParseInt(s, end, out, parse_type);
+}
+
+Result ParseInt16(const char* s,
+                  const char* end,
+                  uint16_t* out,
+                  ParseIntType parse_type) {
+  return ParseInt(s, end, out, parse_type);
+}
+
+Result ParseInt32(const char* s,
+                  const char* end,
+                  uint32_t* out,
+                  ParseIntType parse_type) {
+  return ParseInt(s, end, out, parse_type);
+}
+
+Result ParseFloat(LiteralType literal_type,
+                  const char* s,
+                  const char* end,
+                  uint32_t* out_bits) {
+  return FloatParser<float>::Parse(literal_type, s, end, out_bits);
+}
+
+Result ParseDouble(LiteralType literal_type,
+                   const char* s,
+                   const char* end,
+                   uint64_t* out_bits) {
+  return FloatParser<double>::Parse(literal_type, s, end, out_bits);
+}
+
+void WriteFloatHex(char* buffer, size_t size, uint32_t bits) {
+  return FloatWriter<float>::WriteHex(buffer, size, bits);
+}
+
+void WriteDoubleHex(char* buffer, size_t size, uint64_t bits) {
+  return FloatWriter<double>::WriteHex(buffer, size, bits);
+}
+
+void WriteUint128(char* buffer, size_t size, v128 bits) {
+  uint64_t digits;
+  uint64_t remainder;
+  char reversed_buffer[40];
+  size_t len = 0;
+  do {
+    remainder = bits.u32(3);
+
+    for (int i = 3; i != 0; --i) {
+      digits = remainder / 10;
+      remainder = ((remainder - digits * 10) << 32) + bits.u32(i-1);
+      bits.set_u32(i, digits);
+    }
+
+    digits = remainder / 10;
+    remainder = remainder - digits * 10;
+    bits.set_u32(0, digits);
+
+    char remainder_buffer[21];
+    snprintf(remainder_buffer, 21, "%" PRIu64, remainder);
+    int remainder_buffer_len = strlen(remainder_buffer);
+    assert(len + remainder_buffer_len < sizeof(reversed_buffer));
+    memcpy(&reversed_buffer[len], remainder_buffer, remainder_buffer_len);
+    len += remainder_buffer_len;
+  } while (!bits.is_zero());
+  size_t truncated_tail = 0;
+  if (len >= size) {
+    truncated_tail = len - size + 1;
+    len = size - 1;
+  }
+  std::reverse_copy(reversed_buffer + truncated_tail,
+                    reversed_buffer + len + truncated_tail,
+                    buffer);
+  buffer[len] = '\0';
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/literal.h
new file mode 100644 (file)
index 0000000..b698261
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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_LITERAL_H_
+#define WABT_LITERAL_H_
+
+#include <cstdint>
+
+#include "src/common.h"
+
+namespace wabt {
+
+// These functions all return Result::Ok on success and Result::Error on
+// failure.
+//
+// NOTE: the functions are written for use with wast-lexer, assuming that the
+// literal has already matched the patterns defined there. As a result, the
+// only validation that is done is for overflow, not for otherwise bogus input.
+
+enum class LiteralType {
+  Int,
+  Float,
+  Hexfloat,
+  Infinity,
+  Nan,
+};
+
+enum class ParseIntType {
+  UnsignedOnly = 0,
+  SignedAndUnsigned = 1,
+};
+
+/* Size of char buffer required to hold hex representation of a float/double */
+#define WABT_MAX_FLOAT_HEX 20
+#define WABT_MAX_DOUBLE_HEX 40
+
+Result ParseHexdigit(char c, uint32_t* out);
+Result ParseInt8(const char* s,
+                 const char* end,
+                 uint8_t* out,
+                 ParseIntType parse_type);
+Result ParseInt16(const char* s,
+                  const char* end,
+                  uint16_t* out,
+                  ParseIntType parse_type);
+Result ParseInt32(const char* s,
+                  const char* end,
+                  uint32_t* out,
+                  ParseIntType parse_type);
+Result ParseInt64(const char* s,
+                  const char* end,
+                  uint64_t* out,
+                  ParseIntType parse_type);
+Result ParseUint64(const char* s, const char* end, uint64_t* out);
+Result ParseUint128(const char* s, const char* end, v128* out);
+Result ParseFloat(LiteralType literal_type,
+                  const char* s,
+                  const char* end,
+                  uint32_t* out_bits);
+Result ParseDouble(LiteralType literal_type,
+                   const char* s,
+                   const char* end,
+                   uint64_t* out_bits);
+
+void WriteFloatHex(char* buffer, size_t size, uint32_t bits);
+void WriteDoubleHex(char* buffer, size_t size, uint64_t bits);
+void WriteUint128(char* buffer, size_t size, v128 bits);
+
+}  // namespace wabt
+
+#endif /* WABT_LITERAL_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/make-unique.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/make-unique.h
new file mode 100644 (file)
index 0000000..46d3ac1
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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_MAKE_UNIQUE_H_
+#define WABT_MAKE_UNIQUE_H_
+
+#include <memory>
+
+namespace wabt {
+
+// This is named MakeUnique instead of make_unique because make_unique has the
+// potential to conflict with std::make_unique if it is defined.
+//
+// On gcc/clang, we currently compile with c++11, which doesn't define
+// std::make_unique, but on MSVC the newest C++ version is always used, which
+// includes std::make_unique. If an argument from the std namespace is used, it
+// will cause ADL to find std::make_unique, and an unqualified call to
+// make_unique will be ambiguous. We can work around this by fully qualifying
+// the call (i.e. wabt::make_unique), but it's simpler to just use a different
+// name. It's also more consistent with other names in the wabt namespace,
+// which use CamelCase.
+template <typename T, typename... Args>
+std::unique_ptr<T> MakeUnique(Args&&... args) {
+  return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+}  // namespace wabt
+
+#endif  // WABT_MAKE_UNIQUE_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.c b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.c
new file mode 100644 (file)
index 0000000..c3e06d0
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 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/opcode-code-table.h"
+
+#include "config.h"
+
+#include <stdint.h>
+
+typedef enum WabtOpcodeEnum {
+#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
+                    text, decomp)                                             \
+  Name,
+#include "opcode.def"
+#undef WABT_OPCODE
+  Invalid,
+} WabtOpcodeEnum;
+
+WABT_STATIC_ASSERT(Invalid <= WABT_OPCODE_CODE_TABLE_SIZE);
+
+/* The array index calculated below must match the one in Opcode::FromCode. */
+uint32_t WabtOpcodeCodeTable[WABT_OPCODE_CODE_TABLE_SIZE] = {
+#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
+                    text, decomp)                                             \
+  [(prefix << 8) + code] = Name,
+#include "opcode.def"
+#undef WABT_OPCODE
+};
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode-code-table.h
new file mode 100644 (file)
index 0000000..b223e16
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2018 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_OPCODE_CODE_TABLE_H_
+#define WABT_OPCODE_CODE_TABLE_H_
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WABT_OPCODE_CODE_TABLE_SIZE 65536
+
+/* This structure is defined in C because C++ doesn't (yet) allow you to use
+ * designated array initializers, i.e. [10] = {foo}.
+ */
+extern uint32_t WabtOpcodeCodeTable[WABT_OPCODE_CODE_TABLE_SIZE];
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* WABT_OPCODE_CODE_TABLE_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.cc
new file mode 100644 (file)
index 0000000..03d2479
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * 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/opcode.h"
+
+#include "src/feature.h"
+
+namespace wabt {
+
+// static
+Opcode::Info Opcode::infos_[] = {
+#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
+                    text, decomp)                                             \
+  {text,     decomp, Type::rtype, {Type::type1, Type::type2, Type::type3},    \
+   mem_size, prefix, code,        PrefixCode(prefix, code)},
+#include "src/opcode.def"
+#undef WABT_OPCODE
+
+  {"<invalid>", "", Type::Void, {Type::Void, Type::Void, Type::Void}, 0, 0, 0, 0},
+};
+
+#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
+                    text, decomp)                                                     \
+  /* static */ Opcode Opcode::Name##_Opcode(Opcode::Name);
+#include "src/opcode.def"
+#undef WABT_OPCODE
+
+Opcode::Info Opcode::GetInfo() const {
+  if (enum_ < Invalid) {
+    return infos_[enum_];
+  }
+
+  Info invalid_info = infos_[Opcode::Invalid];
+  DecodeInvalidOpcode(enum_, &invalid_info.prefix, &invalid_info.code);
+  invalid_info.prefix_code = PrefixCode(invalid_info.prefix, invalid_info.code);
+  return invalid_info;
+}
+
+bool Opcode::IsNaturallyAligned(Address alignment) const {
+  Address opcode_align = GetMemorySize();
+  return alignment == WABT_USE_NATURAL_ALIGNMENT || alignment == opcode_align;
+}
+
+Address Opcode::GetAlignment(Address alignment) const {
+  if (alignment == WABT_USE_NATURAL_ALIGNMENT) {
+    return GetMemorySize();
+  }
+  return alignment;
+}
+
+bool Opcode::IsEnabled(const Features& features) const {
+  switch (enum_) {
+    case Opcode::Try:
+    case Opcode::Catch:
+    case Opcode::Unwind:
+    case Opcode::Delegate:
+    case Opcode::Throw:
+    case Opcode::Rethrow:
+      return features.exceptions_enabled();
+
+    case Opcode::ReturnCallIndirect:
+    case Opcode::ReturnCall:
+      return features.tail_call_enabled();
+
+    case Opcode::I32TruncSatF32S:
+    case Opcode::I32TruncSatF32U:
+    case Opcode::I32TruncSatF64S:
+    case Opcode::I32TruncSatF64U:
+    case Opcode::I64TruncSatF32S:
+    case Opcode::I64TruncSatF32U:
+    case Opcode::I64TruncSatF64S:
+    case Opcode::I64TruncSatF64U:
+      return features.sat_float_to_int_enabled();
+
+    case Opcode::I32Extend8S:
+    case Opcode::I32Extend16S:
+    case Opcode::I64Extend8S:
+    case Opcode::I64Extend16S:
+    case Opcode::I64Extend32S:
+      return features.sign_extension_enabled();
+
+    case Opcode::MemoryAtomicNotify:
+    case Opcode::MemoryAtomicWait32:
+    case Opcode::MemoryAtomicWait64:
+    case Opcode::AtomicFence:
+    case Opcode::I32AtomicLoad:
+    case Opcode::I64AtomicLoad:
+    case Opcode::I32AtomicLoad8U:
+    case Opcode::I32AtomicLoad16U:
+    case Opcode::I64AtomicLoad8U:
+    case Opcode::I64AtomicLoad16U:
+    case Opcode::I64AtomicLoad32U:
+    case Opcode::I32AtomicStore:
+    case Opcode::I64AtomicStore:
+    case Opcode::I32AtomicStore8:
+    case Opcode::I32AtomicStore16:
+    case Opcode::I64AtomicStore8:
+    case Opcode::I64AtomicStore16:
+    case Opcode::I64AtomicStore32:
+    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:
+    case Opcode::I32AtomicRmwCmpxchg:
+    case Opcode::I64AtomicRmwCmpxchg:
+    case Opcode::I32AtomicRmw8CmpxchgU:
+    case Opcode::I32AtomicRmw16CmpxchgU:
+    case Opcode::I64AtomicRmw8CmpxchgU:
+    case Opcode::I64AtomicRmw16CmpxchgU:
+    case Opcode::I64AtomicRmw32CmpxchgU:
+      return features.threads_enabled();
+
+    case Opcode::V128Const:
+    case Opcode::V128Load:
+    case Opcode::V128Store:
+    case Opcode::I8X16Splat:
+    case Opcode::I16X8Splat:
+    case Opcode::I32X4Splat:
+    case Opcode::I64X2Splat:
+    case Opcode::F32X4Splat:
+    case Opcode::F64X2Splat:
+    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:
+    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::I8X16Neg:
+    case Opcode::I16X8Neg:
+    case Opcode::I32X4Neg:
+    case Opcode::I64X2Neg:
+    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::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::V128Not:
+    case Opcode::V128BitSelect:
+    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::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:
+    case Opcode::F32X4Neg:
+    case Opcode::F64X2Neg:
+    case Opcode::F32X4Abs:
+    case Opcode::F64X2Abs:
+    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::F32X4Sqrt:
+    case Opcode::F64X2Sqrt:
+    case Opcode::F32X4ConvertI32X4S:
+    case Opcode::F32X4ConvertI32X4U:
+    case Opcode::I32X4TruncSatF32X4S:
+    case Opcode::I32X4TruncSatF32X4U:
+    case Opcode::I8X16Swizzle:
+    case Opcode::I8X16Shuffle:
+    case Opcode::V128Load8Splat:
+    case Opcode::V128Load16Splat:
+    case Opcode::V128Load32Splat:
+    case Opcode::V128Load64Splat:
+    case Opcode::I8X16Abs:
+    case Opcode::I16X8Abs:
+    case Opcode::I32X4Abs:
+      return features.simd_enabled();
+
+    case Opcode::MemoryInit:
+    case Opcode::DataDrop:
+    case Opcode::MemoryCopy:
+    case Opcode::MemoryFill:
+    case Opcode::TableInit:
+    case Opcode::ElemDrop:
+    case Opcode::TableCopy:
+      return features.bulk_memory_enabled();
+
+    case Opcode::TableGet:
+    case Opcode::TableSet:
+    case Opcode::TableGrow:
+    case Opcode::TableSize:
+    case Opcode::RefNull:
+    case Opcode::RefIsNull:
+      return features.reference_types_enabled();
+
+    // Interpreter opcodes are never "enabled".
+    case Opcode::InterpAlloca:
+    case Opcode::InterpBrUnless:
+    case Opcode::InterpCallImport:
+    case Opcode::InterpData:
+    case Opcode::InterpDropKeep:
+      return false;
+
+    default:
+      return true;
+  }
+}
+
+uint32_t Opcode::GetSimdLaneCount() const {
+  switch (enum_) {
+    case Opcode::I8X16ExtractLaneS:
+    case Opcode::I8X16ExtractLaneU:
+    case Opcode::I8X16ReplaceLane:
+      return 16;
+      break;
+    case Opcode::I16X8ExtractLaneS:
+    case Opcode::I16X8ExtractLaneU:
+    case Opcode::I16X8ReplaceLane:
+      return 8;
+      break;
+    case Opcode::F32X4ExtractLane:
+    case Opcode::F32X4ReplaceLane:
+    case Opcode::I32X4ExtractLane:
+    case Opcode::I32X4ReplaceLane:
+      return 4;
+      break;
+    case Opcode::F64X2ExtractLane:
+    case Opcode::F64X2ReplaceLane:
+    case Opcode::I64X2ExtractLane:
+    case Opcode::I64X2ReplaceLane:
+      return 2;
+      break;
+    default:
+      WABT_UNREACHABLE;
+  }
+}
+
+// Get the byte sequence for this opcode, including prefix.
+std::vector<uint8_t> Opcode::GetBytes() const {
+  std::vector<uint8_t> result;
+  if (HasPrefix()) {
+    result.push_back(GetPrefix());
+    uint8_t buffer[5];
+    Offset length =
+        WriteU32Leb128Raw(buffer, buffer + sizeof(buffer), GetCode());
+    assert(length != 0);
+    result.insert(result.end(), buffer, buffer + length);
+  } else {
+    result.push_back(GetCode());
+  }
+  return result;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.def b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.def
new file mode 100644 (file)
index 0000000..0c661c1
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * 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_OPCODE
+#error "You must define WABT_OPCODE before including this file."
+#endif
+
+/* *** NOTE *** This list must be kept sorted so it can be binary searched */
+
+/*
+ *     tr: result type
+ *     t1: type of the 1st parameter
+ *     t2: type of the 2nd parameter
+ *     t3: type of the 3rd parameter
+ *      m: memory size of the operation, if any
+ * prefix: the 1-byte opcode prefix, if any
+ *   code: opcode
+ *   Name: used to generate the opcode enum
+ *   text: a string of the opcode name in the text format
+ * decomp: an optional friendly version of text, used for decompilation.
+ *
+ *          tr    t1    t2    t3    m  prefix code  Name text
+ * ==========================================================  */
+
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x00, Unreachable, "unreachable", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x01, Nop, "nop", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x02, Block, "block", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x03, Loop, "loop", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x04, If, "if", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x05, Else, "else", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x06, Try, "try", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x07, Catch, "catch", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x08, Throw, "throw", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x09, Rethrow, "rethrow", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x0a, Unwind, "unwind", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x0b, End, "end", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x0c, Br, "br", "")
+WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0x0d, BrIf, "br_if", "")
+WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0x0e, BrTable, "br_table", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x0f, Return, "return", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x10, Call, "call", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x11, CallIndirect, "call_indirect", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x12, ReturnCall, "return_call", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x13, ReturnCallIndirect, "return_call_indirect", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x18, Delegate, "delegate", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x19, CatchAll, "catch_all", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x1a, Drop, "drop", "")
+WABT_OPCODE(___,  ___,  ___,  I32,  0,  0,    0x1b, Select, "select", "")
+WABT_OPCODE(___,  ___,  ___,  I32,  0,  0,    0x1c, SelectT, "select", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x20, LocalGet, "local.get", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x21, LocalSet, "local.set", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x22, LocalTee, "local.tee", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x23, GlobalGet, "global.get", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0x24, GlobalSet, "global.set", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  4,  0,    0x28, I32Load, "i32.load", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  8,  0,    0x29, I64Load, "i64.load", "")
+WABT_OPCODE(F32,  I32,  ___,  ___,  4,  0,    0x2a, F32Load, "f32.load", "")
+WABT_OPCODE(F64,  I32,  ___,  ___,  8,  0,    0x2b, F64Load, "f64.load", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  1,  0,    0x2c, I32Load8S, "i32.load8_s", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  1,  0,    0x2d, I32Load8U, "i32.load8_u", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  2,  0,    0x2e, I32Load16S, "i32.load16_s", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  2,  0,    0x2f, I32Load16U, "i32.load16_u", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  1,  0,    0x30, I64Load8S, "i64.load8_s", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  1,  0,    0x31, I64Load8U, "i64.load8_u", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  2,  0,    0x32, I64Load16S, "i64.load16_s", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  2,  0,    0x33, I64Load16U, "i64.load16_u", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  4,  0,    0x34, I64Load32S, "i64.load32_s", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  4,  0,    0x35, I64Load32U, "i64.load32_u", "")
+WABT_OPCODE(___,  I32,  I32,  ___,  4,  0,    0x36, I32Store, "i32.store", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  8,  0,    0x37, I64Store, "i64.store", "")
+WABT_OPCODE(___,  I32,  F32,  ___,  4,  0,    0x38, F32Store, "f32.store", "")
+WABT_OPCODE(___,  I32,  F64,  ___,  8,  0,    0x39, F64Store, "f64.store", "")
+WABT_OPCODE(___,  I32,  I32,  ___,  1,  0,    0x3a, I32Store8, "i32.store8", "")
+WABT_OPCODE(___,  I32,  I32,  ___,  2,  0,    0x3b, I32Store16, "i32.store16", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  1,  0,    0x3c, I64Store8, "i64.store8", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  2,  0,    0x3d, I64Store16, "i64.store16", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  4,  0,    0x3e, I64Store32, "i64.store32", "")
+WABT_OPCODE(I32,  ___,  ___,  ___,  0,  0,    0x3f, MemorySize, "memory.size", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  0,  0,    0x40, MemoryGrow, "memory.grow", "")
+WABT_OPCODE(I32,  ___,  ___,  ___,  0,  0,    0x41, I32Const, "i32.const", "")
+WABT_OPCODE(I64,  ___,  ___,  ___,  0,  0,    0x42, I64Const, "i64.const", "")
+WABT_OPCODE(F32,  ___,  ___,  ___,  0,  0,    0x43, F32Const, "f32.const", "")
+WABT_OPCODE(F64,  ___,  ___,  ___,  0,  0,    0x44, F64Const, "f64.const", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  0,  0,    0x45, I32Eqz, "i32.eqz", "eqz")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x46, I32Eq, "i32.eq", "==")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x47, I32Ne, "i32.ne", "!=")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x48, I32LtS, "i32.lt_s", "<")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x49, I32LtU, "i32.lt_u", "<")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x4a, I32GtS, "i32.gt_s", ">")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x4b, I32GtU, "i32.gt_u", ">")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x4c, I32LeS, "i32.le_s", "<=")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x4d, I32LeU, "i32.le_u", "<=")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x4e, I32GeS, "i32.ge_s", ">=")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x4f, I32GeU, "i32.ge_u", ">=")
+WABT_OPCODE(I32,  I64,  ___,  ___,  0,  0,    0x50, I64Eqz, "i64.eqz", "eqz")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x51, I64Eq, "i64.eq", "==")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x52, I64Ne, "i64.ne", "!=")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x53, I64LtS, "i64.lt_s", "<")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x54, I64LtU, "i64.lt_u", "<")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x55, I64GtS, "i64.gt_s", ">")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x56, I64GtU, "i64.gt_u", ">")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x57, I64LeS, "i64.le_s", "<=")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x58, I64LeU, "i64.le_u", "<=")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x59, I64GeS, "i64.ge_s", ">=")
+WABT_OPCODE(I32,  I64,  I64,  ___,  0,  0,    0x5a, I64GeU, "i64.ge_u", ">=")
+WABT_OPCODE(I32,  F32,  F32,  ___,  0,  0,    0x5b, F32Eq, "f32.eq", "==")
+WABT_OPCODE(I32,  F32,  F32,  ___,  0,  0,    0x5c, F32Ne, "f32.ne", "!=")
+WABT_OPCODE(I32,  F32,  F32,  ___,  0,  0,    0x5d, F32Lt, "f32.lt", "<")
+WABT_OPCODE(I32,  F32,  F32,  ___,  0,  0,    0x5e, F32Gt, "f32.gt", ">")
+WABT_OPCODE(I32,  F32,  F32,  ___,  0,  0,    0x5f, F32Le, "f32.le", "<=")
+WABT_OPCODE(I32,  F32,  F32,  ___,  0,  0,    0x60, F32Ge, "f32.ge", ">=")
+WABT_OPCODE(I32,  F64,  F64,  ___,  0,  0,    0x61, F64Eq, "f64.eq", "==")
+WABT_OPCODE(I32,  F64,  F64,  ___,  0,  0,    0x62, F64Ne, "f64.ne", "!=")
+WABT_OPCODE(I32,  F64,  F64,  ___,  0,  0,    0x63, F64Lt, "f64.lt", "<")
+WABT_OPCODE(I32,  F64,  F64,  ___,  0,  0,    0x64, F64Gt, "f64.gt", ">")
+WABT_OPCODE(I32,  F64,  F64,  ___,  0,  0,    0x65, F64Le, "f64.le", "<=")
+WABT_OPCODE(I32,  F64,  F64,  ___,  0,  0,    0x66, F64Ge, "f64.ge", ">=")
+WABT_OPCODE(I32,  I32,  ___,  ___,  0,  0,    0x67, I32Clz, "i32.clz", "clz")
+WABT_OPCODE(I32,  I32,  ___,  ___,  0,  0,    0x68, I32Ctz, "i32.ctz", "ctz")
+WABT_OPCODE(I32,  I32,  ___,  ___,  0,  0,    0x69, I32Popcnt, "i32.popcnt", "popcnt")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x6a, I32Add, "i32.add", "+")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x6b, I32Sub, "i32.sub", "-")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x6c, I32Mul, "i32.mul", "*")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x6d, I32DivS, "i32.div_s", "/")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x6e, I32DivU, "i32.div_u", "/")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x6f, I32RemS, "i32.rem_s", "%")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x70, I32RemU, "i32.rem_u", "%")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x71, I32And, "i32.and", "&")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x72, I32Or, "i32.or", "|")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x73, I32Xor, "i32.xor", "^")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x74, I32Shl, "i32.shl", "<<")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x75, I32ShrS, "i32.shr_s", ">>")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x76, I32ShrU, "i32.shr_u", ">>")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x77, I32Rotl, "i32.rotl", "<<")
+WABT_OPCODE(I32,  I32,  I32,  ___,  0,  0,    0x78, I32Rotr, "i32.rotr", ">>")
+WABT_OPCODE(I64,  I64,  ___,  ___,  0,  0,    0x79, I64Clz, "i64.clz", "clz")
+WABT_OPCODE(I64,  I64,  ___,  ___,  0,  0,    0x7a, I64Ctz, "i64.ctz", "ctz")
+WABT_OPCODE(I64,  I64,  ___,  ___,  0,  0,    0x7b, I64Popcnt, "i64.popcnt", "popcnt")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x7c, I64Add, "i64.add", "+")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x7d, I64Sub, "i64.sub", "-")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x7e, I64Mul, "i64.mul", "*")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x7f, I64DivS, "i64.div_s", "/")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x80, I64DivU, "i64.div_u", "/")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x81, I64RemS, "i64.rem_s", "%")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x82, I64RemU, "i64.rem_u", "%")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x83, I64And, "i64.and", "&")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x84, I64Or, "i64.or", "|")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x85, I64Xor, "i64.xor", "^")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x86, I64Shl, "i64.shl", "<<")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x87, I64ShrS, "i64.shr_s", ">>")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x88, I64ShrU, "i64.shr_u", ">>")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x89, I64Rotl, "i64.rotl", "<<")
+WABT_OPCODE(I64,  I64,  I64,  ___,  0,  0,    0x8a, I64Rotr, "i64.rotr", ">>")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x8b, F32Abs, "f32.abs", "abs")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x8c, F32Neg, "f32.neg", "-")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x8d, F32Ceil, "f32.ceil", "ceil")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x8e, F32Floor, "f32.floor", "floor")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x8f, F32Trunc, "f32.trunc", "trunc")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x90, F32Nearest, "f32.nearest", "nearest")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x91, F32Sqrt, "f32.sqrt", "sqrt")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x92, F32Add, "f32.add", "+")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x93, F32Sub, "f32.sub", "-")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x94, F32Mul, "f32.mul", "*")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x95, F32Div, "f32.div", "/")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x96, F32Min, "f32.min", "min")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x97, F32Max, "f32.max", "max")
+WABT_OPCODE(F32,  F32,  F32,  ___,  0,  0,    0x98, F32Copysign, "f32.copysign", "copysign")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0x99, F64Abs, "f64.abs", "abs")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0x9a, F64Neg, "f64.neg", "-")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0x9b, F64Ceil, "f64.ceil", "ceil")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0x9c, F64Floor, "f64.floor", "floor")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0x9d, F64Trunc, "f64.trunc", "trunc")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0x9e, F64Nearest, "f64.nearest", "nearest")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0x9f, F64Sqrt, "f64.sqrt", "sqrt")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0xa0, F64Add, "f64.add", "+")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0xa1, F64Sub, "f64.sub", "-")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0xa2, F64Mul, "f64.mul", "*")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0xa3, F64Div, "f64.div", "/")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0xa4, F64Min, "f64.min", "min")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0xa5, F64Max, "f64.max", "max")
+WABT_OPCODE(F64,  F64,  F64,  ___,  0,  0,    0xa6, F64Copysign, "f64.copysign", "copysign")
+WABT_OPCODE(I32,  I64,  ___,  ___,  0,  0,    0xa7, I32WrapI64, "i32.wrap_i64", "")
+WABT_OPCODE(I32,  F32,  ___,  ___,  0,  0,    0xa8, I32TruncF32S, "i32.trunc_f32_s", "")
+WABT_OPCODE(I32,  F32,  ___,  ___,  0,  0,    0xa9, I32TruncF32U, "i32.trunc_f32_u", "")
+WABT_OPCODE(I32,  F64,  ___,  ___,  0,  0,    0xaa, I32TruncF64S, "i32.trunc_f64_s", "")
+WABT_OPCODE(I32,  F64,  ___,  ___,  0,  0,    0xab, I32TruncF64U, "i32.trunc_f64_u", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  0,  0,    0xac, I64ExtendI32S, "i64.extend_i32_s", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  0,  0,    0xad, I64ExtendI32U, "i64.extend_i32_u", "")
+WABT_OPCODE(I64,  F32,  ___,  ___,  0,  0,    0xae, I64TruncF32S, "i64.trunc_f32_s", "")
+WABT_OPCODE(I64,  F32,  ___,  ___,  0,  0,    0xaf, I64TruncF32U, "i64.trunc_f32_u", "")
+WABT_OPCODE(I64,  F64,  ___,  ___,  0,  0,    0xb0, I64TruncF64S, "i64.trunc_f64_s", "")
+WABT_OPCODE(I64,  F64,  ___,  ___,  0,  0,    0xb1, I64TruncF64U, "i64.trunc_f64_u", "")
+WABT_OPCODE(F32,  I32,  ___,  ___,  0,  0,    0xb2, F32ConvertI32S, "f32.convert_i32_s", "")
+WABT_OPCODE(F32,  I32,  ___,  ___,  0,  0,    0xb3, F32ConvertI32U, "f32.convert_i32_u", "")
+WABT_OPCODE(F32,  I64,  ___,  ___,  0,  0,    0xb4, F32ConvertI64S, "f32.convert_i64_s", "")
+WABT_OPCODE(F32,  I64,  ___,  ___,  0,  0,    0xb5, F32ConvertI64U, "f32.convert_i64_u", "")
+WABT_OPCODE(F32,  F64,  ___,  ___,  0,  0,    0xb6, F32DemoteF64, "f32.demote_f64", "")
+WABT_OPCODE(F64,  I32,  ___,  ___,  0,  0,    0xb7, F64ConvertI32S, "f64.convert_i32_s", "")
+WABT_OPCODE(F64,  I32,  ___,  ___,  0,  0,    0xb8, F64ConvertI32U, "f64.convert_i32_u", "")
+WABT_OPCODE(F64,  I64,  ___,  ___,  0,  0,    0xb9, F64ConvertI64S, "f64.convert_i64_s", "")
+WABT_OPCODE(F64,  I64,  ___,  ___,  0,  0,    0xba, F64ConvertI64U, "f64.convert_i64_u", "")
+WABT_OPCODE(F64,  F32,  ___,  ___,  0,  0,    0xbb, F64PromoteF32, "f64.promote_f32", "")
+WABT_OPCODE(I32,  F32,  ___,  ___,  0,  0,    0xbc, I32ReinterpretF32, "i32.reinterpret_f32", "")
+WABT_OPCODE(I64,  F64,  ___,  ___,  0,  0,    0xbd, I64ReinterpretF64, "i64.reinterpret_f64", "")
+WABT_OPCODE(F32,  I32,  ___,  ___,  0,  0,    0xbe, F32ReinterpretI32, "f32.reinterpret_i32", "")
+WABT_OPCODE(F64,  I64,  ___,  ___,  0,  0,    0xbf, F64ReinterpretI64, "f64.reinterpret_i64", "")
+
+/* Sign-extension opcodes (--enable-sign-extension) */
+WABT_OPCODE(I32,  I32,  ___,  ___,  0,  0,    0xC0, I32Extend8S, "i32.extend8_s", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  0,  0,    0xC1, I32Extend16S, "i32.extend16_s", "")
+WABT_OPCODE(I64,  I64,  ___,  ___,  0,  0,    0xC2, I64Extend8S, "i64.extend8_s", "")
+WABT_OPCODE(I64,  I64,  ___,  ___,  0,  0,    0xC3, I64Extend16S, "i64.extend16_s", "")
+WABT_OPCODE(I64,  I64,  ___,  ___,  0,  0,    0xC4, I64Extend32S, "i64.extend32_s", "")
+
+/* Interpreter-only opcodes */
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe0, InterpAlloca, "alloca", "")
+WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0xe1, InterpBrUnless, "br_unless", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe2, InterpCallImport, "call_import", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe3, InterpData, "data", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xe4, InterpDropKeep, "drop_keep", "")
+
+/* Saturating float-to-int opcodes (--enable-saturating-float-to-int) */
+WABT_OPCODE(I32,  F32,  ___,  ___,  0,  0xfc, 0x00, I32TruncSatF32S, "i32.trunc_sat_f32_s", "")
+WABT_OPCODE(I32,  F32,  ___,  ___,  0,  0xfc, 0x01, I32TruncSatF32U, "i32.trunc_sat_f32_u", "")
+WABT_OPCODE(I32,  F64,  ___,  ___,  0,  0xfc, 0x02, I32TruncSatF64S, "i32.trunc_sat_f64_s", "")
+WABT_OPCODE(I32,  F64,  ___,  ___,  0,  0xfc, 0x03, I32TruncSatF64U, "i32.trunc_sat_f64_u", "")
+WABT_OPCODE(I64,  F32,  ___,  ___,  0,  0xfc, 0x04, I64TruncSatF32S, "i64.trunc_sat_f32_s", "")
+WABT_OPCODE(I64,  F32,  ___,  ___,  0,  0xfc, 0x05, I64TruncSatF32U, "i64.trunc_sat_f32_u", "")
+WABT_OPCODE(I64,  F64,  ___,  ___,  0,  0xfc, 0x06, I64TruncSatF64S, "i64.trunc_sat_f64_s", "")
+WABT_OPCODE(I64,  F64,  ___,  ___,  0,  0xfc, 0x07, I64TruncSatF64U, "i64.trunc_sat_f64_u", "")
+
+/* Bulk-memory (--enable-bulk-memory) */
+WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x08, MemoryInit, "memory.init", "")
+WABT_OPCODE(___, ___,  ___,  ___,  0,  0xfc, 0x09, DataDrop, "data.drop", "")
+WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x0a, MemoryCopy,"memory.copy", "")
+WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x0b, MemoryFill, "memory.fill", "")
+WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x0c, TableInit, "table.init", "")
+WABT_OPCODE(___, ___,  ___,  ___,  0,  0xfc, 0x0d, ElemDrop, "elem.drop", "")
+WABT_OPCODE(___, I32,  I32,  I32,  0,  0xfc, 0x0e, TableCopy, "table.copy", "")
+
+/* Reference types (--enable-reference-types) */
+WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0x25, TableGet, "table.get", "")
+WABT_OPCODE(___,  I32,  ___,  ___,  0,  0,    0x26, TableSet, "table.set", "")
+WABT_OPCODE(___,  ___,  I32,  ___,  0,  0xfc, 0x0f, TableGrow, "table.grow", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0xfc, 0x10, TableSize, "table.size", "")
+WABT_OPCODE(___,  I32,  ___,  I32,  0,  0xfc, 0x11, TableFill, "table.fill", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xd0, RefNull, "ref.null", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xd1, RefIsNull, "ref.is_null", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0,    0xd2, RefFunc, "ref.func", "")
+
+/* Simd opcodes (--enable-simd) */
+WABT_OPCODE(V128, I32,  ___,  ___,  16, 0xfd, 0x00, V128Load,  "v128.load", "")
+WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x01, V128Load8X8S, "v128.load8x8_s", "")
+WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x02, V128Load8X8U, "v128.load8x8_u", "")
+WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x03, V128Load16X4S, "v128.load16x4_s", "")
+WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x04, V128Load16X4U, "v128.load16x4_u", "")
+WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x05, V128Load32X2S, "v128.load32x2_s", "")
+WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x06, V128Load32X2U, "v128.load32x2_u", "")
+WABT_OPCODE(V128, I32,   ___, ___,  1,  0xfd, 0x07, V128Load8Splat, "v128.load8_splat", "")
+WABT_OPCODE(V128, I32,   ___, ___,  2,  0xfd, 0x08, V128Load16Splat, "v128.load16_splat", "")
+WABT_OPCODE(V128, I32,   ___, ___,  4,  0xfd, 0x09, V128Load32Splat, "v128.load32_splat", "")
+WABT_OPCODE(V128, I32,   ___, ___,  8,  0xfd, 0x0a, V128Load64Splat, "v128.load64_splat", "")
+WABT_OPCODE(___,  I32,  V128, ___,  16, 0xfd, 0x0b, V128Store, "v128.store", "")
+WABT_OPCODE(V128, ___,  ___,  ___,  0,  0xfd, 0x0c, V128Const, "v128.const", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x0d, I8X16Shuffle, "i8x16.shuffle", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x0e, I8X16Swizzle, "i8x16.swizzle", "")
+WABT_OPCODE(V128, I32,  ___,  ___,  0,  0xfd, 0x0f, I8X16Splat, "i8x16.splat", "")
+WABT_OPCODE(V128, I32,  ___,  ___,  0,  0xfd, 0x10, I16X8Splat, "i16x8.splat", "")
+WABT_OPCODE(V128, I32,  ___,  ___,  0,  0xfd, 0x11, I32X4Splat, "i32x4.splat", "")
+WABT_OPCODE(V128, I64,  ___,  ___,  0,  0xfd, 0x12, I64X2Splat, "i64x2.splat", "")
+WABT_OPCODE(V128, F32,  ___,  ___,  0,  0xfd, 0x13, F32X4Splat, "f32x4.splat", "")
+WABT_OPCODE(V128, F64,  ___,  ___,  0,  0xfd, 0x14, F64X2Splat, "f64x2.splat", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x15, I8X16ExtractLaneS, "i8x16.extract_lane_s", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x16, I8X16ExtractLaneU, "i8x16.extract_lane_u", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x17, I8X16ReplaceLane, "i8x16.replace_lane", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x18, I16X8ExtractLaneS, "i16x8.extract_lane_s", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x19, I16X8ExtractLaneU, "i16x8.extract_lane_u", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x1a, I16X8ReplaceLane, "i16x8.replace_lane", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x1b, I32X4ExtractLane, "i32x4.extract_lane", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x1c, I32X4ReplaceLane, "i32x4.replace_lane", "")
+WABT_OPCODE(I64,  V128, ___,  ___,  0,  0xfd, 0x1d, I64X2ExtractLane, "i64x2.extract_lane", "")
+WABT_OPCODE(V128, V128, I64,  ___,  0,  0xfd, 0x1e, I64X2ReplaceLane, "i64x2.replace_lane", "")
+WABT_OPCODE(F32,  V128, ___,  ___,  0,  0xfd, 0x1f, F32X4ExtractLane, "f32x4.extract_lane", "")
+WABT_OPCODE(V128, V128, F32,  ___,  0,  0xfd, 0x20, F32X4ReplaceLane, "f32x4.replace_lane", "")
+WABT_OPCODE(F64,  V128, ___,  ___,  0,  0xfd, 0x21, F64X2ExtractLane, "f64x2.extract_lane", "")
+WABT_OPCODE(V128, V128, F64,  ___,  0,  0xfd, 0x22, F64X2ReplaceLane, "f64x2.replace_lane", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x23, I8X16Eq, "i8x16.eq", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x24, I8X16Ne, "i8x16.ne", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x25, I8X16LtS, "i8x16.lt_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x26, I8X16LtU, "i8x16.lt_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x27, I8X16GtS, "i8x16.gt_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x28, I8X16GtU, "i8x16.gt_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x29, I8X16LeS, "i8x16.le_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x2a, I8X16LeU, "i8x16.le_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x2b, I8X16GeS, "i8x16.ge_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x2c, I8X16GeU, "i8x16.ge_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x2d, I16X8Eq, "i16x8.eq", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x2e, I16X8Ne, "i16x8.ne", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x2f, I16X8LtS, "i16x8.lt_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x30, I16X8LtU, "i16x8.lt_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x31, I16X8GtS, "i16x8.gt_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x32, I16X8GtU, "i16x8.gt_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x33, I16X8LeS, "i16x8.le_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x34, I16X8LeU, "i16x8.le_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x35, I16X8GeS, "i16x8.ge_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x36, I16X8GeU, "i16x8.ge_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x37, I32X4Eq, "i32x4.eq", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x38, I32X4Ne, "i32x4.ne", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x39, I32X4LtS, "i32x4.lt_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x3a, I32X4LtU, "i32x4.lt_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x3b, I32X4GtS, "i32x4.gt_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x3c, I32X4GtU, "i32x4.gt_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x3d, I32X4LeS, "i32x4.le_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x3e, I32X4LeU, "i32x4.le_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x3f, I32X4GeS, "i32x4.ge_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x40, I32X4GeU, "i32x4.ge_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x41, F32X4Eq, "f32x4.eq", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x42, F32X4Ne, "f32x4.ne", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x43, F32X4Lt, "f32x4.lt", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x44, F32X4Gt, "f32x4.gt", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x45, F32X4Le, "f32x4.le", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x46, F32X4Ge, "f32x4.ge", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x47, F64X2Eq, "f64x2.eq", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x48, F64X2Ne, "f64x2.ne", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x49, F64X2Lt, "f64x2.lt", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x4a, F64X2Gt, "f64x2.gt", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x4b, F64X2Le, "f64x2.le", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x4c, F64X2Ge, "f64x2.ge", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0x4d, V128Not, "v128.not", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x4e, V128And, "v128.and", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x4f, V128Andnot, "v128.andnot", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x50, V128Or,  "v128.or", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x51, V128Xor, "v128.xor", "")
+WABT_OPCODE(V128, V128, V128, V128, 0,  0xfd, 0x52, V128BitSelect, "v128.bitselect", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0x60, I8X16Abs, "i8x16.abs", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0x61, I8X16Neg, "i8x16.neg", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x62, I8X16AnyTrue, "i8x16.any_true", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x63, I8X16AllTrue, "i8x16.all_true", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x64, I8X16Bitmask, "i8x16.bitmask", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x65, I8X16NarrowI16X8S, "i8x16.narrow_i16x8_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x66, I8X16NarrowI16X8U, "i8x16.narrow_i16x8_u", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x6b, I8X16Shl, "i8x16.shl", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x6c, I8X16ShrS, "i8x16.shr_s", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x6d, I8X16ShrU, "i8x16.shr_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x6e, I8X16Add, "i8x16.add", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x6f, I8X16AddSatS, "i8x16.add_sat_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x70, I8X16AddSatU, "i8x16.add_sat_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x71, I8X16Sub, "i8x16.sub", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x72, I8X16SubSatS, "i8x16.sub_sat_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x73, I8X16SubSatU, "i8x16.sub_sat_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x76, I8X16MinS, "i8x16.min_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x77, I8X16MinU, "i8x16.min_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x78, I8X16MaxS, "i8x16.max_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x79, I8X16MaxU, "i8x16.max_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x7b, I8X16AvgrU, "i8x16.avgr_u", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0x80, I16X8Abs, "i16x8.abs", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0x81, I16X8Neg, "i16x8.neg", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x82, I16X8AnyTrue, "i16x8.any_true", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x83, I16X8AllTrue, "i16x8.all_true", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0x84, I16X8Bitmask, "i16x8.bitmask", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x85, I16X8NarrowI32X4S, "i16x8.narrow_i32x4_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x86, I16X8NarrowI32X4U, "i16x8.narrow_i32x4_u", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0x87, I16X8WidenLowI8X16S, "i16x8.widen_low_i8x16_s", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0x88, I16X8WidenHighI8X16S, "i16x8.widen_high_i8x16_s", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0x89, I16X8WidenLowI8X16U, "i16x8.widen_low_i8x16_u", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0x8a, I16X8WidenHighI8X16U, "i16x8.widen_high_i8x16_u", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x8b, I16X8Shl, "i16x8.shl", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x8c, I16X8ShrS, "i16x8.shr_s", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0x8d, I16X8ShrU, "i16x8.shr_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x8e, I16X8Add, "i16x8.add", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x8f, I16X8AddSatS, "i16x8.add_sat_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x90, I16X8AddSatU, "i16x8.add_sat_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x91, I16X8Sub, "i16x8.sub", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x92, I16X8SubSatS, "i16x8.sub_sat_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x93, I16X8SubSatU, "i16x8.sub_sat_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x95, I16X8Mul, "i16x8.mul", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x96, I16X8MinS, "i16x8.min_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x97, I16X8MinU, "i16x8.min_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x98, I16X8MaxS, "i16x8.max_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x99, I16X8MaxU, "i16x8.max_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0x9b, I16X8AvgrU, "i16x8.avgr_u", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0xa0, I32X4Abs, "i32x4.abs", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xa1, I32X4Neg, "i32x4.neg", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0xa2, I32X4AnyTrue, "i32x4.any_true", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0xa3, I32X4AllTrue, "i32x4.all_true", "")
+WABT_OPCODE(I32,  V128, ___,  ___,  0,  0xfd, 0xa4, I32X4Bitmask, "i32x4.bitmask", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0xa7, I32X4WidenLowI16X8S, "i32x4.widen_low_i16x8_s", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0xa8, I32X4WidenHighI16X8S, "i32x4.widen_high_i16x8_s", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0xa9, I32X4WidenLowI16X8U, "i32x4.widen_low_i16x8_u", "")
+WABT_OPCODE(V128, V128,  ___, ___,  0,  0xfd, 0xaa, I32X4WidenHighI16X8U, "i32x4.widen_high_i16x8_u", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0xab, I32X4Shl, "i32x4.shl", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0xac, I32X4ShrS, "i32x4.shr_s", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0xad, I32X4ShrU, "i32x4.shr_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xae, I32X4Add, "i32x4.add", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xb1, I32X4Sub, "i32x4.sub", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xb5, I32X4Mul, "i32x4.mul", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xb6, I32X4MinS, "i32x4.min_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xb7, I32X4MinU, "i32x4.min_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xb8, I32X4MaxS, "i32x4.max_s", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xb9, I32X4MaxU, "i32x4.max_u", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xc1, I64X2Neg, "i64x2.neg", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0xcb, I64X2Shl, "i64x2.shl", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0xcc, I64X2ShrS, "i64x2.shr_s", "")
+WABT_OPCODE(V128, V128, I32,  ___,  0,  0xfd, 0xcd, I64X2ShrU, "i64x2.shr_u", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xce, I64X2Add, "i64x2.add", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xd1, I64X2Sub, "i64x2.sub", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xd5, I64X2Mul, "i64x2.mul", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xd8, F32X4Ceil, "f32x4.ceil", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xd9, F32X4Floor, "f32x4.floor", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xda, F32X4Trunc, "f32x4.trunc", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xdb, F32X4Nearest, "f32x4.nearest", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xdc, F64X2Ceil, "f64x2.ceil", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xdd, F64X2Floor, "f64x2.floor", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xde, F64X2Trunc, "f64x2.trunc", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xdf, F64X2Nearest, "f64x2.nearest", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xe0, F32X4Abs, "f32x4.abs", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xe1, F32X4Neg, "f32x4.neg", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xe3, F32X4Sqrt, "f32x4.sqrt", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xe4, F32X4Add, "f32x4.add", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xe5, F32X4Sub, "f32x4.sub", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xe6, F32X4Mul, "f32x4.mul", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xe7, F32X4Div, "f32x4.div", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xe8, F32X4Min, "f32x4.min", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xe9, F32X4Max, "f32x4.max", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xea, F32X4PMin, "f32x4.pmin", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xeb, F32X4PMax, "f32x4.pmax", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xec, F64X2Abs, "f64x2.abs", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xed, F64X2Neg, "f64x2.neg", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xef, F64X2Sqrt, "f64x2.sqrt", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf0, F64X2Add, "f64x2.add", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf1, F64X2Sub, "f64x2.sub", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf2, F64X2Mul, "f64x2.mul", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf3, F64X2Div, "f64x2.div", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf4, F64X2Min, "f64x2.min", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf5, F64X2Max, "f64x2.max", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf6, F64X2PMin, "f64x2.pmin", "")
+WABT_OPCODE(V128, V128, V128, ___,  0,  0xfd, 0xf7, F64X2PMax, "f64x2.pmax", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xf8, I32X4TruncSatF32X4S,"i32x4.trunc_sat_f32x4_s", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xf9, I32X4TruncSatF32X4U,"i32x4.trunc_sat_f32x4_u", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xfa, F32X4ConvertI32X4S, "f32x4.convert_i32x4_s", "")
+WABT_OPCODE(V128, V128, ___,  ___,  0,  0xfd, 0xfb, F32X4ConvertI32X4U, "f32x4.convert_i32x4_u", "")
+
+/* Thread opcodes (--enable-threads) */
+WABT_OPCODE(I32,  I32,  I32,  ___,  4,  0xfe, 0x00, MemoryAtomicNotify, "memory.atomic.notify", "")
+WABT_OPCODE(I32,  I32,  I32,  I64,  4,  0xfe, 0x01, MemoryAtomicWait32, "memory.atomic.wait32", "")
+WABT_OPCODE(I32,  I32,  I64,  I64,  8,  0xfe, 0x02, MemoryAtomicWait64, "memory.atomic.wait64", "")
+WABT_OPCODE(___,  ___,  ___,  ___,  0,  0xfe, 0x03, AtomicFence, "atomic.fence", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  4,  0xfe, 0x10, I32AtomicLoad, "i32.atomic.load", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  8,  0xfe, 0x11, I64AtomicLoad, "i64.atomic.load", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  1,  0xfe, 0x12, I32AtomicLoad8U, "i32.atomic.load8_u", "")
+WABT_OPCODE(I32,  I32,  ___,  ___,  2,  0xfe, 0x13, I32AtomicLoad16U, "i32.atomic.load16_u", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  1,  0xfe, 0x14, I64AtomicLoad8U, "i64.atomic.load8_u", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  2,  0xfe, 0x15, I64AtomicLoad16U, "i64.atomic.load16_u", "")
+WABT_OPCODE(I64,  I32,  ___,  ___,  4,  0xfe, 0x16, I64AtomicLoad32U, "i64.atomic.load32_u", "")
+WABT_OPCODE(___,  I32,  I32,  ___,  4,  0xfe, 0x17, I32AtomicStore, "i32.atomic.store", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  8,  0xfe, 0x18, I64AtomicStore, "i64.atomic.store", "")
+WABT_OPCODE(___,  I32,  I32,  ___,  1,  0xfe, 0x19, I32AtomicStore8, "i32.atomic.store8", "")
+WABT_OPCODE(___,  I32,  I32,  ___,  2,  0xfe, 0x1a, I32AtomicStore16, "i32.atomic.store16", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  1,  0xfe, 0x1b, I64AtomicStore8, "i64.atomic.store8", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  2,  0xfe, 0x1c, I64AtomicStore16, "i64.atomic.store16", "")
+WABT_OPCODE(___,  I32,  I64,  ___,  4,  0xfe, 0x1d, I64AtomicStore32, "i64.atomic.store32", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  4,  0xfe, 0x1e, I32AtomicRmwAdd, "i32.atomic.rmw.add", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  8,  0xfe, 0x1f, I64AtomicRmwAdd, "i64.atomic.rmw.add", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  1,  0xfe, 0x20, I32AtomicRmw8AddU, "i32.atomic.rmw8.add_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  2,  0xfe, 0x21, I32AtomicRmw16AddU, "i32.atomic.rmw16.add_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  1,  0xfe, 0x22, I64AtomicRmw8AddU, "i64.atomic.rmw8.add_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  2,  0xfe, 0x23, I64AtomicRmw16AddU, "i64.atomic.rmw16.add_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  4,  0xfe, 0x24, I64AtomicRmw32AddU, "i64.atomic.rmw32.add_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  4,  0xfe, 0x25, I32AtomicRmwSub, "i32.atomic.rmw.sub", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  8,  0xfe, 0x26, I64AtomicRmwSub, "i64.atomic.rmw.sub", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  1,  0xfe, 0x27, I32AtomicRmw8SubU, "i32.atomic.rmw8.sub_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  2,  0xfe, 0x28, I32AtomicRmw16SubU, "i32.atomic.rmw16.sub_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  1,  0xfe, 0x29, I64AtomicRmw8SubU, "i64.atomic.rmw8.sub_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  2,  0xfe, 0x2a, I64AtomicRmw16SubU, "i64.atomic.rmw16.sub_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  4,  0xfe, 0x2b, I64AtomicRmw32SubU, "i64.atomic.rmw32.sub_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  4,  0xfe, 0x2c, I32AtomicRmwAnd, "i32.atomic.rmw.and", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  8,  0xfe, 0x2d, I64AtomicRmwAnd, "i64.atomic.rmw.and", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  1,  0xfe, 0x2e, I32AtomicRmw8AndU, "i32.atomic.rmw8.and_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  2,  0xfe, 0x2f, I32AtomicRmw16AndU, "i32.atomic.rmw16.and_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  1,  0xfe, 0x30, I64AtomicRmw8AndU, "i64.atomic.rmw8.and_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  2,  0xfe, 0x31, I64AtomicRmw16AndU, "i64.atomic.rmw16.and_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  4,  0xfe, 0x32, I64AtomicRmw32AndU, "i64.atomic.rmw32.and_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  4,  0xfe, 0x33, I32AtomicRmwOr, "i32.atomic.rmw.or", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  8,  0xfe, 0x34, I64AtomicRmwOr, "i64.atomic.rmw.or", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  1,  0xfe, 0x35, I32AtomicRmw8OrU, "i32.atomic.rmw8.or_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  2,  0xfe, 0x36, I32AtomicRmw16OrU, "i32.atomic.rmw16.or_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  1,  0xfe, 0x37, I64AtomicRmw8OrU, "i64.atomic.rmw8.or_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  2,  0xfe, 0x38, I64AtomicRmw16OrU, "i64.atomic.rmw16.or_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  4,  0xfe, 0x39, I64AtomicRmw32OrU, "i64.atomic.rmw32.or_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  4,  0xfe, 0x3a, I32AtomicRmwXor, "i32.atomic.rmw.xor", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  8,  0xfe, 0x3b, I64AtomicRmwXor, "i64.atomic.rmw.xor", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  1,  0xfe, 0x3c, I32AtomicRmw8XorU, "i32.atomic.rmw8.xor_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  2,  0xfe, 0x3d, I32AtomicRmw16XorU, "i32.atomic.rmw16.xor_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  1,  0xfe, 0x3e, I64AtomicRmw8XorU, "i64.atomic.rmw8.xor_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  2,  0xfe, 0x3f, I64AtomicRmw16XorU, "i64.atomic.rmw16.xor_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  4,  0xfe, 0x40, I64AtomicRmw32XorU, "i64.atomic.rmw32.xor_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  4,  0xfe, 0x41, I32AtomicRmwXchg, "i32.atomic.rmw.xchg", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  8,  0xfe, 0x42, I64AtomicRmwXchg, "i64.atomic.rmw.xchg", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  1,  0xfe, 0x43, I32AtomicRmw8XchgU, "i32.atomic.rmw8.xchg_u", "")
+WABT_OPCODE(I32,  I32,  I32,  ___,  2,  0xfe, 0x44, I32AtomicRmw16XchgU, "i32.atomic.rmw16.xchg_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  1,  0xfe, 0x45, I64AtomicRmw8XchgU, "i64.atomic.rmw8.xchg_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  2,  0xfe, 0x46, I64AtomicRmw16XchgU, "i64.atomic.rmw16.xchg_u", "")
+WABT_OPCODE(I64,  I32,  I64,  ___,  4,  0xfe, 0x47, I64AtomicRmw32XchgU, "i64.atomic.rmw32.xchg_u", "")
+WABT_OPCODE(I32,  I32,  I32,  I32,  4,  0xfe, 0x48, I32AtomicRmwCmpxchg, "i32.atomic.rmw.cmpxchg", "")
+WABT_OPCODE(I64,  I32,  I64,  I64,  8,  0xfe, 0x49, I64AtomicRmwCmpxchg, "i64.atomic.rmw.cmpxchg", "")
+WABT_OPCODE(I32,  I32,  I32,  I32,  1,  0xfe, 0x4a, I32AtomicRmw8CmpxchgU, "i32.atomic.rmw8.cmpxchg_u", "")
+WABT_OPCODE(I32,  I32,  I32,  I32,  2,  0xfe, 0x4b, I32AtomicRmw16CmpxchgU, "i32.atomic.rmw16.cmpxchg_u", "")
+WABT_OPCODE(I64,  I32,  I64,  I64,  1,  0xfe, 0x4c, I64AtomicRmw8CmpxchgU, "i64.atomic.rmw8.cmpxchg_u", "")
+WABT_OPCODE(I64,  I32,  I64,  I64,  2,  0xfe, 0x4d, I64AtomicRmw16CmpxchgU, "i64.atomic.rmw16.cmpxchg_u", "")
+WABT_OPCODE(I64,  I32,  I64,  I64,  4,  0xfe, 0x4e, I64AtomicRmw32CmpxchgU, "i64.atomic.rmw32.cmpxchg_u", "")
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/opcode.h
new file mode 100644 (file)
index 0000000..94cd4cb
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * 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_OPCODE_H_
+#define WABT_OPCODE_H_
+
+#include <vector>
+
+#include "src/common.h"
+#include "src/opcode-code-table.h"
+#include "src/leb128.h"
+
+namespace wabt {
+
+class Features;
+
+struct Opcode {
+  // Opcode enumerations.
+  //
+  // NOTE: this enum does not match the binary encoding.
+  //
+  enum Enum : uint32_t {
+#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
+                    text, decomp)                                             \
+  Name,
+#include "src/opcode.def"
+#undef WABT_OPCODE
+    Invalid,
+  };
+
+// Static opcode objects.
+#define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \
+                    text, decomp)                                             \
+  static Opcode Name##_Opcode;
+#include "src/opcode.def"
+#undef WABT_OPCODE
+
+  Opcode() = default;  // Provided so Opcode can be member of a union.
+  Opcode(Enum e) : enum_(e) {}
+  operator Enum() const { return enum_; }
+
+  static Opcode FromCode(uint32_t);
+  static Opcode FromCode(uint8_t prefix, uint32_t code);
+  bool HasPrefix() const { return GetInfo().prefix != 0; }
+  uint8_t GetPrefix() const { return GetInfo().prefix; }
+  uint32_t GetCode() const { return GetInfo().code; }
+  size_t GetLength() const { return GetBytes().size(); }
+  const char* GetName() const { return GetInfo().name; }
+  const char* GetDecomp() const {
+    return *GetInfo().decomp ? GetInfo().decomp : GetInfo().name;
+  }
+  Type GetResultType() const { return GetInfo().result_type; }
+  Type GetParamType1() const { return GetInfo().param_types[0]; }
+  Type GetParamType2() const { return GetInfo().param_types[1]; }
+  Type GetParamType3() const { return GetInfo().param_types[2]; }
+  Type GetParamType(int n) const { return GetInfo().param_types[n - 1]; }
+  Address GetMemorySize() const { return GetInfo().memory_size; }
+
+  // If this is a load/store op, the type depends on the memory used.
+  Type GetMemoryParam(Type param,
+                      const Limits* limits,
+                      bool has_address_operands) {
+    return limits && limits->is_64 && has_address_operands ? Type(Type::I64)
+                                                           : param;
+  }
+
+  // Get the byte sequence for this opcode, including prefix.
+  std::vector<uint8_t> GetBytes() const;
+
+  // Get the lane count of an extract/replace simd op.
+  uint32_t GetSimdLaneCount() const;
+
+  // Return 1 if |alignment| matches the alignment of |opcode|, or if
+  // |alignment| is WABT_USE_NATURAL_ALIGNMENT.
+  bool IsNaturallyAligned(Address alignment) const;
+
+  // If |alignment| is WABT_USE_NATURAL_ALIGNMENT, return the alignment of
+  // |opcode|, else return |alignment|.
+  Address GetAlignment(Address alignment) const;
+
+  static bool IsPrefixByte(uint8_t byte) {
+    return byte == kMathPrefix || byte == kThreadsPrefix || byte == kSimdPrefix;
+  }
+
+  bool IsEnabled(const Features& features) const;
+  bool IsInvalid() const { return enum_ >= Invalid; }
+
+ private:
+  static const uint32_t kMathPrefix = 0xfc;
+  static const uint32_t kThreadsPrefix = 0xfe;
+  static const uint32_t kSimdPrefix = 0xfd;
+
+  struct Info {
+    const char* name;
+    const char* decomp;
+    Type result_type;
+    Type param_types[3];
+    Address memory_size;
+    uint8_t prefix;
+    uint32_t code;
+    uint32_t prefix_code;  // See PrefixCode below. Used for fast lookup.
+  };
+
+  static uint32_t PrefixCode(uint8_t prefix, uint32_t code) {
+    // For now, 8 bits is enough for all codes.
+    if (code >= 0x100) {
+      // Clamp to 0xff, since we know that it is an invalid code.
+      code = 0xff;
+    }
+    return (prefix << 8) | code;
+  }
+
+  // The Opcode struct only stores an enumeration (Opcode::Enum) of all valid
+  // opcodes, densely packed. We want to be able to store invalid opcodes as
+  // well, for display to the user. To encode these, we use PrefixCode() to
+  // generate a uint32_t of the prefix/code pair, then negate the value so it
+  // doesn't overlap with the valid enum values. The negation is done using
+  // `~code + 1` since prefix_code is unsigned, and MSVC warns if you use - on
+  // an unsigned value.
+  //
+  // | 0             | Opcode::Invalid         | INT32_MAX+1    UINT32_MAX |
+  // |---------------|-------------------------|---------------------------|
+  // | valid opcodes |      unused space       |      invalid opcodes      |
+  //
+  static Enum EncodeInvalidOpcode(uint32_t prefix_code) {
+    Enum result = static_cast<Enum>(~prefix_code + 1);
+    assert(result >= Invalid);
+    return result;
+  }
+
+  static void DecodeInvalidOpcode(Enum e,
+                                  uint8_t* out_prefix,
+                                  uint32_t* out_code) {
+    uint32_t prefix_code = ~static_cast<uint32_t>(e) + 1;
+    *out_prefix = prefix_code >> 8;
+    *out_code = prefix_code & 0xff;
+  }
+
+  Info GetInfo() const;
+  static Info infos_[];
+
+  Enum enum_;
+};
+
+// static
+inline Opcode Opcode::FromCode(uint32_t code) {
+  return FromCode(0, code);
+}
+
+// static
+inline Opcode Opcode::FromCode(uint8_t prefix, uint32_t code) {
+  uint32_t prefix_code = PrefixCode(prefix, code);
+
+  if (WABT_LIKELY(prefix_code < WABT_ARRAY_SIZE(WabtOpcodeCodeTable))) {
+    uint32_t value = WabtOpcodeCodeTable[prefix_code];
+    // The default value in the table is 0. That's a valid value, but only if
+    // the code is 0 (for nop).
+    if (WABT_LIKELY(value != 0 || code == 0)) {
+      return Opcode(static_cast<Enum>(value));
+    }
+  }
+
+  return Opcode(EncodeInvalidOpcode(prefix_code));
+}
+
+
+}  // namespace wabt
+
+#endif  // WABT_OPCODE_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.cc
new file mode 100644 (file)
index 0000000..d6a38ae
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * 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/option-parser.h"
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstring>
+
+#include "config.h"
+
+#if HAVE_ALLOCA
+#include <alloca.h>
+#endif
+
+namespace wabt {
+
+OptionParser::Option::Option(char short_name,
+                             const std::string& long_name,
+                             const std::string& metavar,
+                             HasArgument has_argument,
+                             const std::string& help,
+                             const Callback& callback)
+    : short_name(short_name),
+      long_name(long_name),
+      metavar(metavar),
+      has_argument(has_argument == HasArgument::Yes),
+      help(help),
+      callback(callback) {}
+
+OptionParser::Argument::Argument(const std::string& name,
+                                 ArgumentCount count,
+                                 const Callback& callback)
+    : name(name), count(count), callback(callback) {}
+
+OptionParser::OptionParser(const char* program_name, const char* description)
+    : program_name_(program_name),
+      description_(description),
+      on_error_([this](const std::string& message) { DefaultError(message); }) {
+
+  // Add common options
+  AddOption("help", "Print this help message", [this]() {
+    PrintHelp();
+    exit(0);
+  });
+  AddOption("version", "Print version information", []() {
+    printf("%s\n", CMAKE_PROJECT_VERSION);
+    exit(0);
+  });
+}
+
+void OptionParser::AddOption(const Option& option) {
+  options_.emplace_back(option);
+}
+
+void OptionParser::AddArgument(const std::string& name,
+                               ArgumentCount count,
+                               const Callback& callback) {
+  arguments_.emplace_back(name, count, callback);
+}
+
+void OptionParser::AddOption(char short_name,
+                             const char* long_name,
+                             const char* help,
+                             const NullCallback& callback) {
+  Option option(short_name, long_name, std::string(), HasArgument::No, help,
+                [callback](const char*) { callback(); });
+  AddOption(option);
+}
+
+void OptionParser::AddOption(const char* long_name,
+                             const char* help,
+                             const NullCallback& callback) {
+  Option option('\0', long_name, std::string(), HasArgument::No, help,
+                [callback](const char*) { callback(); });
+  AddOption(option);
+}
+
+void OptionParser::AddOption(char short_name,
+                             const char* long_name,
+                             const char* metavar,
+                             const char* help,
+                             const Callback& callback) {
+  Option option(short_name, long_name, metavar, HasArgument::Yes, help,
+                callback);
+  AddOption(option);
+}
+
+void OptionParser::SetErrorCallback(const Callback& callback) {
+  on_error_ = callback;
+}
+
+// static
+int OptionParser::Match(const char* s,
+                        const std::string& full,
+                        bool has_argument) {
+  int i;
+  for (i = 0;; i++) {
+    if (full[i] == '\0') {
+      // Perfect match. Return +1, so it will be preferred over a longer option
+      // with the same prefix.
+      if (s[i] == '\0') {
+        return i + 1;
+      }
+
+      // We want to fail if s is longer than full, e.g. --foobar vs. --foo.
+      // However, if s ends with an '=', it's OK.
+      if (!(has_argument && s[i] == '=')) {
+        return -1;
+      }
+      break;
+    }
+    if (s[i] == '\0') {
+      break;
+    }
+    if (s[i] != full[i]) {
+      return -1;
+    }
+  }
+  return i;
+}
+
+void OptionParser::Errorf(const char* format, ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  std::string msg(program_name_);
+  msg += ": ";
+  msg += buffer;
+  msg += "\nTry '--help' for more information.";
+  on_error_(msg.c_str());
+}
+
+void OptionParser::DefaultError(const std::string& message) {
+  WABT_FATAL("%s\n", message.c_str());
+}
+
+void OptionParser::HandleArgument(size_t* arg_index, const char* arg_value) {
+  if (*arg_index >= arguments_.size()) {
+    Errorf("unexpected argument '%s'", arg_value);
+    return;
+  }
+  Argument& argument = arguments_[*arg_index];
+  argument.callback(arg_value);
+  argument.handled_count++;
+
+  if (argument.count == ArgumentCount::One) {
+    (*arg_index)++;
+  }
+}
+
+void OptionParser::Parse(int argc, char* argv[]) {
+  size_t arg_index = 0;
+  bool processing_options = true;
+
+  for (int i = 1; i < argc; ++i) {
+    const char* arg = argv[i];
+    if (!processing_options || arg[0] != '-') {
+      // Non-option argument.
+      HandleArgument(&arg_index, arg);
+      continue;
+    }
+
+    if (arg[1] == '-') {
+      if (arg[2] == '\0') {
+        // -- on its own means stop processing args, everything should
+        // be treated as positional.
+        processing_options = false;
+        continue;
+      }
+      // Long option.
+      int best_index = -1;
+      int best_length = 0;
+      int best_count = 0;
+      for (size_t j = 0; j < options_.size(); ++j) {
+        const Option& option = options_[j];
+        if (!option.long_name.empty()) {
+          int match_length =
+              Match(&arg[2], option.long_name, option.has_argument);
+          if (match_length > best_length) {
+            best_index = j;
+            best_length = match_length;
+            best_count = 1;
+          } else if (match_length == best_length && best_length > 0) {
+            best_count++;
+          }
+        }
+      }
+
+      if (best_count > 1) {
+        Errorf("ambiguous option '%s'", arg);
+        continue;
+      } else if (best_count == 0) {
+        Errorf("unknown option '%s'", arg);
+        continue;
+      }
+
+      const Option& best_option = options_[best_index];
+      const char* option_argument = nullptr;
+      if (best_option.has_argument) {
+        if (arg[best_length + 1] != 0 &&    // This byte is 0 on a full match.
+            arg[best_length + 2] == '=') {  // +2 to skip "--".
+          option_argument = &arg[best_length + 3];
+        } else {
+          if (i + 1 == argc || argv[i + 1][0] == '-') {
+            Errorf("option '--%s' requires argument",
+                   best_option.long_name.c_str());
+            continue;
+          }
+          ++i;
+          option_argument = argv[i];
+        }
+      }
+      best_option.callback(option_argument);
+    } else {
+      // Short option.
+      if (arg[1] == '\0') {
+        // Just "-".
+        HandleArgument(&arg_index, arg);
+        continue;
+      }
+
+      // Allow short names to be combined, e.g. "-d -v" => "-dv".
+      for (int k = 1; arg[k]; ++k) {
+        bool matched = false;
+        for (const Option& option : options_) {
+          if (option.short_name && arg[k] == option.short_name) {
+            const char* option_argument = nullptr;
+            if (option.has_argument) {
+              // A short option with a required argument cannot be followed
+              // by other short options_.
+              if (arg[k + 1] != '\0') {
+                Errorf("option '-%c' requires argument", option.short_name);
+                break;
+              }
+
+              if (i + 1 == argc || argv[i + 1][0] == '-') {
+                Errorf("option '-%c' requires argument", option.short_name);
+                break;
+              }
+              ++i;
+              option_argument = argv[i];
+            }
+            option.callback(option_argument);
+            matched = true;
+            break;
+          }
+        }
+
+        if (!matched) {
+          Errorf("unknown option '-%c'", arg[k]);
+          continue;
+        }
+      }
+    }
+  }
+
+  // For now, all arguments must be provided. Check that the last Argument was
+  // handled at least once.
+  if (!arguments_.empty() && arguments_.back().handled_count == 0) {
+    for (size_t i = arg_index; i < arguments_.size(); ++i) {
+      if (arguments_[i].count != ArgumentCount::ZeroOrMore) {
+        Errorf("expected %s argument.", arguments_[i].name.c_str());
+      }
+    }
+  }
+}
+
+void OptionParser::PrintHelp() {
+  printf("usage: %s [options]", program_name_.c_str());
+
+  for (size_t i = 0; i < arguments_.size(); ++i) {
+    Argument& argument = arguments_[i];
+    switch (argument.count) {
+      case ArgumentCount::One:
+        printf(" %s", argument.name.c_str());
+        break;
+
+      case ArgumentCount::OneOrMore:
+        printf(" %s+", argument.name.c_str());
+        break;
+
+      case ArgumentCount::ZeroOrMore:
+        printf(" [%s]...", argument.name.c_str());
+        break;
+    }
+  }
+
+  printf("\n\n");
+  printf("%s\n", description_.c_str());
+  printf("options:\n");
+
+  const size_t kExtraSpace = 8;
+  size_t longest_name_length = 0;
+  for (const Option& option : options_) {
+    size_t length;
+    if (!option.long_name.empty()) {
+      length = option.long_name.size();
+      if (!option.metavar.empty()) {
+        // +1 for '='.
+        length += option.metavar.size() + 1;
+      }
+    } else {
+      continue;
+    }
+
+    if (length > longest_name_length) {
+      longest_name_length = length;
+    }
+  }
+
+  for (const Option& option : options_) {
+    if (!option.short_name && option.long_name.empty()) {
+      continue;
+    }
+
+    std::string line;
+    if (option.short_name) {
+      line += std::string("  -") + option.short_name + ", ";
+    } else {
+      line += "      ";
+    }
+
+    std::string flag;
+    if (!option.long_name.empty()) {
+      flag = "--";
+      if (!option.metavar.empty()) {
+        flag += option.long_name + '=' + option.metavar;
+      } else {
+        flag += option.long_name;
+      }
+    }
+
+    // +2 for "--" of the long flag name.
+    size_t remaining = longest_name_length + kExtraSpace + 2 - flag.size();
+    line += flag + std::string(remaining, ' ');
+
+    if (!option.help.empty()) {
+      line += option.help;
+    }
+    printf("%s\n", line.c_str());
+  }
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/option-parser.h
new file mode 100644 (file)
index 0000000..051ce78
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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_OPTION_PARSER_H_
+#define WABT_OPTION_PARSER_H_
+
+#include <functional>
+#include <string>
+#include <vector>
+
+#include "src/common.h"
+
+namespace wabt {
+
+class OptionParser {
+ public:
+  enum class HasArgument { No, Yes };
+  enum class ArgumentCount { One, OneOrMore, ZeroOrMore };
+
+  struct Option;
+  typedef std::function<void(const char*)> Callback;
+  typedef std::function<void()> NullCallback;
+
+  struct Option {
+    Option(char short_name,
+           const std::string& long_name,
+           const std::string& metavar,
+           HasArgument has_argument,
+           const std::string& help,
+           const Callback&);
+
+    char short_name;
+    std::string long_name;
+    std::string metavar;
+    bool has_argument;
+    std::string help;
+    Callback callback;
+  };
+
+  struct Argument {
+    Argument(const std::string& name, ArgumentCount, const Callback&);
+
+    std::string name;
+    ArgumentCount count;
+    Callback callback;
+    int handled_count = 0;
+  };
+
+  explicit OptionParser(const char* program_name, const char* description);
+
+  void AddOption(const Option&);
+  void AddArgument(const std::string& name, ArgumentCount, const Callback&);
+  void SetErrorCallback(const Callback&);
+  void Parse(int argc, char* argv[]);
+  void PrintHelp();
+
+  // Helper functions.
+  void AddOption(char short_name,
+                 const char* long_name,
+                 const char* help,
+                 const NullCallback&);
+  void AddOption(const char* long_name, const char* help, const NullCallback&);
+  void AddOption(char short_name,
+                 const char* long_name,
+                 const char* metavar,
+                 const char* help,
+                 const Callback&);
+
+ private:
+  static int Match(const char* s, const std::string& full, bool has_argument);
+  void WABT_PRINTF_FORMAT(2, 3) Errorf(const char* format, ...);
+  void HandleArgument(size_t* arg_index, const char* arg_value);
+
+  // Print the error and exit(1).
+  void DefaultError(const std::string&);
+
+  std::string program_name_;
+  std::string description_;
+  std::vector<Option> options_;
+  std::vector<Argument> arguments_;
+  Callback on_error_;
+};
+
+}  // namespace wabt
+
+#endif /* WABT_OPTION_PARSER_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/lexer-keywords.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/lexer-keywords.cc
new file mode 100644 (file)
index 0000000..8fa70e2
--- /dev/null
@@ -0,0 +1,1745 @@
+/* C++ code produced by gperf version 3.1 */
+/* Command-line: gperf -m 50 -L C++ -N InWordSet -E -t -c --output-file=src/prebuilt/lexer-keywords.cc src/lexer-keywords.txt  */
+/* Computed positions: -k'1,3,5-9,11-14,16-19,$' */
+
+#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
+      && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \
+      && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \
+      && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \
+      && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \
+      && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \
+      && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \
+      && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \
+      && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \
+      && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \
+      && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \
+      && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \
+      && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \
+      && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \
+      && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \
+      && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \
+      && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \
+      && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \
+      && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \
+      && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \
+      && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \
+      && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \
+      && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126))
+/* The character set is not based on ISO-646.  */
+#error "gperf generated tables don't work with this execution character set. Please report a bug to <bug-gperf@gnu.org>."
+#endif
+
+#line 1 "src/lexer-keywords.txt"
+struct TokenInfo {
+  TokenInfo(const char* name) : name(name) {}
+  TokenInfo(const char* name, TokenType token_type)
+      : name(name), token_type(token_type) {}
+  TokenInfo(const char* name, Type value_type)
+      : name(name), token_type(TokenType::ValueType), value_type(value_type) {}
+  TokenInfo(const char* name, Type value_type, TokenType token_type)
+      : name(name), token_type(token_type), value_type(value_type) {}
+  TokenInfo(const char* name, TokenType token_type, Opcode opcode)
+      : name(name), token_type(token_type), opcode(opcode) {}
+
+  const char* name;
+  TokenType token_type;
+  union {
+    Type value_type;
+    Opcode opcode;
+  };
+};
+/* maximum key range = 2532, duplicates = 0 */
+
+class Perfect_Hash
+{
+private:
+  static inline unsigned int hash (const char *str, size_t len);
+public:
+  static struct TokenInfo *InWordSet (const char *str, size_t len);
+};
+
+inline unsigned int
+Perfect_Hash::hash (const char *str, size_t len)
+{
+  static unsigned short asso_values[] =
+    {
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549,   12,  216, 2549,   20,
+         7,   28,    6,  214,  124,  365,  259,  677,   19, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549,    7,   12,  111,   36,  111,
+         9,    6,    6,  594,  573,    9,   13,   15,   71,  111,
+        31,    8,  405,  495,    7,    9,    9,   25,  113,  126,
+       314,  430,   60, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549, 2549,
+      2549, 2549, 2549, 2549, 2549, 2549, 2549
+    };
+  unsigned int hval = len;
+
+  switch (hval)
+    {
+      default:
+        hval += asso_values[static_cast<unsigned char>(str[18])];
+      /*FALLTHROUGH*/
+      case 18:
+        hval += asso_values[static_cast<unsigned char>(str[17])];
+      /*FALLTHROUGH*/
+      case 17:
+        hval += asso_values[static_cast<unsigned char>(str[16]+1)];
+      /*FALLTHROUGH*/
+      case 16:
+        hval += asso_values[static_cast<unsigned char>(str[15])];
+      /*FALLTHROUGH*/
+      case 15:
+      case 14:
+        hval += asso_values[static_cast<unsigned char>(str[13])];
+      /*FALLTHROUGH*/
+      case 13:
+        hval += asso_values[static_cast<unsigned char>(str[12])];
+      /*FALLTHROUGH*/
+      case 12:
+        hval += asso_values[static_cast<unsigned char>(str[11])];
+      /*FALLTHROUGH*/
+      case 11:
+        hval += asso_values[static_cast<unsigned char>(str[10])];
+      /*FALLTHROUGH*/
+      case 10:
+      case 9:
+        hval += asso_values[static_cast<unsigned char>(str[8])];
+      /*FALLTHROUGH*/
+      case 8:
+        hval += asso_values[static_cast<unsigned char>(str[7])];
+      /*FALLTHROUGH*/
+      case 7:
+        hval += asso_values[static_cast<unsigned char>(str[6])];
+      /*FALLTHROUGH*/
+      case 6:
+        hval += asso_values[static_cast<unsigned char>(str[5])];
+      /*FALLTHROUGH*/
+      case 5:
+        hval += asso_values[static_cast<unsigned char>(str[4]+1)];
+      /*FALLTHROUGH*/
+      case 4:
+      case 3:
+        hval += asso_values[static_cast<unsigned char>(str[2])];
+      /*FALLTHROUGH*/
+      case 2:
+      case 1:
+        hval += asso_values[static_cast<unsigned char>(str[0])];
+        break;
+    }
+  return hval + asso_values[static_cast<unsigned char>(str[len - 1])];
+}
+
+struct TokenInfo *
+Perfect_Hash::InWordSet (const char *str, size_t len)
+{
+  enum
+    {
+      TOTAL_KEYWORDS = 565,
+      MIN_WORD_LENGTH = 2,
+      MAX_WORD_LENGTH = 26,
+      MIN_HASH_VALUE = 17,
+      MAX_HASH_VALUE = 2548
+    };
+
+  static struct TokenInfo wordlist[] =
+    {
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 471 "src/lexer-keywords.txt"
+      {"if", TokenType::If, Opcode::If},
+      {""},
+#line 42 "src/lexer-keywords.txt"
+      {"do", TokenType::Do},
+      {""},
+#line 138 "src/lexer-keywords.txt"
+      {"f64", Type::F64},
+      {""},
+#line 81 "src/lexer-keywords.txt"
+      {"f32", Type::F32},
+#line 420 "src/lexer-keywords.txt"
+      {"i64", Type::I64},
+#line 46 "src/lexer-keywords.txt"
+      {"else", TokenType::Else, Opcode::Else},
+#line 290 "src/lexer-keywords.txt"
+      {"i32", Type::I32},
+#line 47 "src/lexer-keywords.txt"
+      {"end", TokenType::End, Opcode::End},
+      {""}, {""}, {""}, {""},
+#line 164 "src/lexer-keywords.txt"
+      {"field", TokenType::Field},
+      {""}, {""}, {""}, {""}, {""},
+#line 131 "src/lexer-keywords.txt"
+      {"f64.ne", TokenType::Compare, Opcode::F64Ne},
+#line 75 "src/lexer-keywords.txt"
+      {"f32.ne", TokenType::Compare, Opcode::F32Ne},
+      {""},
+#line 396 "src/lexer-keywords.txt"
+      {"i64.ne", TokenType::Compare, Opcode::I64Ne},
+#line 267 "src/lexer-keywords.txt"
+      {"i32.ne", TokenType::Compare, Opcode::I32Ne},
+      {""},
+#line 495 "src/lexer-keywords.txt"
+      {"offset", TokenType::Offset},
+#line 32 "src/lexer-keywords.txt"
+      {"br", TokenType::Br, Opcode::Br},
+      {""}, {""}, {""},
+#line 512 "src/lexer-keywords.txt"
+      {"struct", Type::Struct, TokenType::Struct},
+#line 521 "src/lexer-keywords.txt"
+      {"then", TokenType::Then},
+#line 48 "src/lexer-keywords.txt"
+      {"event", TokenType::Event},
+#line 163 "src/lexer-keywords.txt"
+      {"f64x2", TokenType::F64X2},
+      {""}, {""},
+#line 433 "src/lexer-keywords.txt"
+      {"i64x2", TokenType::I64X2},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 520 "src/lexer-keywords.txt"
+      {"table", TokenType::Table},
+#line 403 "src/lexer-keywords.txt"
+      {"i64.rotr", TokenType::Binary, Opcode::I64Rotr},
+#line 274 "src/lexer-keywords.txt"
+      {"i32.rotr", TokenType::Binary, Opcode::I32Rotr},
+      {""},
+#line 135 "src/lexer-keywords.txt"
+      {"f64.store", TokenType::Store, Opcode::F64Store},
+#line 78 "src/lexer-keywords.txt"
+      {"f32.store", TokenType::Store, Opcode::F32Store},
+      {""},
+#line 410 "src/lexer-keywords.txt"
+      {"i64.store", TokenType::Store, Opcode::I64Store},
+#line 280 "src/lexer-keywords.txt"
+      {"i32.store", TokenType::Store, Opcode::I32Store},
+#line 165 "src/lexer-keywords.txt"
+      {"funcref", Type::FuncRef},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 408 "src/lexer-keywords.txt"
+      {"i64.store32", TokenType::Store, Opcode::I64Store32},
+      {""}, {""},
+#line 110 "src/lexer-keywords.txt"
+      {"f64.add", TokenType::Binary, Opcode::F64Add},
+#line 53 "src/lexer-keywords.txt"
+      {"f32.add", TokenType::Binary, Opcode::F32Add},
+      {""},
+#line 330 "src/lexer-keywords.txt"
+      {"i64.add", TokenType::Binary, Opcode::I64Add},
+#line 215 "src/lexer-keywords.txt"
+      {"i32.add", TokenType::Binary, Opcode::I32Add},
+      {""}, {""},
+#line 50 "src/lexer-keywords.txt"
+      {"externref", Type::ExternRef},
+      {""}, {""},
+#line 49 "src/lexer-keywords.txt"
+      {"extern", Type::ExternRef, TokenType::Extern},
+#line 508 "src/lexer-keywords.txt"
+      {"return", TokenType::Return, Opcode::Return},
+      {""}, {""},
+#line 112 "src/lexer-keywords.txt"
+      {"f64.const", TokenType::Const, Opcode::F64Const},
+#line 55 "src/lexer-keywords.txt"
+      {"f32.const", TokenType::Const, Opcode::F32Const},
+      {""},
+#line 369 "src/lexer-keywords.txt"
+      {"i64.const", TokenType::Const, Opcode::I64Const},
+#line 245 "src/lexer-keywords.txt"
+      {"i32.const", TokenType::Const, Opcode::I32Const},
+      {""}, {""},
+#line 155 "src/lexer-keywords.txt"
+      {"f64x2.ne", TokenType::Compare, Opcode::F64X2Ne},
+      {""},
+#line 518 "src/lexer-keywords.txt"
+      {"table.set", TokenType::TableSet, Opcode::TableSet},
+      {""},
+#line 331 "src/lexer-keywords.txt"
+      {"i64.and", TokenType::Binary, Opcode::I64And},
+#line 216 "src/lexer-keywords.txt"
+      {"i32.and", TokenType::Binary, Opcode::I32And},
+#line 109 "src/lexer-keywords.txt"
+      {"f64.abs", TokenType::Unary, Opcode::F64Abs},
+#line 52 "src/lexer-keywords.txt"
+      {"f32.abs", TokenType::Unary, Opcode::F32Abs},
+      {""}, {""},
+#line 509 "src/lexer-keywords.txt"
+      {"select", TokenType::Select, Opcode::Select},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 127 "src/lexer-keywords.txt"
+      {"f64.min", TokenType::Binary, Opcode::F64Min},
+#line 71 "src/lexer-keywords.txt"
+      {"f32.min", TokenType::Binary, Opcode::F32Min},
+      {""}, {""},
+#line 136 "src/lexer-keywords.txt"
+      {"f64.sub", TokenType::Binary, Opcode::F64Sub},
+#line 79 "src/lexer-keywords.txt"
+      {"f32.sub", TokenType::Binary, Opcode::F32Sub},
+#line 45 "src/lexer-keywords.txt"
+      {"elem", TokenType::Elem},
+#line 411 "src/lexer-keywords.txt"
+      {"i64.sub", TokenType::Binary, Opcode::I64Sub},
+#line 281 "src/lexer-keywords.txt"
+      {"i32.sub", TokenType::Binary, Opcode::I32Sub},
+#line 475 "src/lexer-keywords.txt"
+      {"item", TokenType::Item},
+#line 517 "src/lexer-keywords.txt"
+      {"table.init", TokenType::TableInit, Opcode::TableInit},
+#line 491 "src/lexer-keywords.txt"
+      {"mut", TokenType::Mut},
+#line 39 "src/lexer-keywords.txt"
+      {"data", TokenType::Data},
+      {""},
+#line 29 "src/lexer-keywords.txt"
+      {"block", TokenType::Block, Opcode::Block},
+      {""}, {""}, {""}, {""}, {""},
+#line 123 "src/lexer-keywords.txt"
+      {"f64.le", TokenType::Compare, Opcode::F64Le},
+#line 67 "src/lexer-keywords.txt"
+      {"f32.le", TokenType::Compare, Opcode::F32Le},
+#line 148 "src/lexer-keywords.txt"
+      {"f64x2.le", TokenType::Compare, Opcode::F64X2Le},
+      {""}, {""}, {""},
+#line 125 "src/lexer-keywords.txt"
+      {"f64.lt", TokenType::Compare, Opcode::F64Lt},
+#line 69 "src/lexer-keywords.txt"
+      {"f32.lt", TokenType::Compare, Opcode::F32Lt},
+#line 149 "src/lexer-keywords.txt"
+      {"f64x2.lt", TokenType::Compare, Opcode::F64X2Lt},
+#line 510 "src/lexer-keywords.txt"
+      {"shared", TokenType::Shared},
+#line 504 "src/lexer-keywords.txt"
+      {"result", TokenType::Result},
+#line 166 "src/lexer-keywords.txt"
+      {"func", Type::FuncRef, TokenType::Func},
+      {""},
+#line 496 "src/lexer-keywords.txt"
+      {"output", TokenType::Output},
+      {""}, {""},
+#line 519 "src/lexer-keywords.txt"
+      {"table.size", TokenType::TableSize, Opcode::TableSize},
+      {""},
+#line 511 "src/lexer-keywords.txt"
+      {"start", TokenType::Start},
+#line 370 "src/lexer-keywords.txt"
+      {"i64.ctz", TokenType::Unary, Opcode::I64Ctz},
+#line 246 "src/lexer-keywords.txt"
+      {"i32.ctz", TokenType::Unary, Opcode::I32Ctz},
+#line 145 "src/lexer-keywords.txt"
+      {"f64x2.floor", TokenType::Unary, Opcode::F64X2Floor},
+      {""}, {""},
+#line 384 "src/lexer-keywords.txt"
+      {"i64.le_s", TokenType::Compare, Opcode::I64LeS},
+#line 257 "src/lexer-keywords.txt"
+      {"i32.le_s", TokenType::Compare, Opcode::I32LeS},
+#line 161 "src/lexer-keywords.txt"
+      {"f64x2.sub", TokenType::Binary, Opcode::F64X2Sub},
+#line 393 "src/lexer-keywords.txt"
+      {"i64.lt_s", TokenType::Compare, Opcode::I64LtS},
+#line 264 "src/lexer-keywords.txt"
+      {"i32.lt_s", TokenType::Compare, Opcode::I32LtS},
+#line 432 "src/lexer-keywords.txt"
+      {"i64x2.sub", TokenType::Binary, Opcode::I64X2Sub},
+      {""}, {""}, {""}, {""},
+#line 400 "src/lexer-keywords.txt"
+      {"i64.rem_s", TokenType::Binary, Opcode::I64RemS},
+#line 271 "src/lexer-keywords.txt"
+      {"i32.rem_s", TokenType::Binary, Opcode::I32RemS},
+#line 371 "src/lexer-keywords.txt"
+      {"i64.div_s", TokenType::Binary, Opcode::I64DivS},
+#line 247 "src/lexer-keywords.txt"
+      {"i32.div_s", TokenType::Binary, Opcode::I32DivS},
+#line 129 "src/lexer-keywords.txt"
+      {"f64.nearest", TokenType::Unary, Opcode::F64Nearest},
+#line 73 "src/lexer-keywords.txt"
+      {"f32.nearest", TokenType::Unary, Opcode::F32Nearest},
+      {""},
+#line 40 "src/lexer-keywords.txt"
+      {"declare", TokenType::Declare},
+#line 585 "src/lexer-keywords.txt"
+      {"unwind", TokenType::Unwind, Opcode::Unwind},
+      {""}, {""},
+#line 111 "src/lexer-keywords.txt"
+      {"f64.ceil", TokenType::Unary, Opcode::F64Ceil},
+#line 54 "src/lexer-keywords.txt"
+      {"f32.ceil", TokenType::Unary, Opcode::F32Ceil},
+      {""}, {""}, {""},
+#line 402 "src/lexer-keywords.txt"
+      {"i64.rotl", TokenType::Binary, Opcode::I64Rotl},
+#line 273 "src/lexer-keywords.txt"
+      {"i32.rotl", TokenType::Binary, Opcode::I32Rotl},
+      {""}, {""}, {""}, {""},
+#line 385 "src/lexer-keywords.txt"
+      {"i64.le_u", TokenType::Compare, Opcode::I64LeU},
+#line 258 "src/lexer-keywords.txt"
+      {"i32.le_u", TokenType::Compare, Opcode::I32LeU},
+#line 140 "src/lexer-keywords.txt"
+      {"f64x2.add", TokenType::Binary, Opcode::F64X2Add},
+#line 394 "src/lexer-keywords.txt"
+      {"i64.lt_u", TokenType::Compare, Opcode::I64LtU},
+#line 265 "src/lexer-keywords.txt"
+      {"i32.lt_u", TokenType::Compare, Opcode::I32LtU},
+#line 421 "src/lexer-keywords.txt"
+      {"i64x2.add", TokenType::Binary, Opcode::I64X2Add},
+      {""}, {""}, {""},
+#line 31 "src/lexer-keywords.txt"
+      {"br_table", TokenType::BrTable, Opcode::BrTable},
+#line 401 "src/lexer-keywords.txt"
+      {"i64.rem_u", TokenType::Binary, Opcode::I64RemU},
+#line 272 "src/lexer-keywords.txt"
+      {"i32.rem_u", TokenType::Binary, Opcode::I32RemU},
+#line 372 "src/lexer-keywords.txt"
+      {"i64.div_u", TokenType::Binary, Opcode::I64DivU},
+#line 248 "src/lexer-keywords.txt"
+      {"i32.div_u", TokenType::Binary, Opcode::I32DivU},
+#line 474 "src/lexer-keywords.txt"
+      {"invoke", TokenType::Invoke},
+      {""}, {""}, {""}, {""}, {""},
+#line 128 "src/lexer-keywords.txt"
+      {"f64.mul", TokenType::Binary, Opcode::F64Mul},
+#line 72 "src/lexer-keywords.txt"
+      {"f32.mul", TokenType::Binary, Opcode::F32Mul},
+      {""},
+#line 395 "src/lexer-keywords.txt"
+      {"i64.mul", TokenType::Binary, Opcode::I64Mul},
+#line 266 "src/lexer-keywords.txt"
+      {"i32.mul", TokenType::Binary, Opcode::I32Mul},
+#line 368 "src/lexer-keywords.txt"
+      {"i64.clz", TokenType::Unary, Opcode::I64Clz},
+#line 244 "src/lexer-keywords.txt"
+      {"i32.clz", TokenType::Unary, Opcode::I32Clz},
+      {""}, {""},
+#line 139 "src/lexer-keywords.txt"
+      {"f64x2.abs", TokenType::Unary, Opcode::F64X2Abs},
+      {""}, {""}, {""},
+#line 514 "src/lexer-keywords.txt"
+      {"table.fill", TokenType::TableFill, Opcode::TableFill},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 108 "src/lexer-keywords.txt"
+      {"f32x4", TokenType::F32X4},
+      {""}, {""},
+#line 322 "src/lexer-keywords.txt"
+      {"i32x4", TokenType::I32X4},
+      {""},
+#line 151 "src/lexer-keywords.txt"
+      {"f64x2.min", TokenType::Binary, Opcode::F64X2Min},
+      {""}, {""},
+#line 153 "src/lexer-keywords.txt"
+      {"f64x2.nearest", TokenType::Unary, Opcode::F64X2Nearest},
+      {""}, {""},
+#line 490 "src/lexer-keywords.txt"
+      {"module", TokenType::Module},
+      {""},
+#line 501 "src/lexer-keywords.txt"
+      {"ref.is_null", TokenType::RefIsNull, Opcode::RefIsNull},
+      {""}, {""},
+#line 367 "src/lexer-keywords.txt"
+      {"i64.atomic.store", TokenType::AtomicStore, Opcode::I64AtomicStore},
+#line 243 "src/lexer-keywords.txt"
+      {"i32.atomic.store", TokenType::AtomicStore, Opcode::I32AtomicStore},
+      {""},
+#line 34 "src/lexer-keywords.txt"
+      {"call", TokenType::Call, Opcode::Call},
+      {""},
+#line 141 "src/lexer-keywords.txt"
+      {"f64x2.ceil", TokenType::Unary, Opcode::F64X2Ceil},
+#line 118 "src/lexer-keywords.txt"
+      {"f64.div", TokenType::Binary, Opcode::F64Div},
+#line 62 "src/lexer-keywords.txt"
+      {"f32.div", TokenType::Binary, Opcode::F32Div},
+      {""}, {""}, {""},
+#line 24 "src/lexer-keywords.txt"
+      {"assert_return", TokenType::AssertReturn},
+      {""},
+#line 502 "src/lexer-keywords.txt"
+      {"ref.null", TokenType::RefNull, Opcode::RefNull},
+#line 124 "src/lexer-keywords.txt"
+      {"f64.load", TokenType::Load, Opcode::F64Load},
+#line 68 "src/lexer-keywords.txt"
+      {"f32.load", TokenType::Load, Opcode::F32Load},
+#line 365 "src/lexer-keywords.txt"
+      {"i64.atomic.store32", TokenType::AtomicStore, Opcode::I64AtomicStore32},
+#line 392 "src/lexer-keywords.txt"
+      {"i64.load", TokenType::Load, Opcode::I64Load},
+#line 263 "src/lexer-keywords.txt"
+      {"i32.load", TokenType::Load, Opcode::I32Load},
+      {""},
+#line 113 "src/lexer-keywords.txt"
+      {"f64.convert_i32_s", TokenType::Convert, Opcode::F64ConvertI32S},
+#line 56 "src/lexer-keywords.txt"
+      {"f32.convert_i32_s", TokenType::Convert, Opcode::F32ConvertI32S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 412 "src/lexer-keywords.txt"
+      {"i64.trunc_f32_s", TokenType::Convert, Opcode::I64TruncF32S},
+#line 282 "src/lexer-keywords.txt"
+      {"i32.trunc_f32_s", TokenType::Convert, Opcode::I32TruncF32S},
+      {""}, {""},
+#line 100 "src/lexer-keywords.txt"
+      {"f32x4.ne", TokenType::Compare, Opcode::F32X4Ne},
+      {""},
+#line 505 "src/lexer-keywords.txt"
+      {"rethrow", TokenType::Rethrow, Opcode::Rethrow},
+#line 315 "src/lexer-keywords.txt"
+      {"i32x4.ne", TokenType::Compare, Opcode::I32X4Ne},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 413 "src/lexer-keywords.txt"
+      {"i64.trunc_f32_u", TokenType::Convert, Opcode::I64TruncF32U},
+#line 283 "src/lexer-keywords.txt"
+      {"i32.trunc_f32_u", TokenType::Convert, Opcode::I32TruncF32U},
+      {""},
+#line 142 "src/lexer-keywords.txt"
+      {"f64x2.div", TokenType::Binary, Opcode::F64X2Div},
+      {""}, {""}, {""}, {""}, {""},
+#line 386 "src/lexer-keywords.txt"
+      {"i64.load16_s", TokenType::Load, Opcode::I64Load16S},
+#line 259 "src/lexer-keywords.txt"
+      {"i32.load16_s", TokenType::Load, Opcode::I32Load16S},
+#line 407 "src/lexer-keywords.txt"
+      {"i64.store16", TokenType::Store, Opcode::I64Store16},
+#line 278 "src/lexer-keywords.txt"
+      {"i32.store16", TokenType::Store, Opcode::I32Store16},
+      {""},
+#line 61 "src/lexer-keywords.txt"
+      {"f32.demote_f64", TokenType::Convert, Opcode::F32DemoteF64},
+      {""}, {""},
+#line 388 "src/lexer-keywords.txt"
+      {"i64.load32_s", TokenType::Load, Opcode::I64Load32S},
+      {""}, {""}, {""},
+#line 409 "src/lexer-keywords.txt"
+      {"i64.store8", TokenType::Store, Opcode::I64Store8},
+#line 279 "src/lexer-keywords.txt"
+      {"i32.store8", TokenType::Store, Opcode::I32Store8},
+      {""},
+#line 162 "src/lexer-keywords.txt"
+      {"f64x2.trunc", TokenType::Unary, Opcode::F64X2Trunc},
+      {""}, {""}, {""},
+#line 93 "src/lexer-keywords.txt"
+      {"f32x4.le", TokenType::Compare, Opcode::F32X4Le},
+#line 137 "src/lexer-keywords.txt"
+      {"f64.trunc", TokenType::Unary, Opcode::F64Trunc},
+#line 80 "src/lexer-keywords.txt"
+      {"f32.trunc", TokenType::Unary, Opcode::F32Trunc},
+      {""}, {""}, {""},
+#line 94 "src/lexer-keywords.txt"
+      {"f32x4.lt", TokenType::Compare, Opcode::F32X4Lt},
+      {""}, {""},
+#line 152 "src/lexer-keywords.txt"
+      {"f64x2.mul", TokenType::Binary, Opcode::F64X2Mul},
+      {""},
+#line 478 "src/lexer-keywords.txt"
+      {"local.tee", TokenType::LocalTee, Opcode::LocalTee},
+#line 425 "src/lexer-keywords.txt"
+      {"i64x2.mul", TokenType::Binary, Opcode::I64X2Mul},
+#line 387 "src/lexer-keywords.txt"
+      {"i64.load16_u", TokenType::Load, Opcode::I64Load16U},
+#line 260 "src/lexer-keywords.txt"
+      {"i32.load16_u", TokenType::Load, Opcode::I32Load16U},
+#line 303 "src/lexer-keywords.txt"
+      {"i32x4.le_s", TokenType::Compare, Opcode::I32X4LeS},
+      {""},
+#line 477 "src/lexer-keywords.txt"
+      {"local.set", TokenType::LocalSet, Opcode::LocalSet},
+#line 307 "src/lexer-keywords.txt"
+      {"i32x4.lt_s", TokenType::Compare, Opcode::I32X4LtS},
+#line 90 "src/lexer-keywords.txt"
+      {"f32x4.floor", TokenType::Unary, Opcode::F32X4Floor},
+      {""},
+#line 389 "src/lexer-keywords.txt"
+      {"i64.load32_u", TokenType::Load, Opcode::I64Load32U},
+      {""}, {""},
+#line 106 "src/lexer-keywords.txt"
+      {"f32x4.sub", TokenType::Binary, Opcode::F32X4Sub},
+      {""}, {""},
+#line 321 "src/lexer-keywords.txt"
+      {"i32x4.sub", TokenType::Binary, Opcode::I32X4Sub},
+      {""}, {""}, {""},
+#line 304 "src/lexer-keywords.txt"
+      {"i32x4.le_u", TokenType::Compare, Opcode::I32X4LeU},
+      {""}, {""},
+#line 308 "src/lexer-keywords.txt"
+      {"i32x4.lt_u", TokenType::Compare, Opcode::I32X4LtU},
+#line 532 "src/lexer-keywords.txt"
+      {"v128.or", TokenType::Binary, Opcode::V128Or},
+      {""}, {""}, {""},
+#line 479 "src/lexer-keywords.txt"
+      {"local", TokenType::Local},
+#line 115 "src/lexer-keywords.txt"
+      {"f64.convert_i64_s", TokenType::Convert, Opcode::F64ConvertI64S},
+#line 58 "src/lexer-keywords.txt"
+      {"f32.convert_i64_s", TokenType::Convert, Opcode::F32ConvertI64S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 414 "src/lexer-keywords.txt"
+      {"i64.trunc_f64_s", TokenType::Convert, Opcode::I64TruncF64S},
+#line 284 "src/lexer-keywords.txt"
+      {"i32.trunc_f64_s", TokenType::Convert, Opcode::I32TruncF64S},
+#line 534 "src/lexer-keywords.txt"
+      {"v128", Type::V128},
+      {""},
+#line 533 "src/lexer-keywords.txt"
+      {"v128.store", TokenType::Store, Opcode::V128Store},
+#line 83 "src/lexer-keywords.txt"
+      {"f32x4.add", TokenType::Binary, Opcode::F32X4Add},
+      {""}, {""},
+#line 293 "src/lexer-keywords.txt"
+      {"i32x4.add", TokenType::Binary, Opcode::I32X4Add},
+      {""}, {""}, {""}, {""},
+#line 114 "src/lexer-keywords.txt"
+      {"f64.convert_i32_u", TokenType::Convert, Opcode::F64ConvertI32U},
+#line 57 "src/lexer-keywords.txt"
+      {"f32.convert_i32_u", TokenType::Convert, Opcode::F32ConvertI32U},
+#line 499 "src/lexer-keywords.txt"
+      {"ref.extern", TokenType::RefExtern},
+#line 415 "src/lexer-keywords.txt"
+      {"i64.trunc_f64_u", TokenType::Convert, Opcode::I64TruncF64U},
+#line 285 "src/lexer-keywords.txt"
+      {"i32.trunc_f64_u", TokenType::Convert, Opcode::I32TruncF64U},
+      {""},
+#line 33 "src/lexer-keywords.txt"
+      {"call_indirect", TokenType::CallIndirect, Opcode::CallIndirect},
+#line 531 "src/lexer-keywords.txt"
+      {"v128.not", TokenType::Unary, Opcode::V128Not},
+#line 27 "src/lexer-keywords.txt"
+      {"atomic.fence", TokenType::AtomicFence, Opcode::AtomicFence},
+      {""}, {""}, {""}, {""}, {""},
+#line 22 "src/lexer-keywords.txt"
+      {"assert_invalid", TokenType::AssertInvalid},
+      {""}, {""}, {""}, {""},
+#line 82 "src/lexer-keywords.txt"
+      {"f32x4.abs", TokenType::Unary, Opcode::F32X4Abs},
+#line 335 "src/lexer-keywords.txt"
+      {"i64.atomic.load", TokenType::AtomicLoad, Opcode::I64AtomicLoad},
+#line 219 "src/lexer-keywords.txt"
+      {"i32.atomic.load", TokenType::AtomicLoad, Opcode::I32AtomicLoad},
+#line 292 "src/lexer-keywords.txt"
+      {"i32x4.abs", TokenType::Unary, Opcode::I32X4Abs},
+      {""}, {""}, {""}, {""}, {""},
+#line 311 "src/lexer-keywords.txt"
+      {"i32x4.min_s", TokenType::Binary, Opcode::I32X4MinS},
+      {""},
+#line 524 "src/lexer-keywords.txt"
+      {"type", TokenType::Type},
+      {""},
+#line 43 "src/lexer-keywords.txt"
+      {"drop", TokenType::Drop, Opcode::Drop},
+      {""}, {""}, {""},
+#line 96 "src/lexer-keywords.txt"
+      {"f32x4.min", TokenType::Binary, Opcode::F32X4Min},
+      {""}, {""},
+#line 98 "src/lexer-keywords.txt"
+      {"f32x4.nearest", TokenType::Unary, Opcode::F32X4Nearest},
+      {""}, {""}, {""}, {""},
+#line 507 "src/lexer-keywords.txt"
+      {"return_call", TokenType::ReturnCall, Opcode::ReturnCall},
+      {""},
+#line 397 "src/lexer-keywords.txt"
+      {"i64.or", TokenType::Binary, Opcode::I64Or},
+#line 268 "src/lexer-keywords.txt"
+      {"i32.or", TokenType::Binary, Opcode::I32Or},
+      {""}, {""},
+#line 51 "src/lexer-keywords.txt"
+      {"export", TokenType::Export},
+      {""},
+#line 84 "src/lexer-keywords.txt"
+      {"f32x4.ceil", TokenType::Unary, Opcode::F32X4Ceil},
+#line 472 "src/lexer-keywords.txt"
+      {"import", TokenType::Import},
+      {""}, {""},
+#line 416 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f32_s", TokenType::Convert, Opcode::I64TruncSatF32S},
+#line 286 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f32_s", TokenType::Convert, Opcode::I32TruncSatF32S},
+      {""},
+#line 473 "src/lexer-keywords.txt"
+      {"input", TokenType::Input},
+#line 312 "src/lexer-keywords.txt"
+      {"i32x4.min_u", TokenType::Binary, Opcode::I32X4MinU},
+#line 376 "src/lexer-keywords.txt"
+      {"i64.extend32_s", TokenType::Unary, Opcode::I64Extend32S},
+      {""}, {""}, {""},
+#line 296 "src/lexer-keywords.txt"
+      {"i32x4.bitmask", TokenType::Unary, Opcode::I32X4Bitmask},
+      {""},
+#line 522 "src/lexer-keywords.txt"
+      {"throw", TokenType::Throw, Opcode::Throw},
+      {""}, {""}, {""}, {""},
+#line 378 "src/lexer-keywords.txt"
+      {"i64.extend_i32_s", TokenType::Convert, Opcode::I64ExtendI32S},
+#line 26 "src/lexer-keywords.txt"
+      {"assert_unlinkable", TokenType::AssertUnlinkable},
+      {""},
+#line 36 "src/lexer-keywords.txt"
+      {"catch_all", TokenType::CatchAll, Opcode::CatchAll},
+#line 545 "src/lexer-keywords.txt"
+      {"i64.atomic.wait", TokenType::AtomicWait, Opcode::MemoryAtomicWait64},
+#line 544 "src/lexer-keywords.txt"
+      {"i32.atomic.wait", TokenType::AtomicWait, Opcode::MemoryAtomicWait32},
+      {""}, {""},
+#line 434 "src/lexer-keywords.txt"
+      {"i64.xor", TokenType::Binary, Opcode::I64Xor},
+#line 329 "src/lexer-keywords.txt"
+      {"i32.xor", TokenType::Binary, Opcode::I32Xor},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 417 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f32_u", TokenType::Convert, Opcode::I64TruncSatF32U},
+#line 287 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f32_u", TokenType::Convert, Opcode::I32TruncSatF32U},
+      {""},
+#line 360 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I64AtomicRmwOr},
+#line 237 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.or", TokenType::AtomicRmw, Opcode::I32AtomicRmwOr},
+      {""},
+#line 480 "src/lexer-keywords.txt"
+      {"loop", TokenType::Loop, Opcode::Loop},
+      {""},
+#line 116 "src/lexer-keywords.txt"
+      {"f64.convert_i64_u", TokenType::Convert, Opcode::F64ConvertI64U},
+#line 59 "src/lexer-keywords.txt"
+      {"f32.convert_i64_u", TokenType::Convert, Opcode::F32ConvertI64U},
+#line 87 "src/lexer-keywords.txt"
+      {"f32x4.div", TokenType::Binary, Opcode::F32X4Div},
+      {""}, {""},
+#line 574 "src/lexer-keywords.txt"
+      {"i64.trunc_s/f32", TokenType::Convert, Opcode::I64TruncF32S},
+#line 562 "src/lexer-keywords.txt"
+      {"i32.trunc_s/f32", TokenType::Convert, Opcode::I32TruncF32S},
+      {""},
+#line 379 "src/lexer-keywords.txt"
+      {"i64.extend_i32_u", TokenType::Convert, Opcode::I64ExtendI32U},
+      {""},
+#line 553 "src/lexer-keywords.txt"
+      {"f64.convert_s/i32", TokenType::Convert, Opcode::F64ConvertI32S},
+#line 547 "src/lexer-keywords.txt"
+      {"f32.convert_s/i32", TokenType::Convert, Opcode::F32ConvertI32S},
+      {""}, {""},
+#line 527 "src/lexer-keywords.txt"
+      {"v128.and", TokenType::Binary, Opcode::V128And},
+#line 364 "src/lexer-keywords.txt"
+      {"i64.atomic.store16", TokenType::AtomicStore, Opcode::I64AtomicStore16},
+#line 241 "src/lexer-keywords.txt"
+      {"i32.atomic.store16", TokenType::AtomicStore, Opcode::I32AtomicStore16},
+#line 584 "src/lexer-keywords.txt"
+      {"tee_local", TokenType::LocalTee, Opcode::LocalTee},
+      {""}, {""},
+#line 583 "src/lexer-keywords.txt"
+      {"set_local", TokenType::LocalSet, Opcode::LocalSet},
+#line 578 "src/lexer-keywords.txt"
+      {"i64.trunc_u/f32", TokenType::Convert, Opcode::I64TruncF32U},
+#line 566 "src/lexer-keywords.txt"
+      {"i32.trunc_u/f32", TokenType::Convert, Opcode::I32TruncF32U},
+#line 107 "src/lexer-keywords.txt"
+      {"f32x4.trunc", TokenType::Unary, Opcode::F32X4Trunc},
+#line 529 "src/lexer-keywords.txt"
+      {"v128.const", TokenType::Const, Opcode::V128Const},
+      {""},
+#line 555 "src/lexer-keywords.txt"
+      {"f64.convert_u/i32", TokenType::Convert, Opcode::F64ConvertI32U},
+#line 549 "src/lexer-keywords.txt"
+      {"f32.convert_u/i32", TokenType::Convert, Opcode::F32ConvertI32U},
+      {""}, {""},
+#line 498 "src/lexer-keywords.txt"
+      {"quote", TokenType::Quote},
+      {""},
+#line 333 "src/lexer-keywords.txt"
+      {"i64.atomic.load32_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad32U},
+      {""}, {""},
+#line 551 "src/lexer-keywords.txt"
+      {"f32.demote/f64", TokenType::Convert, Opcode::F32DemoteF64},
+#line 97 "src/lexer-keywords.txt"
+      {"f32x4.mul", TokenType::Binary, Opcode::F32X4Mul},
+      {""}, {""},
+#line 313 "src/lexer-keywords.txt"
+      {"i32x4.mul", TokenType::Binary, Opcode::I32X4Mul},
+      {""}, {""}, {""},
+#line 23 "src/lexer-keywords.txt"
+      {"assert_malformed", TokenType::AssertMalformed},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 390 "src/lexer-keywords.txt"
+      {"i64.load8_s", TokenType::Load, Opcode::I64Load8S},
+#line 261 "src/lexer-keywords.txt"
+      {"i32.load8_s", TokenType::Load, Opcode::I32Load8S},
+      {""}, {""}, {""},
+#line 526 "src/lexer-keywords.txt"
+      {"v128.andnot", TokenType::Binary, Opcode::V128Andnot},
+      {""},
+#line 134 "src/lexer-keywords.txt"
+      {"f64.sqrt", TokenType::Unary, Opcode::F64Sqrt},
+#line 77 "src/lexer-keywords.txt"
+      {"f32.sqrt", TokenType::Unary, Opcode::F32Sqrt},
+      {""}, {""},
+#line 530 "src/lexer-keywords.txt"
+      {"v128.load", TokenType::Load, Opcode::V128Load},
+      {""}, {""},
+#line 350 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AddU},
+#line 227 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AddU},
+      {""},
+#line 497 "src/lexer-keywords.txt"
+      {"param", TokenType::Param},
+      {""}, {""},
+#line 294 "src/lexer-keywords.txt"
+      {"i32x4.all_true", TokenType::Unary, Opcode::I32X4AllTrue},
+      {""},
+#line 375 "src/lexer-keywords.txt"
+      {"i64.extend16_s", TokenType::Unary, Opcode::I64Extend16S},
+#line 251 "src/lexer-keywords.txt"
+      {"i32.extend16_s", TokenType::Unary, Opcode::I32Extend16S},
+#line 159 "src/lexer-keywords.txt"
+      {"f64x2.splat", TokenType::Unary, Opcode::F64X2Splat},
+#line 506 "src/lexer-keywords.txt"
+      {"return_call_indirect", TokenType::ReturnCallIndirect, Opcode::ReturnCallIndirect},
+      {""},
+#line 431 "src/lexer-keywords.txt"
+      {"i64x2.splat", TokenType::Unary, Opcode::I64X2Splat},
+      {""}, {""},
+#line 354 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8SubU},
+#line 231 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8SubU},
+#line 391 "src/lexer-keywords.txt"
+      {"i64.load8_u", TokenType::Load, Opcode::I64Load8U},
+#line 262 "src/lexer-keywords.txt"
+      {"i32.load8_u", TokenType::Load, Opcode::I32Load8U},
+      {""}, {""},
+#line 351 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8AndU},
+#line 228 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8AndU},
+      {""}, {""},
+#line 160 "src/lexer-keywords.txt"
+      {"f64x2.sqrt", TokenType::Unary, Opcode::F64X2Sqrt},
+#line 76 "src/lexer-keywords.txt"
+      {"f32.reinterpret_i32", TokenType::Convert, Opcode::F32ReinterpretI32},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 575 "src/lexer-keywords.txt"
+      {"i64.trunc_s/f64", TokenType::Convert, Opcode::I64TruncF64S},
+#line 563 "src/lexer-keywords.txt"
+      {"i32.trunc_s/f64", TokenType::Convert, Opcode::I32TruncF64S},
+      {""}, {""}, {""}, {""}, {""},
+#line 357 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I64AtomicRmwAdd},
+#line 234 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.add", TokenType::AtomicRmw, Opcode::I32AtomicRmwAdd},
+#line 358 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I64AtomicRmwAnd},
+#line 235 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.and", TokenType::AtomicRmw, Opcode::I32AtomicRmwAnd},
+      {""}, {""},
+#line 121 "src/lexer-keywords.txt"
+      {"f64.ge", TokenType::Compare, Opcode::F64Ge},
+#line 65 "src/lexer-keywords.txt"
+      {"f32.ge", TokenType::Compare, Opcode::F32Ge},
+      {""},
+#line 579 "src/lexer-keywords.txt"
+      {"i64.trunc_u/f64", TokenType::Convert, Opcode::I64TruncF64U},
+#line 567 "src/lexer-keywords.txt"
+      {"i32.trunc_u/f64", TokenType::Convert, Opcode::I32TruncF64U},
+      {""},
+#line 122 "src/lexer-keywords.txt"
+      {"f64.gt", TokenType::Compare, Opcode::F64Gt},
+#line 66 "src/lexer-keywords.txt"
+      {"f32.gt", TokenType::Compare, Opcode::F32Gt},
+      {""}, {""},
+#line 20 "src/lexer-keywords.txt"
+      {"array", Type::Array, TokenType::Array},
+      {""},
+#line 167 "src/lexer-keywords.txt"
+      {"get", TokenType::Get},
+      {""}, {""},
+#line 157 "src/lexer-keywords.txt"
+      {"f64x2.pmin", TokenType::Binary, Opcode::F64X2PMin},
+#line 528 "src/lexer-keywords.txt"
+      {"v128.bitselect", TokenType::Ternary, Opcode::V128BitSelect},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 380 "src/lexer-keywords.txt"
+      {"i64.ge_s", TokenType::Compare, Opcode::I64GeS},
+#line 253 "src/lexer-keywords.txt"
+      {"i32.ge_s", TokenType::Compare, Opcode::I32GeS},
+#line 493 "src/lexer-keywords.txt"
+      {"nan:canonical", TokenType::NanCanonical},
+#line 382 "src/lexer-keywords.txt"
+      {"i64.gt_s", TokenType::Compare, Opcode::I64GtS},
+#line 255 "src/lexer-keywords.txt"
+      {"i32.gt_s", TokenType::Compare, Opcode::I32GtS},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 405 "src/lexer-keywords.txt"
+      {"i64.shr_s", TokenType::Binary, Opcode::I64ShrS},
+#line 276 "src/lexer-keywords.txt"
+      {"i32.shr_s", TokenType::Binary, Opcode::I32ShrS},
+      {""}, {""}, {""},
+#line 374 "src/lexer-keywords.txt"
+      {"i64.eqz", TokenType::Convert, Opcode::I64Eqz},
+#line 250 "src/lexer-keywords.txt"
+      {"i32.eqz", TokenType::Convert, Opcode::I32Eqz},
+      {""}, {""},
+#line 503 "src/lexer-keywords.txt"
+      {"register", TokenType::Register},
+#line 30 "src/lexer-keywords.txt"
+      {"br_if", TokenType::BrIf, Opcode::BrIf},
+      {""}, {""}, {""},
+#line 571 "src/lexer-keywords.txt"
+      {"i64.extend_s/i32", TokenType::Convert, Opcode::I64ExtendI32S},
+      {""}, {""}, {""},
+#line 361 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I64AtomicRmwSub},
+#line 238 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.sub", TokenType::AtomicRmw, Opcode::I32AtomicRmwSub},
+      {""},
+#line 381 "src/lexer-keywords.txt"
+      {"i64.ge_u", TokenType::Compare, Opcode::I64GeU},
+#line 254 "src/lexer-keywords.txt"
+      {"i32.ge_u", TokenType::Compare, Opcode::I32GeU},
+      {""},
+#line 383 "src/lexer-keywords.txt"
+      {"i64.gt_u", TokenType::Compare, Opcode::I64GtU},
+#line 256 "src/lexer-keywords.txt"
+      {"i32.gt_u", TokenType::Compare, Opcode::I32GtU},
+      {""}, {""},
+#line 146 "src/lexer-keywords.txt"
+      {"f64x2.ge", TokenType::Compare, Opcode::F64X2Ge},
+      {""},
+#line 572 "src/lexer-keywords.txt"
+      {"i64.extend_u/i32", TokenType::Convert, Opcode::I64ExtendI32U},
+      {""},
+#line 406 "src/lexer-keywords.txt"
+      {"i64.shr_u", TokenType::Binary, Opcode::I64ShrU},
+#line 277 "src/lexer-keywords.txt"
+      {"i32.shr_u", TokenType::Binary, Opcode::I32ShrU},
+#line 147 "src/lexer-keywords.txt"
+      {"f64x2.gt", TokenType::Compare, Opcode::F64X2Gt},
+#line 429 "src/lexer-keywords.txt"
+      {"i64x2.shr_s", TokenType::Binary, Opcode::I64X2ShrS},
+      {""}, {""},
+#line 133 "src/lexer-keywords.txt"
+      {"f64.reinterpret_i64", TokenType::Convert, Opcode::F64ReinterpretI64},
+      {""},
+#line 377 "src/lexer-keywords.txt"
+      {"i64.extend8_s", TokenType::Unary, Opcode::I64Extend8S},
+#line 252 "src/lexer-keywords.txt"
+      {"i32.extend8_s", TokenType::Unary, Opcode::I32Extend8S},
+#line 535 "src/lexer-keywords.txt"
+      {"v128.xor", TokenType::Binary, Opcode::V128Xor},
+      {""}, {""},
+#line 21 "src/lexer-keywords.txt"
+      {"assert_exhaustion", TokenType::AssertExhaustion},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 515 "src/lexer-keywords.txt"
+      {"table.get", TokenType::TableGet, Opcode::TableGet},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 327 "src/lexer-keywords.txt"
+      {"i32x4.widen_low_i16x8_s", TokenType::Unary, Opcode::I32X4WidenLowI16X8S},
+      {""}, {""}, {""}, {""}, {""},
+#line 430 "src/lexer-keywords.txt"
+      {"i64x2.shr_u", TokenType::Binary, Opcode::I64X2ShrU},
+      {""},
+#line 35 "src/lexer-keywords.txt"
+      {"catch", TokenType::Catch, Opcode::Catch},
+      {""}, {""},
+#line 132 "src/lexer-keywords.txt"
+      {"f64.promote_f32", TokenType::Convert, Opcode::F64PromoteF32},
+      {""}, {""}, {""},
+#line 488 "src/lexer-keywords.txt"
+      {"memory.size", TokenType::MemorySize, Opcode::MemorySize},
+#line 328 "src/lexer-keywords.txt"
+      {"i32x4.widen_low_i16x8_u", TokenType::Unary, Opcode::I32X4WidenLowI16X8U},
+#line 120 "src/lexer-keywords.txt"
+      {"f64.floor", TokenType::Unary, Opcode::F64Floor},
+#line 64 "src/lexer-keywords.txt"
+      {"f32.floor", TokenType::Unary, Opcode::F32Floor},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 346 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32OrU},
+#line 334 "src/lexer-keywords.txt"
+      {"i64.atomic.load8_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad8U},
+#line 218 "src/lexer-keywords.txt"
+      {"i32.atomic.load8_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad8U},
+      {""},
+#line 418 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f64_s", TokenType::Convert, Opcode::I64TruncSatF64S},
+#line 288 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f64_s", TokenType::Convert, Opcode::I32TruncSatF64S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 487 "src/lexer-keywords.txt"
+      {"memory.init", TokenType::MemoryInit, Opcode::MemoryInit},
+      {""}, {""}, {""},
+#line 404 "src/lexer-keywords.txt"
+      {"i64.shl", TokenType::Binary, Opcode::I64Shl},
+#line 275 "src/lexer-keywords.txt"
+      {"i32.shl", TokenType::Binary, Opcode::I32Shl},
+#line 347 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32SubU},
+      {""}, {""},
+#line 461 "src/lexer-keywords.txt"
+      {"i8x16.ne", TokenType::Compare, Opcode::I8X16Ne},
+      {""},
+#line 104 "src/lexer-keywords.txt"
+      {"f32x4.splat", TokenType::Unary, Opcode::F32X4Splat},
+      {""},
+#line 169 "src/lexer-keywords.txt"
+      {"global.set", TokenType::GlobalSet, Opcode::GlobalSet},
+#line 320 "src/lexer-keywords.txt"
+      {"i32x4.splat", TokenType::Unary, Opcode::I32X4Splat},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 419 "src/lexer-keywords.txt"
+      {"i64.trunc_sat_f64_u", TokenType::Convert, Opcode::I64TruncSatF64U},
+#line 289 "src/lexer-keywords.txt"
+      {"i32.trunc_sat_f64_u", TokenType::Convert, Opcode::I32TruncSatF64U},
+      {""}, {""},
+#line 144 "src/lexer-keywords.txt"
+      {"f64x2.extract_lane", TokenType::SimdLaneOp, Opcode::F64X2ExtractLane},
+#line 105 "src/lexer-keywords.txt"
+      {"f32x4.sqrt", TokenType::Unary, Opcode::F32X4Sqrt},
+      {""},
+#line 422 "src/lexer-keywords.txt"
+      {"i64x2.extract_lane", TokenType::SimdLaneOp, Opcode::I64X2ExtractLane},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 554 "src/lexer-keywords.txt"
+      {"f64.convert_s/i64", TokenType::Convert, Opcode::F64ConvertI64S},
+#line 548 "src/lexer-keywords.txt"
+      {"f32.convert_s/i64", TokenType::Convert, Opcode::F32ConvertI64S},
+      {""}, {""}, {""},
+#line 170 "src/lexer-keywords.txt"
+      {"global", TokenType::Global},
+      {""},
+#line 428 "src/lexer-keywords.txt"
+      {"i64x2.shl", TokenType::Binary, Opcode::I64X2Shl},
+#line 126 "src/lexer-keywords.txt"
+      {"f64.max", TokenType::Binary, Opcode::F64Max},
+#line 70 "src/lexer-keywords.txt"
+      {"f32.max", TokenType::Binary, Opcode::F32Max},
+      {""},
+#line 552 "src/lexer-keywords.txt"
+      {"f32.reinterpret/i32", TokenType::Convert, Opcode::F32ReinterpretI32},
+#line 41 "src/lexer-keywords.txt"
+      {"delegate", TokenType::Delegate},
+      {""}, {""}, {""},
+#line 556 "src/lexer-keywords.txt"
+      {"f64.convert_u/i64", TokenType::Convert, Opcode::F64ConvertI64U},
+#line 550 "src/lexer-keywords.txt"
+      {"f32.convert_u/i64", TokenType::Convert, Opcode::F32ConvertI64U},
+      {""}, {""}, {""}, {""},
+#line 450 "src/lexer-keywords.txt"
+      {"i8x16.le_s", TokenType::Compare, Opcode::I8X16LeS},
+      {""},
+#line 102 "src/lexer-keywords.txt"
+      {"f32x4.pmin", TokenType::Binary, Opcode::F32X4PMin},
+#line 452 "src/lexer-keywords.txt"
+      {"i8x16.lt_s", TokenType::Compare, Opcode::I8X16LtS},
+#line 309 "src/lexer-keywords.txt"
+      {"i32x4.max_s", TokenType::Binary, Opcode::I32X4MaxS},
+#line 516 "src/lexer-keywords.txt"
+      {"table.grow", TokenType::TableGrow, Opcode::TableGrow},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 469 "src/lexer-keywords.txt"
+      {"i8x16.sub", TokenType::Binary, Opcode::I8X16Sub},
+      {""},
+#line 470 "src/lexer-keywords.txt"
+      {"i8x16", TokenType::I8X16},
+      {""},
+#line 451 "src/lexer-keywords.txt"
+      {"i8x16.le_u", TokenType::Compare, Opcode::I8X16LeU},
+      {""}, {""},
+#line 453 "src/lexer-keywords.txt"
+      {"i8x16.lt_u", TokenType::Compare, Opcode::I8X16LtU},
+      {""},
+#line 85 "src/lexer-keywords.txt"
+      {"f32x4.convert_i32x4_s", TokenType::Unary, Opcode::F32X4ConvertI32X4S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 343 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AddU},
+      {""}, {""}, {""}, {""},
+#line 310 "src/lexer-keywords.txt"
+      {"i32x4.max_u", TokenType::Binary, Opcode::I32X4MaxU},
+#line 86 "src/lexer-keywords.txt"
+      {"f32x4.convert_i32x4_u", TokenType::Unary, Opcode::F32X4ConvertI32X4U},
+#line 485 "src/lexer-keywords.txt"
+      {"memory.fill", TokenType::MemoryFill, Opcode::MemoryFill},
+      {""}, {""},
+#line 494 "src/lexer-keywords.txt"
+      {"nop", TokenType::Nop, Opcode::Nop},
+#line 339 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16OrU},
+#line 223 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16OrU},
+#line 438 "src/lexer-keywords.txt"
+      {"i8x16.add", TokenType::Binary, Opcode::I8X16Add},
+      {""}, {""}, {""},
+#line 332 "src/lexer-keywords.txt"
+      {"i64.atomic.load16_u", TokenType::AtomicLoad, Opcode::I64AtomicLoad16U},
+#line 217 "src/lexer-keywords.txt"
+      {"i32.atomic.load16_u", TokenType::AtomicLoad, Opcode::I32AtomicLoad16U},
+#line 91 "src/lexer-keywords.txt"
+      {"f32x4.ge", TokenType::Compare, Opcode::F32X4Ge},
+#line 158 "src/lexer-keywords.txt"
+      {"f64x2.replace_lane", TokenType::SimdLaneOp, Opcode::F64X2ReplaceLane},
+      {""},
+#line 344 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32AndU},
+#line 427 "src/lexer-keywords.txt"
+      {"i64x2.replace_lane", TokenType::SimdLaneOp, Opcode::I64X2ReplaceLane},
+      {""},
+#line 92 "src/lexer-keywords.txt"
+      {"f32x4.gt", TokenType::Compare, Opcode::F32X4Gt},
+#line 318 "src/lexer-keywords.txt"
+      {"i32x4.shr_s", TokenType::Binary, Opcode::I32X4ShrS},
+      {""}, {""}, {""}, {""},
+#line 340 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16SubU},
+#line 224 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.sub_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16SubU},
+      {""},
+#line 299 "src/lexer-keywords.txt"
+      {"i32x4.ge_s", TokenType::Compare, Opcode::I32X4GeS},
+      {""}, {""},
+#line 301 "src/lexer-keywords.txt"
+      {"i32x4.gt_s", TokenType::Compare, Opcode::I32X4GtS},
+#line 523 "src/lexer-keywords.txt"
+      {"try", TokenType::Try, Opcode::Try},
+#line 201 "src/lexer-keywords.txt"
+      {"i16x8.ne", TokenType::Compare, Opcode::I16X8Ne},
+#line 435 "src/lexer-keywords.txt"
+      {"i8x16.abs", TokenType::Unary, Opcode::I8X16Abs},
+      {""}, {""}, {""}, {""}, {""},
+#line 456 "src/lexer-keywords.txt"
+      {"i8x16.min_s", TokenType::Binary, Opcode::I8X16MinS},
+#line 295 "src/lexer-keywords.txt"
+      {"i32x4.any_true", TokenType::Unary, Opcode::I32X4AnyTrue},
+      {""}, {""},
+#line 300 "src/lexer-keywords.txt"
+      {"i32x4.ge_u", TokenType::Compare, Opcode::I32X4GeU},
+#line 558 "src/lexer-keywords.txt"
+      {"f64.reinterpret/i64", TokenType::Convert, Opcode::F64ReinterpretI64},
+      {""},
+#line 302 "src/lexer-keywords.txt"
+      {"i32x4.gt_u", TokenType::Compare, Opcode::I32X4GtU},
+      {""}, {""}, {""}, {""},
+#line 319 "src/lexer-keywords.txt"
+      {"i32x4.shr_u", TokenType::Binary, Opcode::I32X4ShrU},
+#line 500 "src/lexer-keywords.txt"
+      {"ref.func", TokenType::RefFunc, Opcode::RefFunc},
+#line 423 "src/lexer-keywords.txt"
+      {"v128.load32x2_s", TokenType::Load, Opcode::V128Load32X2S},
+      {""}, {""}, {""},
+#line 582 "src/lexer-keywords.txt"
+      {"set_global", TokenType::GlobalSet, Opcode::GlobalSet},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 424 "src/lexer-keywords.txt"
+      {"v128.load32x2_u", TokenType::Load, Opcode::V128Load32X2U},
+#line 150 "src/lexer-keywords.txt"
+      {"f64x2.max", TokenType::Binary, Opcode::F64X2Max},
+#line 457 "src/lexer-keywords.txt"
+      {"i8x16.min_u", TokenType::Binary, Opcode::I8X16MinU},
+      {""},
+#line 546 "src/lexer-keywords.txt"
+      {"anyfunc", Type::FuncRef},
+      {""}, {""},
+#line 442 "src/lexer-keywords.txt"
+      {"i8x16.bitmask", TokenType::Unary, Opcode::I8X16Bitmask},
+      {""},
+#line 557 "src/lexer-keywords.txt"
+      {"f64.promote/f32", TokenType::Convert, Opcode::F64PromoteF32},
+#line 353 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8OrU},
+#line 230 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.or_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8OrU},
+#line 525 "src/lexer-keywords.txt"
+      {"unreachable", TokenType::Unreachable, Opcode::Unreachable},
+      {""}, {""},
+#line 187 "src/lexer-keywords.txt"
+      {"i16x8.le_s", TokenType::Compare, Opcode::I16X8LeS},
+      {""}, {""},
+#line 191 "src/lexer-keywords.txt"
+      {"i16x8.lt_s", TokenType::Compare, Opcode::I16X8LtS},
+      {""},
+#line 467 "src/lexer-keywords.txt"
+      {"i8x16.sub_sat_s", TokenType::Binary, Opcode::I8X16SubSatS},
+      {""},
+#line 476 "src/lexer-keywords.txt"
+      {"local.get", TokenType::LocalGet, Opcode::LocalGet},
+      {""}, {""}, {""}, {""},
+#line 209 "src/lexer-keywords.txt"
+      {"i16x8.sub", TokenType::Binary, Opcode::I16X8Sub},
+      {""}, {""},
+#line 345 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw32CmpxchgU},
+#line 188 "src/lexer-keywords.txt"
+      {"i16x8.le_u", TokenType::Compare, Opcode::I16X8LeU},
+#line 28 "src/lexer-keywords.txt"
+      {"binary", TokenType::Bin},
+      {""},
+#line 192 "src/lexer-keywords.txt"
+      {"i16x8.lt_u", TokenType::Compare, Opcode::I16X8LtU},
+      {""},
+#line 468 "src/lexer-keywords.txt"
+      {"i8x16.sub_sat_u", TokenType::Binary, Opcode::I8X16SubSatU},
+#line 356 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XorU},
+#line 233 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XorU},
+      {""}, {""},
+#line 336 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AddU},
+#line 220 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.add_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AddU},
+      {""}, {""},
+#line 89 "src/lexer-keywords.txt"
+      {"f32x4.extract_lane", TokenType::SimdLaneOp, Opcode::F32X4ExtractLane},
+#line 492 "src/lexer-keywords.txt"
+      {"nan:arithmetic", TokenType::NanArithmetic},
+      {""},
+#line 298 "src/lexer-keywords.txt"
+      {"i32x4.extract_lane", TokenType::SimdLaneOp, Opcode::I32X4ExtractLane},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 175 "src/lexer-keywords.txt"
+      {"i16x8.add", TokenType::Binary, Opcode::I16X8Add},
+      {""}, {""}, {""},
+#line 337 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16AndU},
+#line 221 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.and_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16AndU},
+#line 317 "src/lexer-keywords.txt"
+      {"i32x4.shl", TokenType::Binary, Opcode::I32X4Shl},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 25 "src/lexer-keywords.txt"
+      {"assert_trap", TokenType::AssertTrap},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 436 "src/lexer-keywords.txt"
+      {"i8x16.add_sat_s", TokenType::Binary, Opcode::I8X16AddSatS},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 172 "src/lexer-keywords.txt"
+      {"i16x8.abs", TokenType::Unary, Opcode::I16X8Abs},
+      {""}, {""}, {""},
+#line 541 "src/lexer-keywords.txt"
+      {"i8x16.swizzle", TokenType::Binary, Opcode::I8X16Swizzle},
+      {""},
+#line 195 "src/lexer-keywords.txt"
+      {"i16x8.min_s", TokenType::Binary, Opcode::I16X8MinS},
+#line 156 "src/lexer-keywords.txt"
+      {"f64x2.pmax", TokenType::Binary, Opcode::F64X2PMax},
+      {""},
+#line 437 "src/lexer-keywords.txt"
+      {"i8x16.add_sat_u", TokenType::Binary, Opcode::I8X16AddSatU},
+      {""}, {""},
+#line 291 "src/lexer-keywords.txt"
+      {"i32.wrap_i64", TokenType::Convert, Opcode::I32WrapI64},
+      {""},
+#line 305 "src/lexer-keywords.txt"
+      {"v128.load16x4_s", TokenType::Load, Opcode::V128Load16X4S},
+      {""}, {""}, {""},
+#line 119 "src/lexer-keywords.txt"
+      {"f64.eq", TokenType::Compare, Opcode::F64Eq},
+#line 63 "src/lexer-keywords.txt"
+      {"f32.eq", TokenType::Compare, Opcode::F32Eq},
+      {""},
+#line 373 "src/lexer-keywords.txt"
+      {"i64.eq", TokenType::Compare, Opcode::I64Eq},
+#line 249 "src/lexer-keywords.txt"
+      {"i32.eq", TokenType::Compare, Opcode::I32Eq},
+      {""},
+#line 439 "src/lexer-keywords.txt"
+      {"i8x16.all_true", TokenType::Unary, Opcode::I8X16AllTrue},
+      {""}, {""}, {""}, {""}, {""},
+#line 306 "src/lexer-keywords.txt"
+      {"v128.load16x4_u", TokenType::Load, Opcode::V128Load16X4U},
+#line 513 "src/lexer-keywords.txt"
+      {"table.copy", TokenType::TableCopy, Opcode::TableCopy},
+      {""}, {""}, {""},
+#line 352 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw8CmpxchgU},
+#line 229 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw8CmpxchgU},
+      {""},
+#line 196 "src/lexer-keywords.txt"
+      {"i16x8.min_u", TokenType::Binary, Opcode::I16X8MinU},
+      {""},
+#line 349 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XorU},
+      {""}, {""},
+#line 179 "src/lexer-keywords.txt"
+      {"i16x8.bitmask", TokenType::Unary, Opcode::I16X8Bitmask},
+      {""},
+#line 103 "src/lexer-keywords.txt"
+      {"f32x4.replace_lane", TokenType::SimdLaneOp, Opcode::F32X4ReplaceLane},
+      {""}, {""},
+#line 316 "src/lexer-keywords.txt"
+      {"i32x4.replace_lane", TokenType::SimdLaneOp, Opcode::I32X4ReplaceLane},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 207 "src/lexer-keywords.txt"
+      {"i16x8.sub_sat_s", TokenType::Binary, Opcode::I16X8SubSatS},
+      {""}, {""}, {""},
+#line 143 "src/lexer-keywords.txt"
+      {"f64x2.eq", TokenType::Compare, Opcode::F64X2Eq},
+#line 338 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmw16CmpxchgU},
+#line 222 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.cmpxchg_u", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmw16CmpxchgU},
+      {""}, {""},
+#line 539 "src/lexer-keywords.txt"
+      {"v128.load8_splat", TokenType::Load, Opcode::V128Load8Splat},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 208 "src/lexer-keywords.txt"
+      {"i16x8.sub_sat_u", TokenType::Binary, Opcode::I16X8SubSatU},
+      {""}, {""},
+#line 44 "src/lexer-keywords.txt"
+      {"elem.drop", TokenType::ElemDrop, Opcode::ElemDrop},
+      {""}, {""},
+#line 210 "src/lexer-keywords.txt"
+      {"i16x8", TokenType::I16X8},
+      {""}, {""},
+#line 38 "src/lexer-keywords.txt"
+      {"data.drop", TokenType::DataDrop, Opcode::DataDrop},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 398 "src/lexer-keywords.txt"
+      {"i64.popcnt", TokenType::Unary, Opcode::I64Popcnt},
+#line 269 "src/lexer-keywords.txt"
+      {"i32.popcnt", TokenType::Unary, Opcode::I32Popcnt},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 560 "src/lexer-keywords.txt"
+      {"get_local", TokenType::LocalGet, Opcode::LocalGet},
+      {""},
+#line 489 "src/lexer-keywords.txt"
+      {"memory", TokenType::Memory},
+#line 95 "src/lexer-keywords.txt"
+      {"f32x4.max", TokenType::Binary, Opcode::F32X4Max},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 197 "src/lexer-keywords.txt"
+      {"i16x8.mul", TokenType::Binary, Opcode::I16X8Mul},
+      {""},
+#line 173 "src/lexer-keywords.txt"
+      {"i16x8.add_sat_s", TokenType::Binary, Opcode::I16X8AddSatS},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 538 "src/lexer-keywords.txt"
+      {"v128.load64_splat", TokenType::Load, Opcode::V128Load64Splat},
+#line 537 "src/lexer-keywords.txt"
+      {"v128.load32_splat", TokenType::Load, Opcode::V128Load32Splat},
+      {""},
+#line 174 "src/lexer-keywords.txt"
+      {"i16x8.add_sat_u", TokenType::Binary, Opcode::I16X8AddSatU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 348 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw32.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw32XchgU},
+      {""},
+#line 176 "src/lexer-keywords.txt"
+      {"i16x8.all_true", TokenType::Unary, Opcode::I16X8AllTrue},
+      {""}, {""}, {""}, {""},
+#line 189 "src/lexer-keywords.txt"
+      {"v128.load8x8_s", TokenType::Load, Opcode::V128Load8X8S},
+      {""}, {""}, {""}, {""}, {""},
+#line 342 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XorU},
+#line 226 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.xor_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XorU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 270 "src/lexer-keywords.txt"
+      {"i32.reinterpret_f32", TokenType::Convert, Opcode::I32ReinterpretF32},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 190 "src/lexer-keywords.txt"
+      {"v128.load8x8_u", TokenType::Load, Opcode::V128Load8X8U},
+      {""}, {""},
+#line 543 "src/lexer-keywords.txt"
+      {"atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify},
+      {""}, {""},
+#line 366 "src/lexer-keywords.txt"
+      {"i64.atomic.store8", TokenType::AtomicStore, Opcode::I64AtomicStore8},
+#line 242 "src/lexer-keywords.txt"
+      {"i32.atomic.store8", TokenType::AtomicStore, Opcode::I32AtomicStore8},
+      {""}, {""},
+#line 323 "src/lexer-keywords.txt"
+      {"i32x4.trunc_sat_f32x4_s", TokenType::Unary, Opcode::I32X4TruncSatF32X4S},
+#line 101 "src/lexer-keywords.txt"
+      {"f32x4.pmax", TokenType::Binary, Opcode::F32X4PMax},
+      {""}, {""}, {""}, {""},
+#line 363 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I64AtomicRmwXor},
+#line 240 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.xor", TokenType::AtomicRmw, Opcode::I32AtomicRmwXor},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 324 "src/lexer-keywords.txt"
+      {"i32x4.trunc_sat_f32x4_u", TokenType::Unary, Opcode::I32X4TruncSatF32X4U},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 466 "src/lexer-keywords.txt"
+      {"i8x16.splat", TokenType::Unary, Opcode::I8X16Splat},
+      {""}, {""},
+#line 570 "src/lexer-keywords.txt"
+      {"i32.wrap/i64", TokenType::Convert, Opcode::I32WrapI64},
+      {""}, {""}, {""},
+#line 130 "src/lexer-keywords.txt"
+      {"f64.neg", TokenType::Unary, Opcode::F64Neg},
+#line 74 "src/lexer-keywords.txt"
+      {"f32.neg", TokenType::Unary, Opcode::F32Neg},
+      {""},
+#line 482 "src/lexer-keywords.txt"
+      {"memory.atomic.wait32", TokenType::AtomicWait, Opcode::MemoryAtomicWait32},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 576 "src/lexer-keywords.txt"
+      {"i64.trunc_s:sat/f32", TokenType::Convert, Opcode::I64TruncSatF32S},
+#line 564 "src/lexer-keywords.txt"
+      {"i32.trunc_s:sat/f32", TokenType::Convert, Opcode::I32TruncSatF32S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 536 "src/lexer-keywords.txt"
+      {"v128.load16_splat", TokenType::Load, Opcode::V128Load16Splat},
+#line 88 "src/lexer-keywords.txt"
+      {"f32x4.eq", TokenType::Compare, Opcode::F32X4Eq},
+      {""}, {""},
+#line 297 "src/lexer-keywords.txt"
+      {"i32x4.eq", TokenType::Compare, Opcode::I32X4Eq},
+      {""}, {""},
+#line 580 "src/lexer-keywords.txt"
+      {"i64.trunc_u:sat/f32", TokenType::Convert, Opcode::I64TruncSatF32U},
+#line 568 "src/lexer-keywords.txt"
+      {"i32.trunc_u:sat/f32", TokenType::Convert, Opcode::I32TruncSatF32U},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 341 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw16XchgU},
+#line 225 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw16.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw16XchgU},
+      {""},
+#line 399 "src/lexer-keywords.txt"
+      {"i64.reinterpret_f64", TokenType::Convert, Opcode::I64ReinterpretF64},
+      {""}, {""}, {""}, {""},
+#line 454 "src/lexer-keywords.txt"
+      {"i8x16.max_s", TokenType::Binary, Opcode::I8X16MaxS},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 37 "src/lexer-keywords.txt"
+      {"current_memory", TokenType::MemorySize, Opcode::MemorySize},
+      {""}, {""}, {""},
+#line 154 "src/lexer-keywords.txt"
+      {"f64x2.neg", TokenType::Unary, Opcode::F64X2Neg},
+      {""}, {""},
+#line 426 "src/lexer-keywords.txt"
+      {"i64x2.neg", TokenType::Unary, Opcode::I64X2Neg},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 455 "src/lexer-keywords.txt"
+      {"i8x16.max_u", TokenType::Binary, Opcode::I8X16MaxU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 464 "src/lexer-keywords.txt"
+      {"i8x16.shr_s", TokenType::Binary, Opcode::I8X16ShrS},
+#line 483 "src/lexer-keywords.txt"
+      {"memory.atomic.wait64", TokenType::AtomicWait, Opcode::MemoryAtomicWait64},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 446 "src/lexer-keywords.txt"
+      {"i8x16.ge_s", TokenType::Compare, Opcode::I8X16GeS},
+#line 577 "src/lexer-keywords.txt"
+      {"i64.trunc_s:sat/f64", TokenType::Convert, Opcode::I64TruncSatF64S},
+#line 565 "src/lexer-keywords.txt"
+      {"i32.trunc_s:sat/f64", TokenType::Convert, Opcode::I32TruncSatF64S},
+#line 448 "src/lexer-keywords.txt"
+      {"i8x16.gt_s", TokenType::Compare, Opcode::I8X16GtS},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 206 "src/lexer-keywords.txt"
+      {"i16x8.splat", TokenType::Unary, Opcode::I16X8Splat},
+      {""}, {""},
+#line 440 "src/lexer-keywords.txt"
+      {"i8x16.any_true", TokenType::Unary, Opcode::I8X16AnyTrue},
+#line 168 "src/lexer-keywords.txt"
+      {"global.get", TokenType::GlobalGet, Opcode::GlobalGet},
+      {""},
+#line 447 "src/lexer-keywords.txt"
+      {"i8x16.ge_u", TokenType::Compare, Opcode::I8X16GeU},
+#line 581 "src/lexer-keywords.txt"
+      {"i64.trunc_u:sat/f64", TokenType::Convert, Opcode::I64TruncSatF64U},
+#line 569 "src/lexer-keywords.txt"
+      {"i32.trunc_u:sat/f64", TokenType::Convert, Opcode::I32TruncSatF64U},
+#line 449 "src/lexer-keywords.txt"
+      {"i8x16.gt_u", TokenType::Compare, Opcode::I8X16GtU},
+      {""}, {""}, {""}, {""},
+#line 465 "src/lexer-keywords.txt"
+      {"i8x16.shr_u", TokenType::Binary, Opcode::I8X16ShrU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 561 "src/lexer-keywords.txt"
+      {"i32.reinterpret/f32", TokenType::Convert, Opcode::I32ReinterpretF32},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 193 "src/lexer-keywords.txt"
+      {"i16x8.max_s", TokenType::Binary, Opcode::I16X8MaxS},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 540 "src/lexer-keywords.txt"
+      {"i8x16.shuffle", TokenType::SimdShuffleOp, Opcode::I8X16Shuffle},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 194 "src/lexer-keywords.txt"
+      {"i16x8.max_u", TokenType::Binary, Opcode::I16X8MaxU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 444 "src/lexer-keywords.txt"
+      {"i8x16.extract_lane_s", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneS},
+      {""}, {""}, {""}, {""},
+#line 463 "src/lexer-keywords.txt"
+      {"i8x16.shl", TokenType::Binary, Opcode::I8X16Shl},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 204 "src/lexer-keywords.txt"
+      {"i16x8.shr_s", TokenType::Binary, Opcode::I16X8ShrS},
+      {""}, {""}, {""},
+#line 445 "src/lexer-keywords.txt"
+      {"i8x16.extract_lane_u", TokenType::SimdLaneOp, Opcode::I8X16ExtractLaneU},
+      {""}, {""}, {""},
+#line 183 "src/lexer-keywords.txt"
+      {"i16x8.ge_s", TokenType::Compare, Opcode::I16X8GeS},
+      {""}, {""},
+#line 185 "src/lexer-keywords.txt"
+      {"i16x8.gt_s", TokenType::Compare, Opcode::I16X8GtS},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 177 "src/lexer-keywords.txt"
+      {"i16x8.any_true", TokenType::Unary, Opcode::I16X8AnyTrue},
+      {""}, {""},
+#line 184 "src/lexer-keywords.txt"
+      {"i16x8.ge_u", TokenType::Compare, Opcode::I16X8GeU},
+      {""}, {""},
+#line 186 "src/lexer-keywords.txt"
+      {"i16x8.gt_u", TokenType::Compare, Opcode::I16X8GtU},
+      {""},
+#line 573 "src/lexer-keywords.txt"
+      {"i64.reinterpret/f64", TokenType::Convert, Opcode::I64ReinterpretF64},
+      {""}, {""},
+#line 205 "src/lexer-keywords.txt"
+      {"i16x8.shr_u", TokenType::Binary, Opcode::I16X8ShrU},
+#line 99 "src/lexer-keywords.txt"
+      {"f32x4.neg", TokenType::Unary, Opcode::F32X4Neg},
+      {""}, {""},
+#line 314 "src/lexer-keywords.txt"
+      {"i32x4.neg", TokenType::Unary, Opcode::I32X4Neg},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 559 "src/lexer-keywords.txt"
+      {"get_global", TokenType::GlobalGet, Opcode::GlobalGet},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 462 "src/lexer-keywords.txt"
+      {"i8x16.replace_lane", TokenType::SimdLaneOp, Opcode::I8X16ReplaceLane},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+#line 481 "src/lexer-keywords.txt"
+      {"memory.atomic.notify", TokenType::AtomicNotify, Opcode::MemoryAtomicNotify},
+      {""}, {""},
+#line 486 "src/lexer-keywords.txt"
+      {"memory.grow", TokenType::MemoryGrow, Opcode::MemoryGrow},
+      {""}, {""}, {""},
+#line 117 "src/lexer-keywords.txt"
+      {"f64.copysign", TokenType::Binary, Opcode::F64Copysign},
+#line 60 "src/lexer-keywords.txt"
+      {"f32.copysign", TokenType::Binary, Opcode::F32Copysign},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 181 "src/lexer-keywords.txt"
+      {"i16x8.extract_lane_s", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneS},
+      {""}, {""}, {""}, {""},
+#line 203 "src/lexer-keywords.txt"
+      {"i16x8.shl", TokenType::Binary, Opcode::I16X8Shl},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 182 "src/lexer-keywords.txt"
+      {"i16x8.extract_lane_u", TokenType::SimdLaneOp, Opcode::I16X8ExtractLaneU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 441 "src/lexer-keywords.txt"
+      {"i8x16.avgr_u", TokenType::Binary, Opcode::I8X16AvgrU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 198 "src/lexer-keywords.txt"
+      {"i16x8.narrow_i32x4_s", TokenType::Binary, Opcode::I16X8NarrowI32X4S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 199 "src/lexer-keywords.txt"
+      {"i16x8.narrow_i32x4_u", TokenType::Binary, Opcode::I16X8NarrowI32X4U},
+#line 355 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I64AtomicRmw8XchgU},
+#line 232 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw8.xchg_u", TokenType::AtomicRmw, Opcode::I32AtomicRmw8XchgU},
+      {""}, {""}, {""}, {""}, {""},
+#line 202 "src/lexer-keywords.txt"
+      {"i16x8.replace_lane", TokenType::SimdLaneOp, Opcode::I16X8ReplaceLane},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 325 "src/lexer-keywords.txt"
+      {"i32x4.widen_high_i16x8_s", TokenType::Unary, Opcode::I32X4WidenHighI16X8S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 484 "src/lexer-keywords.txt"
+      {"memory.copy", TokenType::MemoryCopy, Opcode::MemoryCopy},
+      {""}, {""}, {""}, {""}, {""},
+#line 326 "src/lexer-keywords.txt"
+      {"i32x4.widen_high_i16x8_u", TokenType::Unary, Opcode::I32X4WidenHighI16X8U},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""},
+#line 443 "src/lexer-keywords.txt"
+      {"i8x16.eq", TokenType::Compare, Opcode::I8X16Eq},
+      {""}, {""}, {""},
+#line 213 "src/lexer-keywords.txt"
+      {"i16x8.widen_low_i8x16_s", TokenType::Unary, Opcode::I16X8WidenLowI8X16S},
+#line 178 "src/lexer-keywords.txt"
+      {"i16x8.avgr_u", TokenType::Binary, Opcode::I16X8AvgrU},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 171 "src/lexer-keywords.txt"
+      {"grow_memory", TokenType::MemoryGrow, Opcode::MemoryGrow},
+      {""}, {""},
+#line 214 "src/lexer-keywords.txt"
+      {"i16x8.widen_low_i8x16_u", TokenType::Unary, Opcode::I16X8WidenLowI8X16U},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 180 "src/lexer-keywords.txt"
+      {"i16x8.eq", TokenType::Compare, Opcode::I16X8Eq},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""},
+#line 458 "src/lexer-keywords.txt"
+      {"i8x16.narrow_i16x8_s", TokenType::Binary, Opcode::I8X16NarrowI16X8S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 459 "src/lexer-keywords.txt"
+      {"i8x16.narrow_i16x8_u", TokenType::Binary, Opcode::I8X16NarrowI16X8U},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 359 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I64AtomicRmwCmpxchg},
+#line 236 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.cmpxchg", TokenType::AtomicRmwCmpxchg, Opcode::I32AtomicRmwCmpxchg},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""},
+#line 460 "src/lexer-keywords.txt"
+      {"i8x16.neg", TokenType::Unary, Opcode::I8X16Neg},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+#line 200 "src/lexer-keywords.txt"
+      {"i16x8.neg", TokenType::Unary, Opcode::I16X8Neg},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""},
+#line 211 "src/lexer-keywords.txt"
+      {"i16x8.widen_high_i8x16_s", TokenType::Unary, Opcode::I16X8WidenHighI8X16S},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""},
+#line 212 "src/lexer-keywords.txt"
+      {"i16x8.widen_high_i8x16_u", TokenType::Unary, Opcode::I16X8WidenHighI8X16U},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""}, {""},
+      {""}, {""}, {""}, {""},
+#line 362 "src/lexer-keywords.txt"
+      {"i64.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I64AtomicRmwXchg},
+#line 239 "src/lexer-keywords.txt"
+      {"i32.atomic.rmw.xchg", TokenType::AtomicRmw, Opcode::I32AtomicRmwXchg}
+    };
+
+  if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH)
+    {
+      unsigned int key = hash (str, len);
+
+      if (key <= MAX_HASH_VALUE)
+        {
+          const char *s = wordlist[key].name;
+
+          if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0')
+            return &wordlist[key];
+        }
+    }
+  return 0;
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.c b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.c
new file mode 100644 (file)
index 0000000..63ab825
--- /dev/null
@@ -0,0 +1,188 @@
+/* Generated from 'wasm2c.c.tmpl' by wasm2c_tmpl.py, do not edit! */
+const char SECTION_NAME(includes)[] =
+"/* Automically generated by wasm2c */\n"
+"#include <math.h>\n"
+"#include <string.h>\n"
+;
+
+const char SECTION_NAME(declarations)[] =
+"#define UNLIKELY(x) __builtin_expect(!!(x), 0)\n"
+"#define LIKELY(x) __builtin_expect(!!(x), 1)\n"
+"\n"
+"#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0)\n"
+"\n"
+"#define FUNC_PROLOGUE                                            \\\n"
+"  if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \\\n"
+"    TRAP(EXHAUSTION)\n"
+"\n"
+"#define FUNC_EPILOGUE --wasm_rt_call_stack_depth\n"
+"\n"
+"#define UNREACHABLE TRAP(UNREACHABLE)\n"
+"\n"
+"#define CALL_INDIRECT(table, t, ft, x, ...)          \\\n"
+"  (LIKELY((x) < table.size && table.data[x].func &&  \\\n"
+"          table.data[x].func_type == func_types[ft]) \\\n"
+"       ? ((t)table.data[x].func)(__VA_ARGS__)        \\\n"
+"       : TRAP(CALL_INDIRECT))\n"
+"\n"
+"#if WASM_RT_MEMCHECK_SIGNAL_HANDLER\n"
+"#define MEMCHECK(mem, a, t)\n"
+"#else\n"
+"#define MEMCHECK(mem, a, t)  \\\n"
+"  if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)\n"
+"#endif\n"
+"\n"
+"#if WABT_BIG_ENDIAN\n"
+"static inline void load_data(void *dest, const void *src, size_t n) {\n"
+"  size_t i = 0;\n"
+"  u8 *dest_chars = dest;\n"
+"  memcpy(dest, src, n);\n"
+"  for (i = 0; i < (n>>1); i++) {\n"
+"    u8 cursor = dest_chars[i];\n"
+"    dest_chars[i] = dest_chars[n - i - 1];\n"
+"    dest_chars[n - i - 1] = cursor;\n"
+"  }\n"
+"}\n"
+"#define LOAD_DATA(m, o, i, s) load_data(&(m.data[m.size - o - s]), i, s)\n"
+"#define DEFINE_LOAD(name, t1, t2, t3)                                                 \\\n"
+"  static inline t3 name(wasm_rt_memory_t* mem, u64 addr) {                            \\\n"
+"    MEMCHECK(mem, addr, t1);                                                          \\\n"
+"    t1 result;                                                                        \\\n"
+"    __builtin_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], sizeof(t1)); \\\n"
+"    return (t3)(t2)result;                                                            \\\n"
+"  }\n"
+"\n"
+"#define DEFINE_STORE(name, t1, t2)                                                     \\\n"
+"  static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) {                 \\\n"
+"    MEMCHECK(mem, addr, t1);                                                           \\\n"
+"    t1 wrapped = (t1)value;                                                            \\\n"
+"    __builtin_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, sizeof(t1)); \\\n"
+"  }\n"
+"#else\n"
+"static inline void load_data(void *dest, const void *src, size_t n) {\n"
+"  memcpy(dest, src, n);\n"
+"}\n"
+"#define LOAD_DATA(m, o, i, s) load_data(&(m.data[o]), i, s)\n"
+"#define DEFINE_LOAD(name, t1, t2, t3)                        \\\n"
+"  static inline t3 name(wasm_rt_memory_t* mem, u64 addr) {   \\\n"
+"    MEMCHECK(mem, addr, t1);                                 \\\n"
+"    t1 result;                                               \\\n"
+"    __builtin_memcpy(&result, &mem->data[addr], sizeof(t1)); \\\n"
+"    return (t3)(t2)result;                                   \\\n"
+"  }\n"
+"\n"
+"#define DEFINE_STORE(name, t1, t2)                                     \\\n"
+"  static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \\\n"
+"    MEMCHECK(mem, addr, t1);                                           \\\n"
+"    t1 wrapped = (t1)value;                                            \\\n"
+"    __builtin_memcpy(&mem->data[addr], &wrapped, sizeof(t1));          \\\n"
+"  }\n"
+"#endif\n"
+"\n"
+"DEFINE_LOAD(i32_load, u32, u32, u32);\n"
+"DEFINE_LOAD(i64_load, u64, u64, u64);\n"
+"DEFINE_LOAD(f32_load, f32, f32, f32);\n"
+"DEFINE_LOAD(f64_load, f64, f64, f64);\n"
+"DEFINE_LOAD(i32_load8_s, s8, s32, u32);\n"
+"DEFINE_LOAD(i64_load8_s, s8, s64, u64);\n"
+"DEFINE_LOAD(i32_load8_u, u8, u32, u32);\n"
+"DEFINE_LOAD(i64_load8_u, u8, u64, u64);\n"
+"DEFINE_LOAD(i32_load16_s, s16, s32, u32);\n"
+"DEFINE_LOAD(i64_load16_s, s16, s64, u64);\n"
+"DEFINE_LOAD(i32_load16_u, u16, u32, u32);\n"
+"DEFINE_LOAD(i64_load16_u, u16, u64, u64);\n"
+"DEFINE_LOAD(i64_load32_s, s32, s64, u64);\n"
+"DEFINE_LOAD(i64_load32_u, u32, u64, u64);\n"
+"DEFINE_STORE(i32_store, u32, u32);\n"
+"DEFINE_STORE(i64_store, u64, u64);\n"
+"DEFINE_STORE(f32_store, f32, f32);\n"
+"DEFINE_STORE(f64_store, f64, f64);\n"
+"DEFINE_STORE(i32_store8, u8, u32);\n"
+"DEFINE_STORE(i32_store16, u16, u32);\n"
+"DEFINE_STORE(i64_store8, u8, u64);\n"
+"DEFINE_STORE(i64_store16, u16, u64);\n"
+"DEFINE_STORE(i64_store32, u32, u64);\n"
+"\n"
+"#define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32)\n"
+"#define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64)\n"
+"#define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32)\n"
+"#define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64)\n"
+"#define I32_POPCNT(x) (__builtin_popcount(x))\n"
+"#define I64_POPCNT(x) (__builtin_popcountll(x))\n"
+"\n"
+"#define DIV_S(ut, min, x, y)                                 \\\n"
+"   ((UNLIKELY((y) == 0)) ?                TRAP(DIV_BY_ZERO)  \\\n"
+"  : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \\\n"
+"  : (ut)((x) / (y)))\n"
+"\n"
+"#define REM_S(ut, min, x, y)                                \\\n"
+"   ((UNLIKELY((y) == 0)) ?                TRAP(DIV_BY_ZERO) \\\n"
+"  : (UNLIKELY((x) == min && (y) == -1)) ? 0                 \\\n"
+"  : (ut)((x) % (y)))\n"
+"\n"
+"#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y)\n"
+"#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y)\n"
+"#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y)\n"
+"#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y)\n"
+"\n"
+"#define DIVREM_U(op, x, y) \\\n"
+"  ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y)))\n"
+"\n"
+"#define DIV_U(x, y) DIVREM_U(/, x, y)\n"
+"#define REM_U(x, y) DIVREM_U(%, x, y)\n"
+"\n"
+"#define ROTL(x, y, mask) \\\n"
+"  (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask))))\n"
+"#define ROTR(x, y, mask) \\\n"
+"  (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask))))\n"
+"\n"
+"#define I32_ROTL(x, y) ROTL(x, y, 31)\n"
+"#define I64_ROTL(x, y) ROTL(x, y, 63)\n"
+"#define I32_ROTR(x, y) ROTR(x, y, 31)\n"
+"#define I64_ROTR(x, y) ROTR(x, y, 63)\n"
+"\n"
+"#define FMIN(x, y)                                          \\\n"
+"   ((UNLIKELY((x) != (x))) ? NAN                            \\\n"
+"  : (UNLIKELY((y) != (y))) ? NAN                            \\\n"
+"  : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \\\n"
+"  : (x < y) ? x : y)\n"
+"\n"
+"#define FMAX(x, y)                                          \\\n"
+"   ((UNLIKELY((x) != (x))) ? NAN                            \\\n"
+"  : (UNLIKELY((y) != (y))) ? NAN                            \\\n"
+"  : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \\\n"
+"  : (x > y) ? x : y)\n"
+"\n"
+"#define TRUNC_S(ut, st, ft, min, minop, max, x)                             \\\n"
+"  ((UNLIKELY((x) != (x)))                        ? TRAP(INVALID_CONVERSION) \\\n"
+"   : (UNLIKELY(!((x)minop(min) && (x) < (max)))) ? TRAP(INT_OVERFLOW)       \\\n"
+"                                                 : (ut)(st)(x))\n"
+"\n"
+"#define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, (f32)INT32_MIN, >=, 2147483648.f, x)\n"
+"#define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, (f32)INT64_MIN, >=, (f32)INT64_MAX, x)\n"
+"#define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, -2147483649., >, 2147483648., x)\n"
+"#define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, (f64)INT64_MIN, >=, (f64)INT64_MAX, x)\n"
+"\n"
+"#define TRUNC_U(ut, ft, max, x)                                            \\\n"
+"  ((UNLIKELY((x) != (x)))                       ? TRAP(INVALID_CONVERSION) \\\n"
+"   : (UNLIKELY(!((x) > (ft)-1 && (x) < (max)))) ? TRAP(INT_OVERFLOW)       \\\n"
+"                                                : (ut)(x))\n"
+"\n"
+"#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, 4294967296.f, x)\n"
+"#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, (f32)UINT64_MAX, x)\n"
+"#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, 4294967296.,  x)\n"
+"#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, (f64)UINT64_MAX, x)\n"
+"\n"
+"#define DEFINE_REINTERPRET(name, t1, t2)  \\\n"
+"  static inline t2 name(t1 x) {           \\\n"
+"    t2 result;                            \\\n"
+"    memcpy(&result, &x, sizeof(result));  \\\n"
+"    return result;                        \\\n"
+"  }\n"
+"\n"
+"DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32)\n"
+"DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32)\n"
+"DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64)\n"
+"DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64)\n"
+"\n"
+;
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/prebuilt/wasm2c.include.h
new file mode 100644 (file)
index 0000000..4ba2475
--- /dev/null
@@ -0,0 +1,39 @@
+/* Generated from 'wasm2c.h.tmpl' by wasm2c_tmpl.py, do not edit! */
+const char SECTION_NAME(top)[] =
+"/* Automically generated by wasm2c */\n"
+"#ifdef __cplusplus\n"
+"extern \"C\" {\n"
+"#endif\n"
+"\n"
+"#include <stdint.h>\n"
+"\n"
+"#include \"wasm-rt.h\"\n"
+"\n"
+"#ifndef WASM_RT_MODULE_PREFIX\n"
+"#define WASM_RT_MODULE_PREFIX\n"
+"#endif\n"
+"\n"
+"#define WASM_RT_PASTE_(x, y) x ## y\n"
+"#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y)\n"
+"#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x)\n"
+"\n"
+"/* TODO(binji): only use stdint.h types in header */\n"
+"typedef uint8_t u8;\n"
+"typedef int8_t s8;\n"
+"typedef uint16_t u16;\n"
+"typedef int16_t s16;\n"
+"typedef uint32_t u32;\n"
+"typedef int32_t s32;\n"
+"typedef uint64_t u64;\n"
+"typedef int64_t s64;\n"
+"typedef float f32;\n"
+"typedef double f64;\n"
+"\n"
+"extern void WASM_RT_ADD_PREFIX(init)(void);\n"
+;
+
+const char SECTION_NAME(bottom)[] =
+"#ifdef __cplusplus\n"
+"}\n"
+"#endif\n"
+;
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/range.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/range.h
new file mode 100644 (file)
index 0000000..fa0310e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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_RANGE_H_
+#define WABT_RANGE_H_
+
+namespace wabt {
+
+template <typename T>
+struct Range {
+  Range() : start(0), end(0) {}
+  Range(T start, T end) : start(start), end(end) {}
+  T start;
+  T end;
+
+  T size() const { return end - start; }
+};
+
+typedef Range<Offset> OffsetRange;
+typedef Range<int> ColumnRange;
+
+}  // namespace wabt
+
+#endif  // WABT_RANGE_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.cc
new file mode 100644 (file)
index 0000000..46f397e
--- /dev/null
@@ -0,0 +1,589 @@
+/*
+ * 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/resolve-names.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include "src/cast.h"
+#include "src/expr-visitor.h"
+#include "src/ir.h"
+#include "src/wast-lexer.h"
+
+namespace wabt {
+
+namespace {
+
+class NameResolver : public ExprVisitor::DelegateNop {
+ public:
+  NameResolver(Script* script, Errors* errors);
+
+  Result VisitModule(Module* module);
+  Result VisitScript(Script* script);
+
+  // 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 OnCallIndirectExpr(CallIndirectExpr*) override;
+  Result OnCatchExpr(TryExpr*, Catch*) override;
+  Result OnDelegateExpr(TryExpr*) 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 OnRefFuncExpr(RefFuncExpr*) override;
+  Result BeginTryExpr(TryExpr*) override;
+  Result EndTryExpr(TryExpr*) override;
+  Result OnThrowExpr(ThrowExpr*) override;
+  Result OnRethrowExpr(RethrowExpr*) override;
+
+ private:
+  void PrintError(const Location* loc, const char* fmt, ...);
+  void PushLabel(const std::string& label);
+  void PopLabel();
+  void CheckDuplicateBindings(const BindingHash* bindings, const char* desc);
+  void PrintDuplicateBindingsError(const BindingHash::value_type&,
+                                   const BindingHash::value_type&,
+                                   const char* desc);
+  void ResolveLabelVar(Var* var);
+  void ResolveVar(const BindingHash* bindings, Var* var, const char* desc);
+  void ResolveFuncVar(Var* var);
+  void ResolveGlobalVar(Var* var);
+  void ResolveFuncTypeVar(Var* var);
+  void ResolveTableVar(Var* var);
+  void ResolveMemoryVar(Var* var);
+  void ResolveEventVar(Var* var);
+  void ResolveDataSegmentVar(Var* var);
+  void ResolveElemSegmentVar(Var* var);
+  void ResolveLocalVar(Var* var);
+  void ResolveBlockDeclarationVar(BlockDeclaration* decl);
+  void VisitFunc(Func* func);
+  void VisitExport(Export* export_);
+  void VisitGlobal(Global* global);
+  void VisitEvent(Event* event);
+  void VisitElemSegment(ElemSegment* segment);
+  void VisitDataSegment(DataSegment* segment);
+  void VisitScriptModule(ScriptModule* script_module);
+  void VisitCommand(Command* command);
+
+  Errors* errors_ = nullptr;
+  Script* script_ = nullptr;
+  Module* current_module_ = nullptr;
+  Func* current_func_ = nullptr;
+  ExprVisitor visitor_;
+  std::vector<std::string> labels_;
+  Result result_ = Result::Ok;
+};
+
+NameResolver::NameResolver(Script* script, Errors* errors)
+    : errors_(errors),
+      script_(script),
+      visitor_(this) {}
+
+}  // end anonymous namespace
+
+void WABT_PRINTF_FORMAT(3, 4) NameResolver::PrintError(const Location* loc,
+                                                       const char* format,
+                                                       ...) {
+  result_ = Result::Error;
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  errors_->emplace_back(ErrorLevel::Error, *loc, buffer);
+}
+
+void NameResolver::PushLabel(const std::string& label) {
+  labels_.push_back(label);
+}
+
+void NameResolver::PopLabel() {
+  labels_.pop_back();
+}
+
+void NameResolver::CheckDuplicateBindings(const BindingHash* bindings,
+                                          const char* desc) {
+  bindings->FindDuplicates([this, desc](const BindingHash::value_type& a,
+                                        const BindingHash::value_type& b) {
+    PrintDuplicateBindingsError(a, b, desc);
+  });
+}
+
+void NameResolver::PrintDuplicateBindingsError(const BindingHash::value_type& a,
+                                               const BindingHash::value_type& b,
+                                               const char* desc) {
+  // Choose the location that is later in the file.
+  const Location& a_loc = a.second.loc;
+  const Location& b_loc = b.second.loc;
+  const Location& loc = a_loc.line > b_loc.line ? a_loc : b_loc;
+  PrintError(&loc, "redefinition of %s \"%s\"", desc, a.first.c_str());
+}
+
+void NameResolver::ResolveLabelVar(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()) {
+        var->set_index(labels_.size() - i - 1);
+        return;
+      }
+    }
+    PrintError(&var->loc, "undefined label variable \"%s\"",
+               var->name().c_str());
+  }
+}
+
+void NameResolver::ResolveVar(const BindingHash* bindings,
+                              Var* var,
+                              const char* desc) {
+  if (var->is_name()) {
+    Index index = bindings->FindIndex(*var);
+    if (index == kInvalidIndex) {
+      PrintError(&var->loc, "undefined %s variable \"%s\"", desc,
+                 var->name().c_str());
+      return;
+    }
+
+    var->set_index(index);
+  }
+}
+
+void NameResolver::ResolveFuncVar(Var* var) {
+  ResolveVar(&current_module_->func_bindings, var, "function");
+}
+
+void NameResolver::ResolveGlobalVar(Var* var) {
+  ResolveVar(&current_module_->global_bindings, var, "global");
+}
+
+void NameResolver::ResolveFuncTypeVar(Var* var) {
+  ResolveVar(&current_module_->type_bindings, var, "type");
+}
+
+void NameResolver::ResolveTableVar(Var* var) {
+  ResolveVar(&current_module_->table_bindings, var, "table");
+}
+
+void NameResolver::ResolveMemoryVar(Var* var) {
+  ResolveVar(&current_module_->memory_bindings, var, "memory");
+}
+
+void NameResolver::ResolveEventVar(Var* var) {
+  ResolveVar(&current_module_->event_bindings, var, "event");
+}
+
+void NameResolver::ResolveDataSegmentVar(Var* var) {
+  ResolveVar(&current_module_->data_segment_bindings, var, "data segment");
+}
+
+void NameResolver::ResolveElemSegmentVar(Var* var) {
+  ResolveVar(&current_module_->elem_segment_bindings, var, "elem segment");
+}
+
+void NameResolver::ResolveLocalVar(Var* var) {
+  if (var->is_name()) {
+    if (!current_func_) {
+      return;
+    }
+
+    Index index = current_func_->GetLocalIndex(*var);
+    if (index == kInvalidIndex) {
+      PrintError(&var->loc, "undefined local variable \"%s\"",
+                 var->name().c_str());
+      return;
+    }
+
+    var->set_index(index);
+  }
+}
+
+void NameResolver::ResolveBlockDeclarationVar(BlockDeclaration* decl) {
+  if (decl->has_func_type) {
+    ResolveFuncTypeVar(&decl->type_var);
+  }
+}
+
+Result NameResolver::BeginBlockExpr(BlockExpr* expr) {
+  PushLabel(expr->block.label);
+  ResolveBlockDeclarationVar(&expr->block.decl);
+  return Result::Ok;
+}
+
+Result NameResolver::EndBlockExpr(BlockExpr* expr) {
+  PopLabel();
+  return Result::Ok;
+}
+
+Result NameResolver::BeginLoopExpr(LoopExpr* expr) {
+  PushLabel(expr->block.label);
+  ResolveBlockDeclarationVar(&expr->block.decl);
+  return Result::Ok;
+}
+
+Result NameResolver::EndLoopExpr(LoopExpr* expr) {
+  PopLabel();
+  return Result::Ok;
+}
+
+Result NameResolver::OnBrExpr(BrExpr* expr) {
+  ResolveLabelVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnBrIfExpr(BrIfExpr* expr) {
+  ResolveLabelVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnBrTableExpr(BrTableExpr* expr) {
+  for (Var& target : expr->targets)
+    ResolveLabelVar(&target);
+  ResolveLabelVar(&expr->default_target);
+  return Result::Ok;
+}
+
+Result NameResolver::OnCallExpr(CallExpr* expr) {
+  ResolveFuncVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnCallIndirectExpr(CallIndirectExpr* expr) {
+  if (expr->decl.has_func_type) {
+    ResolveFuncTypeVar(&expr->decl.type_var);
+  }
+  ResolveTableVar(&expr->table);
+  return Result::Ok;
+}
+
+Result NameResolver::OnReturnCallExpr(ReturnCallExpr* expr) {
+  ResolveFuncVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) {
+  if (expr->decl.has_func_type) {
+    ResolveFuncTypeVar(&expr->decl.type_var);
+  }
+  ResolveTableVar(&expr->table);
+  return Result::Ok;
+}
+
+Result NameResolver::OnGlobalGetExpr(GlobalGetExpr* expr) {
+  ResolveGlobalVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnGlobalSetExpr(GlobalSetExpr* expr) {
+  ResolveGlobalVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::BeginIfExpr(IfExpr* expr) {
+  PushLabel(expr->true_.label);
+  ResolveBlockDeclarationVar(&expr->true_.decl);
+  return Result::Ok;
+}
+
+Result NameResolver::EndIfExpr(IfExpr* expr) {
+  PopLabel();
+  return Result::Ok;
+}
+
+Result NameResolver::OnLocalGetExpr(LocalGetExpr* expr) {
+  ResolveLocalVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnLocalSetExpr(LocalSetExpr* expr) {
+  ResolveLocalVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnLocalTeeExpr(LocalTeeExpr* expr) {
+  ResolveLocalVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnDataDropExpr(DataDropExpr* expr) {
+  ResolveDataSegmentVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnMemoryInitExpr(MemoryInitExpr* expr) {
+  ResolveDataSegmentVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnElemDropExpr(ElemDropExpr* expr) {
+  ResolveElemSegmentVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnTableCopyExpr(TableCopyExpr* expr) {
+  ResolveTableVar(&expr->dst_table);
+  ResolveTableVar(&expr->src_table);
+  return Result::Ok;
+}
+
+Result NameResolver::OnTableInitExpr(TableInitExpr* expr) {
+  ResolveElemSegmentVar(&expr->segment_index);
+  ResolveTableVar(&expr->table_index);
+  return Result::Ok;
+}
+
+Result NameResolver::OnTableGetExpr(TableGetExpr* expr) {
+  ResolveTableVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnTableSetExpr(TableSetExpr* expr) {
+  ResolveTableVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnTableGrowExpr(TableGrowExpr* expr) {
+  ResolveTableVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnTableSizeExpr(TableSizeExpr* expr) {
+  ResolveTableVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnTableFillExpr(TableFillExpr* expr) {
+  ResolveTableVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnRefFuncExpr(RefFuncExpr* expr) {
+  ResolveFuncVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::BeginTryExpr(TryExpr* expr) {
+  PushLabel(expr->block.label);
+  ResolveBlockDeclarationVar(&expr->block.decl);
+  return Result::Ok;
+}
+
+Result NameResolver::EndTryExpr(TryExpr*) {
+  PopLabel();
+  return Result::Ok;
+}
+
+Result NameResolver::OnCatchExpr(TryExpr*, Catch* catch_) {
+  if (!catch_->IsCatchAll()) {
+    ResolveEventVar(&catch_->var);
+  }
+  return Result::Ok;
+}
+
+Result NameResolver::OnDelegateExpr(TryExpr* expr) {
+  ResolveLabelVar(&expr->delegate_target);
+  return Result::Ok;
+}
+
+Result NameResolver::OnThrowExpr(ThrowExpr* expr) {
+  ResolveEventVar(&expr->var);
+  return Result::Ok;
+}
+
+Result NameResolver::OnRethrowExpr(RethrowExpr* expr) {
+  // Note: the variable refers to corresponding (enclosing) catch, using the try
+  // block label for context.
+  ResolveLabelVar(&expr->var);
+  return Result::Ok;
+}
+
+void NameResolver::VisitFunc(Func* func) {
+  current_func_ = func;
+  if (func->decl.has_func_type) {
+    ResolveFuncTypeVar(&func->decl.type_var);
+  }
+
+  func->bindings.FindDuplicates(
+      [=](const BindingHash::value_type& a, const BindingHash::value_type& b) {
+        const char* desc =
+            (a.second.index < func->GetNumParams()) ? "parameter" : "local";
+        PrintDuplicateBindingsError(a, b, desc);
+      });
+
+  visitor_.VisitFunc(func);
+  current_func_ = nullptr;
+}
+
+void NameResolver::VisitExport(Export* export_) {
+  switch (export_->kind) {
+    case ExternalKind::Func:
+      ResolveFuncVar(&export_->var);
+      break;
+
+    case ExternalKind::Table:
+      ResolveTableVar(&export_->var);
+      break;
+
+    case ExternalKind::Memory:
+      ResolveMemoryVar(&export_->var);
+      break;
+
+    case ExternalKind::Global:
+      ResolveGlobalVar(&export_->var);
+      break;
+
+    case ExternalKind::Event:
+      ResolveEventVar(&export_->var);
+      break;
+  }
+}
+
+void NameResolver::VisitGlobal(Global* global) {
+  visitor_.VisitExprList(global->init_expr);
+}
+
+void NameResolver::VisitEvent(Event* event) {
+  if (event->decl.has_func_type) {
+    ResolveFuncTypeVar(&event->decl.type_var);
+  }
+}
+
+void NameResolver::VisitElemSegment(ElemSegment* segment) {
+  ResolveTableVar(&segment->table_var);
+  visitor_.VisitExprList(segment->offset);
+  for (ElemExpr& elem_expr : segment->elem_exprs) {
+    if (elem_expr.kind == ElemExprKind::RefFunc) {
+      ResolveFuncVar(&elem_expr.var);
+    }
+  }
+}
+
+void NameResolver::VisitDataSegment(DataSegment* segment) {
+  ResolveMemoryVar(&segment->memory_var);
+  visitor_.VisitExprList(segment->offset);
+}
+
+Result NameResolver::VisitModule(Module* module) {
+  current_module_ = module;
+  CheckDuplicateBindings(&module->elem_segment_bindings, "elem");
+  CheckDuplicateBindings(&module->func_bindings, "function");
+  CheckDuplicateBindings(&module->global_bindings, "global");
+  CheckDuplicateBindings(&module->type_bindings, "type");
+  CheckDuplicateBindings(&module->table_bindings, "table");
+  CheckDuplicateBindings(&module->memory_bindings, "memory");
+  CheckDuplicateBindings(&module->event_bindings, "event");
+
+  for (Func* func : module->funcs)
+    VisitFunc(func);
+  for (Export* export_ : module->exports)
+    VisitExport(export_);
+  for (Global* global : module->globals)
+    VisitGlobal(global);
+  for (Event* event : module->events)
+    VisitEvent(event);
+  for (ElemSegment* elem_segment : module->elem_segments)
+    VisitElemSegment(elem_segment);
+  for (DataSegment* data_segment : module->data_segments)
+    VisitDataSegment(data_segment);
+  for (Var* start : module->starts)
+    ResolveFuncVar(start);
+  current_module_ = nullptr;
+  return result_;
+}
+
+void NameResolver::VisitScriptModule(ScriptModule* script_module) {
+  if (auto* tsm = dyn_cast<TextScriptModule>(script_module)) {
+    VisitModule(&tsm->module);
+  }
+}
+
+void NameResolver::VisitCommand(Command* command) {
+  switch (command->type) {
+    case CommandType::Module:
+      VisitModule(&cast<ModuleCommand>(command)->module);
+      break;
+
+    case CommandType::Action:
+    case CommandType::AssertReturn:
+    case CommandType::AssertTrap:
+    case CommandType::AssertExhaustion:
+    case CommandType::Register:
+      /* Don't resolve a module_var, since it doesn't really behave like other
+       * vars. You can't reference a module by index. */
+      break;
+
+    case CommandType::AssertMalformed:
+      /* Malformed modules should not be text; the whole point of this
+       * assertion is to test for malformed binary modules. */
+      break;
+
+    case CommandType::AssertInvalid: {
+      auto* assert_invalid_command = cast<AssertInvalidCommand>(command);
+      /* The module may be invalid because the names cannot be resolved; we
+       * don't want to print errors or fail if that's the case, but we still
+       * should try to resolve names when possible. */
+      Errors errors;
+      NameResolver new_resolver(script_, &errors);
+      new_resolver.VisitScriptModule(assert_invalid_command->module.get());
+      break;
+    }
+
+    case CommandType::AssertUnlinkable:
+      VisitScriptModule(cast<AssertUnlinkableCommand>(command)->module.get());
+      break;
+
+    case CommandType::AssertUninstantiable:
+      VisitScriptModule(
+          cast<AssertUninstantiableCommand>(command)->module.get());
+      break;
+  }
+}
+
+Result NameResolver::VisitScript(Script* script) {
+  for (const std::unique_ptr<Command>& command : script->commands)
+    VisitCommand(command.get());
+  return result_;
+}
+
+Result ResolveNamesModule(Module* module, Errors* errors) {
+  NameResolver resolver(nullptr, errors);
+  return resolver.VisitModule(module);
+}
+
+Result ResolveNamesScript(Script* script, Errors* errors) {
+  NameResolver resolver(script, errors);
+  return resolver.VisitScript(script);
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/resolve-names.h
new file mode 100644 (file)
index 0000000..04f2115
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * 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_RESOLVE_NAMES_H_
+#define WABT_RESOLVE_NAMES_H_
+
+#include "src/common.h"
+#include "src/error.h"
+
+namespace wabt {
+
+struct Module;
+struct Script;
+
+Result ResolveNamesModule(Module*, Errors*);
+Result ResolveNamesScript(Script*, Errors*);
+
+}  // namespace wabt
+
+#endif /* WABT_RESOLVE_NAMES_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/result.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/result.h
new file mode 100644 (file)
index 0000000..a40faab
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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_RESULT_H_
+#define WABT_RESULT_H_
+
+namespace wabt {
+
+struct Result {
+  enum Enum {
+    Ok,
+    Error,
+  };
+
+  Result() : Result(Ok) {}
+  Result(Enum e) : enum_(e) {}
+  operator Enum() const { return enum_; }
+  Result& operator|=(Result rhs);
+
+ private:
+  Enum enum_;
+};
+
+inline Result operator|(Result lhs, Result rhs) {
+  return (lhs == Result::Error || rhs == Result::Error) ? Result::Error
+                                                        : Result::Ok;
+}
+
+inline Result& Result::operator|=(Result rhs) {
+  enum_ = *this | rhs;
+  return *this;
+}
+
+inline bool Succeeded(Result result) {
+  return result == Result::Ok;
+}
+inline bool Failed(Result result) {
+  return result == Result::Error;
+}
+
+#define CHECK_RESULT(expr)          \
+  do {                              \
+    if (Failed(expr)) {             \
+      return ::wabt::Result::Error; \
+    }                               \
+  } while (0)
+
+}  // namespace wabt
+
+#endif  // WABT_RESULT_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.cc
new file mode 100644 (file)
index 0000000..5d3b8ac
--- /dev/null
@@ -0,0 +1,1208 @@
+/*
+ * 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/shared-validator.h"
+
+#include <algorithm>
+#include <cinttypes>
+#include <limits>
+
+namespace wabt {
+
+TypeVector SharedValidator::ToTypeVector(Index count, const Type* types) {
+  return TypeVector(&types[0], &types[count]);
+}
+
+SharedValidator::SharedValidator(Errors* errors, const ValidateOptions& options)
+    : options_(options), errors_(errors), typechecker_(options.features) {
+  typechecker_.set_error_callback(
+      [this](const char* msg) { OnTypecheckerError(msg); });
+}
+
+Result WABT_PRINTF_FORMAT(3, 4) SharedValidator::PrintError(const Location& loc,
+                                                            const char* format,
+                                                            ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  errors_->emplace_back(ErrorLevel::Error, loc, buffer);
+  return Result::Error;
+}
+
+void SharedValidator::OnTypecheckerError(const char* msg) {
+  PrintError(*expr_loc_, "%s", msg);
+}
+
+Result SharedValidator::OnFuncType(const Location& loc,
+                                   Index param_count,
+                                   const Type* param_types,
+                                   Index result_count,
+                                   const Type* result_types) {
+  Result result = Result::Ok;
+  if (!options_.features.multi_value_enabled() && result_count > 1) {
+    result |=
+        PrintError(loc, "multiple result values not currently supported.");
+  }
+  func_types_.emplace(num_types_++,
+                      FuncType{ToTypeVector(param_count, param_types),
+                               ToTypeVector(result_count, result_types)});
+  return result;
+}
+
+Result SharedValidator::OnStructType(const Location&,
+                                     Index field_count,
+                                     TypeMut* fields) {
+  struct_types_.emplace(num_types_++, StructType{TypeMutVector(
+                                          &fields[0], &fields[field_count])});
+  return Result::Ok;
+}
+
+Result SharedValidator::OnArrayType(const Location&, TypeMut field) {
+  array_types_.emplace(num_types_++, ArrayType{field});
+  return Result::Ok;
+}
+
+Result SharedValidator::OnFunction(const Location& loc, Var sig_var) {
+  Result result = Result::Ok;
+  FuncType type;
+  result |= CheckFuncTypeIndex(sig_var, &type);
+  funcs_.push_back(type);
+  return result;
+}
+
+Result SharedValidator::CheckLimits(const Location& loc,
+                                    const Limits& limits,
+                                    uint64_t absolute_max,
+                                    const char* desc) {
+  Result result = Result::Ok;
+  if (limits.initial > absolute_max) {
+    result |=
+        PrintError(loc, "initial %s (%" PRIu64 ") must be <= (%" PRIu64 ")",
+                   desc, limits.initial, absolute_max);
+  }
+
+  if (limits.has_max) {
+    if (limits.max > absolute_max) {
+      result |= PrintError(loc, "max %s (%" PRIu64 ") must be <= (%" PRIu64 ")",
+                           desc, limits.max, absolute_max);
+    }
+
+    if (limits.max < limits.initial) {
+      result |= PrintError(
+          loc, "max %s (%" PRIu64 ") must be >= initial %s (%" PRIu64 ")", desc,
+          limits.max, desc, limits.initial);
+    }
+  }
+  return result;
+}
+
+Result SharedValidator::OnTable(const Location& loc,
+                                Type elem_type,
+                                const Limits& limits) {
+  Result result = Result::Ok;
+  if (tables_.size() > 0 && !options_.features.reference_types_enabled()) {
+    result |= PrintError(loc, "only one table allowed");
+  }
+  result |= CheckLimits(loc, limits, UINT32_MAX, "elems");
+
+  if (limits.is_shared) {
+    result |= PrintError(loc, "tables may not be shared");
+  }
+  if (elem_type != Type::FuncRef &&
+      !options_.features.reference_types_enabled()) {
+    result |= PrintError(loc, "tables must have funcref type");
+  }
+  if (!elem_type.IsRef()) {
+    result |= PrintError(loc, "tables must have reference types");
+  }
+
+  tables_.push_back(TableType{elem_type, limits});
+  return result;
+}
+
+Result SharedValidator::OnMemory(const Location& loc, const Limits& limits) {
+  Result result = Result::Ok;
+  if (memories_.size() > 0) {
+    result |= PrintError(loc, "only one memory block allowed");
+  }
+  result |= CheckLimits(loc, limits, WABT_MAX_PAGES, "pages");
+
+  if (limits.is_shared) {
+    if (!options_.features.threads_enabled()) {
+      result |= PrintError(loc, "memories may not be shared");
+    } else if (!limits.has_max) {
+      result |= PrintError(loc, "shared memories must have max sizes");
+    }
+  }
+
+  memories_.push_back(MemoryType{limits});
+  return result;
+}
+
+Result SharedValidator::OnGlobalImport(const Location& loc,
+                                       Type type,
+                                       bool mutable_) {
+  Result result = Result::Ok;
+  if (mutable_ && !options_.features.mutable_globals_enabled()) {
+    result |= PrintError(loc, "mutable globals cannot be imported");
+  }
+  globals_.push_back(GlobalType{type, mutable_});
+  ++num_imported_globals_;
+  return result;
+}
+
+Result SharedValidator::OnGlobal(const Location& loc,
+                                 Type type,
+                                 bool mutable_) {
+  globals_.push_back(GlobalType{type, mutable_});
+  return Result::Ok;
+}
+
+Result SharedValidator::CheckType(const Location& loc,
+                                  Type actual,
+                                  Type expected,
+                                  const char* desc) {
+  if (Failed(TypeChecker::CheckType(actual, expected))) {
+    PrintError(loc, "type mismatch at %s. got %s, expected %s", desc,
+               actual.GetName(), expected.GetName());
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
+Result SharedValidator::OnGlobalInitExpr_Const(const Location& loc,
+                                               Type actual) {
+  return CheckType(loc, actual, globals_.back().type,
+                   "global initializer expression");
+}
+
+Result SharedValidator::OnGlobalInitExpr_GlobalGet(const Location& loc,
+                                                   Var ref_global_var) {
+  Result result = Result::Ok;
+  GlobalType ref_global;
+  CHECK_RESULT(CheckGlobalIndex(ref_global_var, &ref_global));
+
+  if (ref_global_var.index() >= num_imported_globals_) {
+    result |= PrintError(
+        ref_global_var.loc,
+        "initializer expression can only reference an imported global");
+  }
+
+  if (ref_global.mutable_) {
+    result |= PrintError(
+        loc, "initializer expression cannot reference a mutable global");
+  }
+
+  result |= CheckType(loc, ref_global.type, globals_.back().type,
+                      "global initializer expression");
+  return result;
+}
+
+Result SharedValidator::OnGlobalInitExpr_RefNull(const Location& loc,
+                                                 Type type) {
+  return CheckType(loc, type, globals_.back().type,
+                   "global initializer expression");
+}
+
+Result SharedValidator::OnGlobalInitExpr_RefFunc(const Location& loc,
+                                                 Var func_var) {
+  Result result = Result::Ok;
+  result |= CheckFuncIndex(func_var);
+  init_expr_funcs_.push_back(func_var);
+  result |= CheckType(loc, Type::FuncRef, globals_.back().type,
+                      "global initializer expression");
+  return result;
+}
+
+Result SharedValidator::OnGlobalInitExpr_Other(const Location& loc) {
+  return PrintError(
+      loc,
+      "invalid global initializer expression, must be a constant expression");
+}
+
+Result SharedValidator::OnEvent(const Location& loc, Var sig_var) {
+  Result result = Result::Ok;
+  FuncType type;
+  result |= CheckFuncTypeIndex(sig_var, &type);
+  if (!type.results.empty()) {
+    result |= PrintError(loc, "Event signature must have 0 results.");
+  }
+  events_.push_back(EventType{type.params});
+  return result;
+}
+
+Result SharedValidator::OnExport(const Location& loc,
+                                 ExternalKind kind,
+                                 Var item_var,
+                                 string_view name) {
+  Result result = Result::Ok;
+  auto name_str = name.to_string();
+  if (export_names_.find(name_str) != export_names_.end()) {
+    result |= PrintError(loc, "duplicate export \"" PRIstringview "\"",
+                         WABT_PRINTF_STRING_VIEW_ARG(name));
+  }
+  export_names_.insert(name_str);
+
+  switch (kind) {
+    case ExternalKind::Func:
+      result |= CheckFuncIndex(item_var);
+      break;
+
+    case ExternalKind::Table:
+      result |= CheckTableIndex(item_var);
+      break;
+
+    case ExternalKind::Memory:
+      result |= CheckMemoryIndex(item_var);
+      break;
+
+    case ExternalKind::Global:
+      result |= CheckGlobalIndex(item_var);
+      break;
+
+    case ExternalKind::Event:
+      result |= CheckEventIndex(item_var);
+      break;
+  }
+  return result;
+}
+
+Result SharedValidator::OnStart(const Location& loc, Var func_var) {
+  Result result = Result::Ok;
+  if (starts_++ > 0) {
+    result |= PrintError(loc, "only one start function allowed");
+  }
+  FuncType func_type;
+  result |= CheckFuncIndex(func_var, &func_type);
+  if (func_type.params.size() != 0) {
+    result |= PrintError(loc, "start function must be nullary");
+  }
+  if (func_type.results.size() != 0) {
+    result |= PrintError(loc, "start function must not return anything");
+  }
+  return result;
+}
+
+Result SharedValidator::OnElemSegment(const Location& loc,
+                                      Var table_var,
+                                      SegmentKind kind) {
+  Result result = Result::Ok;
+  if (kind == SegmentKind::Active) {
+    result |= CheckTableIndex(table_var);
+  }
+  elems_.push_back(ElemType{Type::Void});  // Updated in OnElemSegmentElemType.
+  return result;
+}
+
+void SharedValidator::OnElemSegmentElemType(Type elem_type) {
+  elems_.back().element = elem_type;
+}
+
+Result SharedValidator::OnElemSegmentInitExpr_Const(const Location& loc,
+                                                    Type type) {
+  return CheckType(loc, type, Type::I32, "elem segment offset");
+}
+
+Result SharedValidator::OnElemSegmentInitExpr_GlobalGet(const Location& loc,
+                                                        Var global_var) {
+  Result result = Result::Ok;
+  GlobalType ref_global;
+  result |= CheckGlobalIndex(global_var, &ref_global);
+
+  if (ref_global.mutable_) {
+    result |= PrintError(
+        loc, "initializer expression cannot reference a mutable global");
+  }
+
+  result |= CheckType(loc, ref_global.type, Type::I32, "elem segment offset");
+  return result;
+}
+
+Result SharedValidator::OnElemSegmentInitExpr_Other(const Location& loc) {
+  return PrintError(loc,
+                    "invalid elem segment offset, must be a constant "
+                    "expression; either i32.const or "
+                    "global.get.");
+}
+
+Result SharedValidator::OnElemSegmentElemExpr_RefNull(const Location& loc,
+                                                      Type type) {
+  return CheckType(loc, type, elems_.back().element, "elem expression");
+}
+
+Result SharedValidator::OnElemSegmentElemExpr_RefFunc(const Location& loc,
+                                                      Var func_var) {
+  Result result = Result::Ok;
+  result |= CheckFuncIndex(func_var);
+  declared_funcs_.insert(func_var.index());
+  return result;
+}
+
+Result SharedValidator::OnElemSegmentElemExpr_Other(const Location& loc) {
+  return PrintError(loc,
+                    "invalid elem expression expression; must be either "
+                    "ref.null or ref.func.");
+}
+
+void SharedValidator::OnDataCount(Index count) {
+  data_segments_ = count;
+}
+
+Result SharedValidator::OnDataSegment(const Location& loc,
+                                      Var memory_var,
+                                      SegmentKind kind) {
+  Result result = Result::Ok;
+  if (kind == SegmentKind::Active) {
+    result |= CheckMemoryIndex(memory_var);
+  }
+  return result;
+}
+
+Result SharedValidator::OnDataSegmentInitExpr_Const(const Location& loc,
+                                                    Type type) {
+  return CheckType(loc, type, Type::I32, "data segment offset");
+}
+
+Result SharedValidator::OnDataSegmentInitExpr_GlobalGet(const Location& loc,
+                                                        Var global_var) {
+  Result result = Result::Ok;
+  GlobalType ref_global;
+  result |= CheckGlobalIndex(global_var, &ref_global);
+
+  if (ref_global.mutable_) {
+    result |= PrintError(
+        loc, "initializer expression cannot reference a mutable global");
+  }
+
+  result |= CheckType(loc, ref_global.type, Type::I32, "data segment offset");
+  return result;
+}
+
+Result SharedValidator::OnDataSegmentInitExpr_Other(const Location& loc) {
+  return PrintError(loc,
+                    "invalid data segment offset, must be a constant "
+                    "expression; either i32.const or "
+                    "global.get.");
+}
+
+Result SharedValidator::CheckDeclaredFunc(Var func_var) {
+  if (declared_funcs_.count(func_var.index()) == 0) {
+    return PrintError(func_var.loc,
+                      "function is not declared in any elem sections");
+  }
+  return Result::Ok;
+}
+
+Result SharedValidator::EndModule() {
+  // Verify that any ref.func used in init expressions for globals are
+  // mentioned in an elems section.  This can't be done while process the
+  // globals because the global section comes before the elem section.
+  Result result = Result::Ok;
+  for (Var func_var : init_expr_funcs_) {
+    result |= CheckDeclaredFunc(func_var);
+  }
+  return result;
+}
+
+Result SharedValidator::CheckIndex(Var var, Index max_index, const char* desc) {
+  if (var.index() >= max_index) {
+    return PrintError(
+        var.loc, "%s variable out of range: %" PRIindex " (max %" PRIindex ")",
+        desc, var.index(), max_index);
+  }
+  return Result::Ok;
+}
+
+template <typename T>
+Result SharedValidator::CheckIndexWithValue(Var var,
+                                            const std::vector<T>& values,
+                                            T* out,
+                                            const char* desc) {
+  Result result = CheckIndex(var, values.size(), desc);
+  if (out) {
+    *out = Succeeded(result) ? values[var.index()] : T{};
+  }
+  return result;
+}
+
+Result SharedValidator::CheckLocalIndex(Var local_var, Type* out_type) {
+  auto iter = std::upper_bound(
+      locals_.begin(), locals_.end(), local_var.index(),
+      [](Index index, const LocalDecl& decl) { return index < decl.end; });
+  if (iter == locals_.end()) {
+    // TODO: better error
+    return PrintError(local_var.loc, "local variable out of range (max %u)",
+                      GetLocalCount());
+  }
+  *out_type = iter->type;
+  return Result::Ok;
+}
+
+Result SharedValidator::CheckFuncTypeIndex(Var sig_var, FuncType* out) {
+  Result result = CheckIndex(sig_var, num_types_, "function type");
+  if (Failed(result)) {
+    *out = FuncType{};
+    return Result::Error;
+  }
+
+  auto iter = func_types_.find(sig_var.index());
+  if (iter == func_types_.end()) {
+    return PrintError(sig_var.loc, "type %d is not a function",
+                      sig_var.index());
+  }
+
+  if (out) {
+    *out = iter->second;
+  }
+  return Result::Ok;
+}
+
+Result SharedValidator::CheckFuncIndex(Var func_var, FuncType* out) {
+  return CheckIndexWithValue(func_var, funcs_, out, "function");
+}
+
+Result SharedValidator::CheckMemoryIndex(Var memory_var, MemoryType* out) {
+  return CheckIndexWithValue(memory_var, memories_, out, "memory");
+}
+
+Result SharedValidator::CheckTableIndex(Var table_var, TableType* out) {
+  return CheckIndexWithValue(table_var, tables_, out, "table");
+}
+
+Result SharedValidator::CheckGlobalIndex(Var global_var, GlobalType* out) {
+  return CheckIndexWithValue(global_var, globals_, out, "global");
+}
+
+Result SharedValidator::CheckEventIndex(Var event_var, EventType* out) {
+  return CheckIndexWithValue(event_var, events_, out, "event");
+}
+
+Result SharedValidator::CheckElemSegmentIndex(Var elem_segment_var,
+                                              ElemType* out) {
+  return CheckIndexWithValue(elem_segment_var, elems_, out, "elem_segment");
+}
+
+Result SharedValidator::CheckDataSegmentIndex(Var data_segment_var) {
+  return CheckIndex(data_segment_var, data_segments_, "data_segment");
+}
+
+Result SharedValidator::CheckBlockSignature(const Location& loc,
+                                            Opcode opcode,
+                                            Type sig_type,
+                                            TypeVector* out_param_types,
+                                            TypeVector* out_result_types) {
+  Result result = Result::Ok;
+
+  if (sig_type.IsIndex()) {
+    Index sig_index = sig_type.GetIndex();
+    FuncType func_type;
+    result |= CheckFuncTypeIndex(Var(sig_index, loc), &func_type);
+
+    if (!func_type.params.empty() && !options_.features.multi_value_enabled()) {
+      result |= PrintError(loc, "%s params not currently supported.",
+                           opcode.GetName());
+    }
+    // Multiple results without --enable-multi-value is checked above in
+    // OnType.
+
+    *out_param_types = func_type.params;
+    *out_result_types = func_type.results;
+  } else {
+    out_param_types->clear();
+    *out_result_types = sig_type.GetInlineVector();
+  }
+
+  return result;
+}
+
+Result SharedValidator::BeginFunctionBody(const Location& loc,
+                                          Index func_index) {
+  expr_loc_ = &loc;
+  locals_.clear();
+  if (func_index < funcs_.size()) {
+    for (Type type : funcs_[func_index].params) {
+      // TODO: Coalesce parameters of the same type?
+      locals_.push_back(LocalDecl{type, GetLocalCount() + 1});
+    }
+    return typechecker_.BeginFunction(funcs_[func_index].results);
+  } else {
+    // Signature isn't available, use empty.
+    return typechecker_.BeginFunction(TypeVector());
+  }
+}
+
+Result SharedValidator::EndFunctionBody(const Location& loc) {
+  return typechecker_.EndFunction();
+}
+
+Result SharedValidator::OnLocalDecl(const Location& loc,
+                                    Index count,
+                                    Type type) {
+  const auto max_locals = std::numeric_limits<Index>::max();
+  if (count > max_locals - GetLocalCount()) {
+    PrintError(loc, "local count must be < 0x10000000");
+    return Result::Error;
+  }
+  locals_.push_back(LocalDecl{type, GetLocalCount() + count});
+  return Result::Ok;
+}
+
+Index SharedValidator::GetLocalCount() const {
+  return locals_.empty() ? 0 : locals_.back().end;
+}
+
+static bool is_power_of_two(uint32_t x) {
+  return x && ((x & (x - 1)) == 0);
+}
+
+Result SharedValidator::CheckAlign(const Location& loc,
+                                   Address alignment,
+                                   Address natural_alignment) {
+  if (!is_power_of_two(alignment)) {
+    PrintError(loc, "alignment (%" PRIaddress ") must be a power of 2",
+               alignment);
+    return Result::Error;
+  }
+  if (alignment > natural_alignment) {
+    PrintError(
+        loc,
+        "alignment must not be larger than natural alignment (%" PRIaddress ")",
+        natural_alignment);
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
+Result SharedValidator::CheckAtomicAlign(const Location& loc,
+                                         Address alignment,
+                                         Address natural_alignment) {
+  if (!is_power_of_two(alignment)) {
+    PrintError(loc, "alignment (%" PRIaddress ") must be a power of 2",
+               alignment);
+    return Result::Error;
+  }
+  if (alignment != natural_alignment) {
+    PrintError(loc,
+               "alignment must be equal to natural alignment (%" PRIaddress ")",
+               natural_alignment);
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
+Result SharedValidator::OnAtomicFence(const Location& loc,
+                                      uint32_t consistency_model) {
+  Result result = Result::Ok;
+  if (consistency_model != 0) {
+    result |= PrintError(
+        loc, "unexpected atomic.fence consistency model (expected 0): %u",
+        consistency_model);
+  }
+  result |= typechecker_.OnAtomicFence(consistency_model);
+  return result;
+}
+
+Result SharedValidator::OnAtomicLoad(const Location& loc,
+                                     Opcode opcode,
+                                     Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnAtomicLoad(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnAtomicNotify(const Location& loc,
+                                       Opcode opcode,
+                                       Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnAtomicNotify(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnAtomicRmwCmpxchg(const Location& loc,
+                                           Opcode opcode,
+                                           Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnAtomicRmwCmpxchg(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnAtomicRmw(const Location& loc,
+                                    Opcode opcode,
+                                    Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnAtomicRmw(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnAtomicStore(const Location& loc,
+                                      Opcode opcode,
+                                      Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnAtomicStore(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnAtomicWait(const Location& loc,
+                                     Opcode opcode,
+                                     Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAtomicAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnAtomicWait(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnBinary(const Location& loc, Opcode opcode) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnBinary(opcode);
+  return result;
+}
+
+Result SharedValidator::OnBlock(const Location& loc, Type sig_type) {
+  Result result = Result::Ok;
+  TypeVector param_types, result_types;
+  expr_loc_ = &loc;
+  result |= CheckBlockSignature(loc, Opcode::Block, sig_type, &param_types,
+                                &result_types);
+  result |= typechecker_.OnBlock(param_types, result_types);
+  return result;
+}
+
+Result SharedValidator::OnBr(const Location& loc, Var depth) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnBr(depth.index());
+  return result;
+}
+
+Result SharedValidator::OnBrIf(const Location& loc, Var depth) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnBrIf(depth.index());
+  return result;
+}
+
+Result SharedValidator::BeginBrTable(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.BeginBrTable();
+  return result;
+}
+
+Result SharedValidator::OnBrTableTarget(const Location& loc, Var depth) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnBrTableTarget(depth.index());
+  return result;
+}
+
+Result SharedValidator::EndBrTable(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.EndBrTable();
+  return result;
+}
+
+Result SharedValidator::OnCall(const Location& loc, Var func_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  FuncType func_type;
+  result |= CheckFuncIndex(func_var, &func_type);
+  result |= typechecker_.OnCall(func_type.params, func_type.results);
+  return result;
+}
+
+Result SharedValidator::OnCallIndirect(const Location& loc,
+                                       Var sig_var,
+                                       Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  FuncType func_type;
+  result |= CheckFuncTypeIndex(sig_var, &func_type);
+  result |= CheckTableIndex(table_var);
+  result |= typechecker_.OnCallIndirect(func_type.params, func_type.results);
+  return result;
+}
+
+Result SharedValidator::OnCatch(const Location& loc,
+                                Var event_var,
+                                bool is_catch_all) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  if (is_catch_all) {
+    TypeVector empty;
+    result |= typechecker_.OnCatch(empty);
+  } else {
+    EventType event_type;
+    result |= CheckEventIndex(event_var, &event_type);
+    result |= typechecker_.OnCatch(event_type.params);
+  }
+  return result;
+}
+
+Result SharedValidator::OnCompare(const Location& loc, Opcode opcode) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnCompare(opcode);
+  return result;
+}
+
+Result SharedValidator::OnConst(const Location& loc, Type type) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnConst(type);
+  return result;
+}
+
+Result SharedValidator::OnConvert(const Location& loc, Opcode opcode) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnConvert(opcode);
+  return result;
+}
+
+Result SharedValidator::OnDataDrop(const Location& loc, Var segment_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= CheckDataSegmentIndex(segment_var);
+  result |= typechecker_.OnDataDrop(segment_var.index());
+  return result;
+}
+
+Result SharedValidator::OnDelegate(const Location& loc, Var depth) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnDelegate(depth.index());
+  return result;
+}
+
+Result SharedValidator::OnDrop(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnDrop();
+  return result;
+}
+
+Result SharedValidator::OnElemDrop(const Location& loc, Var segment_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= CheckElemSegmentIndex(segment_var);
+  result |= typechecker_.OnElemDrop(segment_var.index());
+  return result;
+}
+
+Result SharedValidator::OnElse(const Location& loc) {
+  Result result = Result::Ok;
+  result |= typechecker_.OnElse();
+  return result;
+}
+
+Result SharedValidator::OnEnd(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnEnd();
+  return result;
+}
+
+Result SharedValidator::OnGlobalGet(const Location& loc, Var global_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  GlobalType global_type;
+  result |= CheckGlobalIndex(global_var, &global_type);
+  result |= typechecker_.OnGlobalGet(global_type.type);
+  return result;
+}
+
+Result SharedValidator::OnGlobalSet(const Location& loc, Var global_var) {
+  Result result = Result::Ok;
+  GlobalType global_type;
+  result |= CheckGlobalIndex(global_var, &global_type);
+  if (!global_type.mutable_) {
+    result |= PrintError(
+        loc, "can't global.set on immutable global at index %" PRIindex ".",
+        global_var.index());
+  }
+  expr_loc_ = &loc;
+  result |= typechecker_.OnGlobalSet(global_type.type);
+  return result;
+}
+
+Result SharedValidator::OnIf(const Location& loc, Type sig_type) {
+  Result result = Result::Ok;
+  TypeVector param_types, result_types;
+  expr_loc_ = &loc;
+  result |= CheckBlockSignature(loc, Opcode::If, sig_type, &param_types,
+                                &result_types);
+  result |= typechecker_.OnIf(param_types, result_types);
+  return result;
+}
+
+Result SharedValidator::OnLoad(const Location& loc,
+                               Opcode opcode,
+                               Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnLoad(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnLoadSplat(const Location& loc,
+                                    Opcode opcode,
+                                    Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnLoad(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnLocalGet(const Location& loc, Var local_var) {
+  Result result = Result::Ok;
+  Type type = Type::Any;
+  expr_loc_ = &loc;
+  result |= CheckLocalIndex(local_var, &type);
+  result |= typechecker_.OnLocalGet(type);
+  return result;
+}
+
+Result SharedValidator::OnLocalSet(const Location& loc, Var local_var) {
+  Result result = Result::Ok;
+  Type type = Type::Any;
+  expr_loc_ = &loc;
+  result |= CheckLocalIndex(local_var, &type);
+  result |= typechecker_.OnLocalSet(type);
+  return result;
+}
+
+Result SharedValidator::OnLocalTee(const Location& loc, Var local_var) {
+  Result result = Result::Ok;
+  Type type = Type::Any;
+  expr_loc_ = &loc;
+  result |= CheckLocalIndex(local_var, &type);
+  result |= typechecker_.OnLocalTee(type);
+  return result;
+}
+
+Result SharedValidator::OnLoop(const Location& loc, Type sig_type) {
+  Result result = Result::Ok;
+  TypeVector param_types, result_types;
+  expr_loc_ = &loc;
+  result |= CheckBlockSignature(loc, Opcode::Loop, sig_type, &param_types,
+                                &result_types);
+  result |= typechecker_.OnLoop(param_types, result_types);
+  return result;
+}
+
+Result SharedValidator::OnMemoryCopy(const Location& loc) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= typechecker_.OnMemoryCopy(mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnMemoryFill(const Location& loc) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= typechecker_.OnMemoryFill(mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnMemoryGrow(const Location& loc) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= typechecker_.OnMemoryGrow(mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnMemoryInit(const Location& loc, Var segment_var) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckDataSegmentIndex(segment_var);
+  result |= typechecker_.OnMemoryInit(segment_var.index(), mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnMemorySize(const Location& loc) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= typechecker_.OnMemorySize(mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnNop(const Location& loc) {
+  expr_loc_ = &loc;
+  return Result::Ok;
+}
+
+Result SharedValidator::OnRefFunc(const Location& loc, Var func_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= CheckDeclaredFunc(func_var);
+  result |= typechecker_.OnRefFuncExpr(func_var.index());
+  return result;
+}
+
+Result SharedValidator::OnRefIsNull(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnRefIsNullExpr();
+  return result;
+}
+
+Result SharedValidator::OnRefNull(const Location& loc, Type type) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnRefNullExpr(type);
+  return result;
+}
+
+Result SharedValidator::OnRethrow(const Location& loc, Var depth) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnRethrow(depth.index());
+  return result;
+}
+
+Result SharedValidator::OnReturnCall(const Location& loc, Var func_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  FuncType func_type;
+  result |= CheckFuncIndex(func_var, &func_type);
+  result |= typechecker_.OnReturnCall(func_type.params, func_type.results);
+  return result;
+}
+
+Result SharedValidator::OnReturnCallIndirect(const Location& loc,
+                                             Var sig_var,
+                                             Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= CheckTableIndex(table_var);
+  FuncType func_type;
+  result |= CheckFuncTypeIndex(sig_var, &func_type);
+  result |=
+      typechecker_.OnReturnCallIndirect(func_type.params, func_type.results);
+  return result;
+}
+
+Result SharedValidator::OnReturn(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnReturn();
+  return result;
+}
+
+Result SharedValidator::OnSelect(const Location& loc,
+                                 Index result_count,
+                                 Type* result_types) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  if (result_count > 1) {
+    result |=
+        PrintError(loc, "invalid arity in select instruction: %" PRIindex ".",
+                   result_count);
+  } else {
+    result |= typechecker_.OnSelect(ToTypeVector(result_count, result_types));
+  }
+  return result;
+}
+
+Result SharedValidator::OnSimdLaneOp(const Location& loc,
+                                     Opcode opcode,
+                                     uint64_t value) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnSimdLaneOp(opcode, value);
+  return result;
+}
+
+Result SharedValidator::OnSimdShuffleOp(const Location& loc,
+                                        Opcode opcode,
+                                        v128 value) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnSimdShuffleOp(opcode, value);
+  return result;
+}
+
+Result SharedValidator::OnStore(const Location& loc,
+                                Opcode opcode,
+                                Address alignment) {
+  Result result = Result::Ok;
+  MemoryType mt;
+  expr_loc_ = &loc;
+  result |= CheckMemoryIndex(Var(0, loc), &mt);
+  result |= CheckAlign(loc, alignment, opcode.GetMemorySize());
+  result |= typechecker_.OnStore(opcode, mt.limits);
+  return result;
+}
+
+Result SharedValidator::OnTableCopy(const Location& loc,
+                                    Var dst_var,
+                                    Var src_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  TableType dst_table;
+  TableType src_table;
+  result |= CheckTableIndex(dst_var, &dst_table);
+  result |= CheckTableIndex(src_var, &src_table);
+  result |= typechecker_.OnTableCopy();
+  result |= CheckType(loc, src_table.element, dst_table.element, "table.copy");
+  return result;
+}
+
+Result SharedValidator::OnTableFill(const Location& loc, Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  TableType table_type;
+  result |= CheckTableIndex(table_var, &table_type);
+  result |= typechecker_.OnTableFill(table_type.element);
+  return result;
+}
+
+Result SharedValidator::OnTableGet(const Location& loc, Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  TableType table_type;
+  result |= CheckTableIndex(table_var, &table_type);
+  result |= typechecker_.OnTableGet(table_type.element);
+  return result;
+}
+
+Result SharedValidator::OnTableGrow(const Location& loc, Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  TableType table_type;
+  result |= CheckTableIndex(table_var, &table_type);
+  result |= typechecker_.OnTableGrow(table_type.element);
+  return result;
+}
+
+Result SharedValidator::OnTableInit(const Location& loc,
+                                    Var segment_var,
+                                    Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  TableType table_type;
+  ElemType elem_type;
+  result |= CheckTableIndex(table_var, &table_type);
+  result |= CheckElemSegmentIndex(segment_var, &elem_type);
+  result |= typechecker_.OnTableInit(table_var.index(), segment_var.index());
+  result |= CheckType(loc, elem_type.element, table_type.element, "table.init");
+  return result;
+}
+
+Result SharedValidator::OnTableSet(const Location& loc, Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  TableType table_type;
+  result |= CheckTableIndex(table_var, &table_type);
+  result |= typechecker_.OnTableSet(table_type.element);
+  return result;
+}
+
+Result SharedValidator::OnTableSize(const Location& loc, Var table_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= CheckTableIndex(table_var);
+  result |= typechecker_.OnTableSize();
+  return result;
+}
+
+Result SharedValidator::OnTernary(const Location& loc, Opcode opcode) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnTernary(opcode);
+  return result;
+}
+
+Result SharedValidator::OnThrow(const Location& loc, Var event_var) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  EventType event_type;
+  result |= CheckEventIndex(event_var, &event_type);
+  result |= typechecker_.OnThrow(event_type.params);
+  return result;
+}
+
+Result SharedValidator::OnTry(const Location& loc, Type sig_type) {
+  Result result = Result::Ok;
+  TypeVector param_types, result_types;
+  expr_loc_ = &loc;
+  result |= CheckBlockSignature(loc, Opcode::Try, sig_type, &param_types,
+                                &result_types);
+  result |= typechecker_.OnTry(param_types, result_types);
+  return result;
+}
+
+Result SharedValidator::OnUnary(const Location& loc, Opcode opcode) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnUnary(opcode);
+  return result;
+}
+
+Result SharedValidator::OnUnreachable(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnUnreachable();
+  return result;
+}
+
+Result SharedValidator::OnUnwind(const Location& loc) {
+  Result result = Result::Ok;
+  expr_loc_ = &loc;
+  result |= typechecker_.OnUnwind();
+  return result;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/shared-validator.h
new file mode 100644 (file)
index 0000000..456693b
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * 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_SHARED_VALIDATOR_H_
+#define WABT_SHARED_VALIDATOR_H_
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "src/common.h"
+#include "src/error.h"
+#include "src/feature.h"
+#include "src/ir.h"
+#include "src/opcode.h"
+#include "src/type-checker.h"
+
+#include "src/binary-reader.h"  // For TypeMut.
+
+namespace wabt {
+
+struct ValidateOptions {
+  ValidateOptions() = default;
+  ValidateOptions(const Features& features) : features(features) {}
+
+  Features features;
+};
+
+class SharedValidator {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(SharedValidator);
+  SharedValidator(Errors*, const ValidateOptions& options);
+
+  // TODO: Move into SharedValidator?
+  using Label = TypeChecker::Label;
+  size_t type_stack_size() const { return typechecker_.type_stack_size(); }
+  Result GetLabel(Index depth, Label** out_label) {
+    return typechecker_.GetLabel(depth, out_label);
+  }
+
+  Result WABT_PRINTF_FORMAT(3, 4)
+      PrintError(const Location& loc, const char* fmt, ...);
+
+  void OnTypecheckerError(const char* msg);
+
+  Index GetLocalCount() const;
+
+  Result EndModule();
+
+  Result OnFuncType(const Location&,
+                    Index param_count,
+                    const Type* param_types,
+                    Index result_count,
+                    const Type* result_types);
+  Result OnStructType(const Location&, Index field_count, TypeMut* fields);
+  Result OnArrayType(const Location&, TypeMut field);
+
+  Result OnFunction(const Location&, Var sig_var);
+  Result OnTable(const Location&, Type elem_type, const Limits&);
+  Result OnMemory(const Location&, const Limits&);
+  Result OnGlobalImport(const Location&, Type type, bool mutable_);
+  Result OnGlobal(const Location&, Type type, bool mutable_);
+  Result OnGlobalInitExpr_Const(const Location&, Type);
+  Result OnGlobalInitExpr_GlobalGet(const Location&, Var global_var);
+  Result OnGlobalInitExpr_RefNull(const Location&, Type type);
+  Result OnGlobalInitExpr_RefFunc(const Location&, Var func_var);
+  Result OnGlobalInitExpr_Other(const Location&);
+  Result OnEvent(const Location&, Var sig_var);
+
+  Result OnExport(const Location&,
+                  ExternalKind,
+                  Var item_var,
+                  string_view name);
+
+  Result OnStart(const Location&, Var func_var);
+
+  Result OnElemSegment(const Location&, Var table_var, SegmentKind);
+  void OnElemSegmentElemType(Type elem_type);
+  Result OnElemSegmentInitExpr_Const(const Location&, Type);
+  Result OnElemSegmentInitExpr_GlobalGet(const Location&, Var global_var);
+  Result OnElemSegmentInitExpr_Other(const Location&);
+  Result OnElemSegmentElemExpr_RefNull(const Location&, Type type);
+  Result OnElemSegmentElemExpr_RefFunc(const Location&, Var func_var);
+  Result OnElemSegmentElemExpr_Other(const Location&);
+
+  void OnDataCount(Index count);
+
+  Result OnDataSegment(const Location&, Var memory_var, SegmentKind);
+  Result OnDataSegmentInitExpr_Const(const Location&, Type);
+  Result OnDataSegmentInitExpr_GlobalGet(const Location&, Var global_var);
+  Result OnDataSegmentInitExpr_Other(const Location&);
+
+  Result BeginFunctionBody(const Location&, Index func_index);
+  Result EndFunctionBody(const Location&);
+  Result OnLocalDecl(const Location&, Index count, Type type);
+
+  Result OnAtomicFence(const Location&, uint32_t consistency_model);
+  Result OnAtomicLoad(const Location&, Opcode, Address align);
+  Result OnAtomicNotify(const Location&, Opcode, Address align);
+  Result OnAtomicRmwCmpxchg(const Location&, Opcode, Address align);
+  Result OnAtomicRmw(const Location&, Opcode, Address align);
+  Result OnAtomicStore(const Location&, Opcode, Address align);
+  Result OnAtomicWait(const Location&, Opcode, Address align);
+  Result OnBinary(const Location&, Opcode);
+  Result OnBlock(const Location&, Type sig_type);
+  Result OnBr(const Location&, Var depth);
+  Result OnBrIf(const Location&, Var depth);
+  Result BeginBrTable(const Location&);
+  Result OnBrTableTarget(const Location&, Var depth);
+  Result EndBrTable(const Location&);
+  Result OnCall(const Location&, Var func_var);
+  Result OnCallIndirect(const Location&, Var sig_var, Var table_var);
+  Result OnCatch(const Location&, Var event_var, bool is_catch_all);
+  Result OnCompare(const Location&, Opcode);
+  Result OnConst(const Location&, Type);
+  Result OnConvert(const Location&, Opcode);
+  Result OnDataDrop(const Location&, Var segment_var);
+  Result OnDelegate(const Location&, Var depth);
+  Result OnDrop(const Location&);
+  Result OnElemDrop(const Location&, Var segment_var);
+  Result OnElse(const Location&);
+  Result OnEnd(const Location&);
+  Result OnGlobalGet(const Location&, Var);
+  Result OnGlobalSet(const Location&, Var);
+  Result OnIf(const Location&, Type sig_type);
+  Result OnLoad(const Location&, Opcode, Address align);
+  Result OnLoadSplat(const Location&, Opcode, Address align);
+  Result OnLocalGet(const Location&, Var);
+  Result OnLocalSet(const Location&, Var);
+  Result OnLocalTee(const Location&, Var);
+  Result OnLoop(const Location&, Type sig_type);
+  Result OnMemoryCopy(const Location&);
+  Result OnMemoryFill(const Location&);
+  Result OnMemoryGrow(const Location&);
+  Result OnMemoryInit(const Location&, Var segment_var);
+  Result OnMemorySize(const Location&);
+  Result OnNop(const Location&);
+  Result OnRefFunc(const Location&, Var func_var);
+  Result OnRefIsNull(const Location&);
+  Result OnRefNull(const Location&, Type type);
+  Result OnRethrow(const Location&, Var depth);
+  Result OnReturnCall(const Location&, Var func_var);
+  Result OnReturnCallIndirect(const Location&, Var sig_var, Var table_var);
+  Result OnReturn(const Location&);
+  Result OnSelect(const Location&, Index result_count, Type* result_types);
+  Result OnSimdLaneOp(const Location&, Opcode, uint64_t lane_idx);
+  Result OnSimdShuffleOp(const Location&, Opcode, v128 lane_idx);
+  Result OnStore(const Location&, Opcode, Address align);
+  Result OnTableCopy(const Location&, Var dst_var, Var src_var);
+  Result OnTableFill(const Location&, Var table_var);
+  Result OnTableGet(const Location&, Var table_var);
+  Result OnTableGrow(const Location&, Var table_var);
+  Result OnTableInit(const Location&, Var segment_var, Var table_var);
+  Result OnTableSet(const Location&, Var table_var);
+  Result OnTableSize(const Location&, Var table_var);
+  Result OnTernary(const Location&, Opcode);
+  Result OnThrow(const Location&, Var event_var);
+  Result OnTry(const Location&, Type sig_type);
+  Result OnUnary(const Location&, Opcode);
+  Result OnUnreachable(const Location&);
+  Result OnUnwind(const Location&);
+
+ private:
+  struct FuncType {
+    FuncType() = default;
+    FuncType(const TypeVector& params, const TypeVector& results)
+        : params(params), results(results) {}
+
+    TypeVector params;
+    TypeVector results;
+  };
+
+  struct StructType {
+    StructType() = default;
+    StructType(const TypeMutVector& fields) : fields(fields) {}
+
+    TypeMutVector fields;
+  };
+
+  struct ArrayType {
+    ArrayType() = default;
+    ArrayType(TypeMut field) : field(field) {}
+
+    TypeMut field;
+  };
+
+  struct TableType {
+    TableType() = default;
+    TableType(Type element, Limits limits) : element(element), limits(limits) {}
+
+    Type element = Type::Any;
+    Limits limits;
+  };
+
+  struct MemoryType {
+    MemoryType() = default;
+    MemoryType(Limits limits) : limits(limits) {}
+
+    Limits limits;
+  };
+
+  struct GlobalType {
+    GlobalType() = default;
+    GlobalType(Type type, bool mutable_) : type(type), mutable_(mutable_) {}
+
+    Type type = Type::Any;
+    bool mutable_ = true;
+  };
+
+  struct EventType {
+    TypeVector params;
+  };
+
+  struct ElemType {
+    ElemType() = default;
+    ElemType(Type element) : element(element) {}
+
+    Type element;
+  };
+
+  struct LocalDecl {
+    Type type;
+    Index end;
+  };
+
+  Result CheckType(const Location&,
+                   Type actual,
+                   Type expected,
+                   const char* desc);
+  Result CheckLimits(const Location&,
+                     const Limits&,
+                     uint64_t absolute_max,
+                     const char* desc);
+
+  Result CheckLocalIndex(Var local_var, Type* out_type);
+
+  Result CheckDeclaredFunc(Var func_var);
+
+  Result CheckIndex(Var var, Index max_index, const char* desc);
+  template <typename T>
+  Result CheckIndexWithValue(Var var,
+                             const std::vector<T>& values,
+                             T* out,
+                             const char* desc);
+  Result CheckFuncTypeIndex(Var sig_var, FuncType* out = nullptr);
+  Result CheckFuncIndex(Var func_var, FuncType* out = nullptr);
+  Result CheckTableIndex(Var table_var, TableType* out = nullptr);
+  Result CheckMemoryIndex(Var memory_var, MemoryType* out = nullptr);
+  Result CheckGlobalIndex(Var global_var, GlobalType* out = nullptr);
+  Result CheckEventIndex(Var event_var, EventType* out = nullptr);
+  Result CheckElemSegmentIndex(Var elem_segment_var, ElemType* out = nullptr);
+  Result CheckDataSegmentIndex(Var data_segment_var);
+
+  Result CheckAlign(const Location&, Address align, Address natural_align);
+  Result CheckAtomicAlign(const Location&, Address align, Address natural_align);
+
+  Result CheckBlockSignature(const Location&,
+                             Opcode,
+                             Type sig_type,
+                             TypeVector* out_param_types,
+                             TypeVector* out_result_types);
+
+  TypeVector ToTypeVector(Index count, const Type* types);
+
+  ValidateOptions options_;
+  Errors* errors_;
+  TypeChecker typechecker_;  // TODO: Move into SharedValidator.
+  // Cached for access by OnTypecheckerError.
+  const Location* expr_loc_ = nullptr;
+
+  Index num_types_ = 0;
+  std::map<Index, FuncType> func_types_;
+  std::map<Index, StructType> struct_types_;
+  std::map<Index, ArrayType> array_types_;
+
+  std::vector<FuncType> funcs_;       // Includes imported and defined.
+  std::vector<TableType> tables_;     // Includes imported and defined.
+  std::vector<MemoryType> memories_;  // Includes imported and defined.
+  std::vector<GlobalType> globals_;   // Includes imported and defined.
+  std::vector<EventType> events_;     // Includes imported and defined.
+  std::vector<ElemType> elems_;
+  Index starts_ = 0;
+  Index num_imported_globals_ = 0;
+  Index data_segments_ = 0;
+
+  // Includes parameters, since this is only used for validating
+  // local.{get,set,tee} instructions.
+  std::vector<LocalDecl> locals_;
+
+  std::set<std::string> export_names_;  // Used to check for duplicates.
+  std::set<Index> declared_funcs_;      // TODO: optimize?
+  std::vector<Var> init_expr_funcs_;
+};
+
+}  // namespace wabt
+
+#endif  // WABT_SHARED_VALIDATOR_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.cc
new file mode 100644 (file)
index 0000000..e52c51b
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * 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/stream.h"
+
+#include <cassert>
+#include <cctype>
+#include <cerrno>
+
+#define DUMP_OCTETS_PER_LINE 16
+#define DUMP_OCTETS_PER_GROUP 2
+
+#define ERROR0(msg) fprintf(stderr, "%s:%d: " msg, __FILE__, __LINE__)
+#define ERROR(fmt, ...) \
+  fprintf(stderr, "%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__)
+
+namespace wabt {
+
+Stream::Stream(Stream* log_stream)
+    : offset_(0), result_(Result::Ok), log_stream_(log_stream) {}
+
+void Stream::AddOffset(ssize_t delta) {
+  offset_ += delta;
+}
+
+void Stream::WriteDataAt(size_t at,
+                         const void* src,
+                         size_t size,
+                         const char* desc,
+                         PrintChars print_chars) {
+  if (Failed(result_)) {
+    return;
+  }
+  if (log_stream_) {
+    log_stream_->WriteMemoryDump(src, size, at, print_chars, nullptr, desc);
+  }
+  result_ = WriteDataImpl(at, src, size);
+}
+
+void Stream::WriteData(const void* src,
+                       size_t size,
+                       const char* desc,
+                       PrintChars print_chars) {
+  WriteDataAt(offset_, src, size, desc, print_chars);
+  offset_ += size;
+}
+
+void Stream::MoveData(size_t dst_offset, size_t src_offset, size_t size) {
+  if (Failed(result_)) {
+    return;
+  }
+  if (log_stream_) {
+    log_stream_->Writef(
+        "; move data: [%" PRIzx ", %" PRIzx ") -> [%" PRIzx ", %" PRIzx ")\n",
+        src_offset, src_offset + size, dst_offset, dst_offset + size);
+  }
+  result_ = MoveDataImpl(dst_offset, src_offset, size);
+}
+
+void Stream::Truncate(size_t size) {
+  if (Failed(result_)) {
+    return;
+  }
+  if (log_stream_) {
+    log_stream_->Writef("; truncate to %" PRIzd " (0x%" PRIzx ")\n", size,
+                        size);
+  }
+  result_ = TruncateImpl(size);
+  if (Succeeded(result_) && offset_ > size) {
+    offset_ = size;
+  }
+}
+
+void Stream::Writef(const char* format, ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  WriteData(buffer, length);
+}
+
+void Stream::WriteMemoryDump(const void* start,
+                             size_t size,
+                             size_t offset,
+                             PrintChars print_chars,
+                             const char* prefix,
+                             const char* desc) {
+  const uint8_t* p = static_cast<const uint8_t*>(start);
+  const uint8_t* end = p + size;
+  while (p < end) {
+    const uint8_t* line = p;
+    const uint8_t* line_end = p + DUMP_OCTETS_PER_LINE;
+    if (prefix) {
+      Writef("%s", prefix);
+    }
+    Writef("%07" PRIzx ": ", reinterpret_cast<intptr_t>(p) -
+                                 reinterpret_cast<intptr_t>(start) + offset);
+    while (p < line_end) {
+      for (int i = 0; i < DUMP_OCTETS_PER_GROUP; ++i, ++p) {
+        if (p < end) {
+          Writef("%02x", *p);
+        } else {
+          WriteChar(' ');
+          WriteChar(' ');
+        }
+      }
+      WriteChar(' ');
+    }
+
+    if (print_chars == PrintChars::Yes) {
+      WriteChar(' ');
+      p = line;
+      for (int i = 0; i < DUMP_OCTETS_PER_LINE && p < end; ++i, ++p)
+        WriteChar(isprint(*p) ? *p : '.');
+    }
+
+    /* if there are multiple lines, only print the desc on the last one */
+    if (p >= end && desc) {
+      Writef("  ; %s", desc);
+    }
+    WriteChar('\n');
+  }
+}
+
+Result OutputBuffer::WriteToFile(string_view filename) const {
+  std::string filename_str = filename.to_string();
+  FILE* file = fopen(filename_str.c_str(), "wb");
+  if (!file) {
+    ERROR("unable to open %s for writing\n", filename_str.c_str());
+    return Result::Error;
+  }
+
+  if (data.empty()) {
+    fclose(file);
+    return Result::Ok;
+  }
+
+  ssize_t bytes = fwrite(data.data(), 1, data.size(), file);
+  if (bytes < 0 || static_cast<size_t>(bytes) != data.size()) {
+    ERROR("failed to write %" PRIzd " bytes to %s\n", data.size(),
+          filename_str.c_str());
+    fclose(file);
+    return Result::Error;
+  }
+
+  fclose(file);
+  return Result::Ok;
+}
+
+MemoryStream::MemoryStream(Stream* log_stream)
+    : Stream(log_stream), buf_(new OutputBuffer()) {}
+
+MemoryStream::MemoryStream(std::unique_ptr<OutputBuffer>&& buf,
+                           Stream* log_stream)
+    : Stream(log_stream), buf_(std::move(buf)) {}
+
+std::unique_ptr<OutputBuffer> MemoryStream::ReleaseOutputBuffer() {
+  return std::move(buf_);
+}
+
+void MemoryStream::Clear() {
+  if (buf_)
+    buf_->clear();
+  else
+    buf_.reset(new OutputBuffer());
+}
+
+Result MemoryStream::WriteDataImpl(size_t dst_offset,
+                                   const void* src,
+                                   size_t size) {
+  if (size == 0) {
+    return Result::Ok;
+  }
+  size_t end = dst_offset + size;
+  if (end > buf_->data.size()) {
+    buf_->data.resize(end);
+  }
+  uint8_t* dst = &buf_->data[dst_offset];
+  memcpy(dst, src, size);
+  return Result::Ok;
+}
+
+Result MemoryStream::MoveDataImpl(size_t dst_offset,
+                                  size_t src_offset,
+                                  size_t size) {
+  if (size == 0) {
+    return Result::Ok;
+  }
+  size_t src_end = src_offset + size;
+  size_t dst_end = dst_offset + size;
+  size_t end = src_end > dst_end ? src_end : dst_end;
+  if (end > buf_->data.size()) {
+    buf_->data.resize(end);
+  }
+
+  uint8_t* dst = &buf_->data[dst_offset];
+  uint8_t* src = &buf_->data[src_offset];
+  memmove(dst, src, size);
+  return Result::Ok;
+}
+
+Result MemoryStream::TruncateImpl(size_t size) {
+  if (size > buf_->data.size()) {
+    return Result::Error;
+  }
+  buf_->data.resize(size);
+  return Result::Ok;
+}
+
+FileStream::FileStream(string_view filename, Stream* log_stream)
+    : Stream(log_stream), file_(nullptr), offset_(0), should_close_(false) {
+  std::string filename_str = filename.to_string();
+  file_ = fopen(filename_str.c_str(), "wb");
+
+  // TODO(binji): this is pretty cheesy, should come up with a better API.
+  if (file_) {
+    should_close_ = true;
+  } else {
+    ERROR("fopen name=\"%s\" failed, errno=%d\n", filename_str.c_str(), errno);
+  }
+}
+
+FileStream::FileStream(FILE* file, Stream* log_stream)
+    : Stream(log_stream), file_(file), offset_(0), should_close_(false) {}
+
+FileStream::FileStream(FileStream&& other) {
+  *this = std::move(other);
+}
+
+FileStream& FileStream::operator=(FileStream&& other) {
+  file_ = other.file_;
+  offset_ = other.offset_;
+  should_close_ = other.should_close_;
+  other.file_ = nullptr;
+  other.offset_ = 0;
+  other.should_close_ = false;
+  return *this;
+}
+
+FileStream::~FileStream() {
+  // We don't want to close existing files (stdout/sterr, for example).
+  if (should_close_) {
+    fclose(file_);
+  }
+}
+
+void FileStream::Flush() {
+  if (file_) fflush(file_);
+}
+
+Result FileStream::WriteDataImpl(size_t at, const void* data, size_t size) {
+  if (!file_) {
+    return Result::Error;
+  }
+  if (size == 0) {
+    return Result::Ok;
+  }
+  if (at != offset_) {
+    if (fseek(file_, at, SEEK_SET) != 0) {
+      ERROR("fseek offset=%" PRIzd " failed, errno=%d\n", size, errno);
+      return Result::Error;
+    }
+    offset_ = at;
+  }
+  if (fwrite(data, size, 1, file_) != 1) {
+    ERROR("fwrite size=%" PRIzd " failed, errno=%d\n", size, errno);
+    return Result::Error;
+  }
+  offset_ += size;
+  return Result::Ok;
+}
+
+Result FileStream::MoveDataImpl(size_t dst_offset,
+                                size_t src_offset,
+                                size_t size) {
+  if (!file_) {
+    return Result::Error;
+  }
+  if (size == 0) {
+    return Result::Ok;
+  }
+  // TODO(binji): implement if needed.
+  ERROR0("FileStream::MoveDataImpl not implemented!\n");
+  return Result::Error;
+}
+
+Result FileStream::TruncateImpl(size_t size) {
+  if (!file_) {
+    return Result::Error;
+  }
+  // TODO(binji): implement if needed.
+  ERROR0("FileStream::TruncateImpl not implemented!\n");
+  return Result::Error;
+}
+
+// static
+std::unique_ptr<FileStream> FileStream::CreateStdout() {
+  return std::unique_ptr<FileStream>(new FileStream(stdout));
+}
+
+// static
+std::unique_ptr<FileStream> FileStream::CreateStderr() {
+  return std::unique_ptr<FileStream>(new FileStream(stderr));
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/stream.h
new file mode 100644 (file)
index 0000000..66582fa
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * 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_STREAM_H_
+#define WABT_STREAM_H_
+
+#include <cassert>
+#include <memory>
+#include <vector>
+
+#include "src/common.h"
+
+namespace wabt {
+
+/* whether to display the ASCII characters in the debug output for
+ * write_memory */
+enum class PrintChars {
+  No = 0,
+  Yes = 1,
+};
+
+class Stream {
+ public:
+  explicit Stream(Stream* log_stream = nullptr);
+  virtual ~Stream() = default;
+
+  size_t offset() { return offset_; }
+  Result result() { return result_; }
+
+  void set_log_stream(Stream* stream) {
+    assert(stream);
+    log_stream_ = stream;
+  }
+
+  Stream& log_stream() {
+    assert(log_stream_);
+    return *log_stream_;
+  }
+
+  bool has_log_stream() const { return log_stream_ != nullptr; }
+
+  void ClearOffset() { offset_ = 0; }
+  void AddOffset(ssize_t delta);
+
+  void WriteData(const void* src,
+                 size_t size,
+                 const char* desc = nullptr,
+                 PrintChars = PrintChars::No);
+
+  template <typename T>
+  void WriteData(const std::vector<T> src,
+                 const char* desc,
+                 PrintChars print_chars = PrintChars::No) {
+    if (!src.empty()) {
+      WriteData(src.data(), src.size() * sizeof(T), desc, print_chars);
+    }
+  }
+
+  void WriteDataAt(size_t offset,
+                   const void* src,
+                   size_t size,
+                   const char* desc = nullptr,
+                   PrintChars = PrintChars::No);
+
+  void MoveData(size_t dst_offset, size_t src_offset, size_t size);
+
+  void Truncate(size_t size);
+
+  void WABT_PRINTF_FORMAT(2, 3) Writef(const char* format, ...);
+
+  // Specified as uint32_t instead of uint8_t so we can check if the value
+  // given is in range before wrapping.
+  void WriteU8(uint32_t value,
+               const char* desc = nullptr,
+               PrintChars print_chars = PrintChars::No) {
+    assert(value <= UINT8_MAX);
+    Write(static_cast<uint8_t>(value), desc, print_chars);
+  }
+  void WriteU32(uint32_t value,
+                const char* desc = nullptr,
+                PrintChars print_chars = PrintChars::No) {
+    Write(value, desc, print_chars);
+  }
+  void WriteU64(uint64_t value,
+                const char* desc = nullptr,
+                PrintChars print_chars = PrintChars::No) {
+    Write(value, desc, print_chars);
+  }
+  void WriteU128(v128 value,
+                 const char* desc = nullptr,
+                 PrintChars print_chars = PrintChars::No) {
+    Write(value, desc, print_chars);
+  }
+
+  void WriteChar(char c,
+                 const char* desc = nullptr,
+                 PrintChars print_chars = PrintChars::No) {
+    WriteU8(static_cast<unsigned char>(c), desc, print_chars);
+  }
+
+  // Dump memory as text, similar to the xxd format.
+  void WriteMemoryDump(const void* start,
+                       size_t size,
+                       size_t offset = 0,
+                       PrintChars print_chars = PrintChars::No,
+                       const char* prefix = nullptr,
+                       const char* desc = nullptr);
+
+  // Convenience functions for writing enums.
+  template <typename T>
+  void WriteU8Enum(T value,
+                   const char* desc = nullptr,
+                   PrintChars print_chars = PrintChars::No) {
+    WriteU8(static_cast<uint32_t>(value), desc, print_chars);
+  }
+
+  virtual void Flush() {}
+
+ protected:
+  virtual Result WriteDataImpl(size_t offset,
+                               const void* data,
+                               size_t size) = 0;
+  virtual Result MoveDataImpl(size_t dst_offset,
+                              size_t src_offset,
+                              size_t size) = 0;
+  virtual Result TruncateImpl(size_t size) = 0;
+
+ private:
+  template <typename T>
+  void Write(const T& data, const char* desc, PrintChars print_chars) {
+#if WABT_BIG_ENDIAN
+    char tmp[sizeof(T)];
+    memcpy(tmp, &data, sizeof(tmp));
+    SwapBytesSized(tmp, sizeof(tmp));
+    WriteData(tmp, sizeof(tmp), desc, print_chars);
+#else
+    WriteData(&data, sizeof(data), desc, print_chars);
+#endif
+  }
+
+  size_t offset_;
+  Result result_;
+  // Not owned. If non-null, log all writes to this stream.
+  Stream* log_stream_;
+};
+
+struct OutputBuffer {
+  Result WriteToFile(string_view filename) const;
+
+  void clear() { data.clear(); }
+  size_t size() const { return data.size(); }
+
+  std::vector<uint8_t> data;
+};
+
+class MemoryStream : public Stream {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(MemoryStream);
+  explicit MemoryStream(Stream* log_stream = nullptr);
+  explicit MemoryStream(std::unique_ptr<OutputBuffer>&&,
+                        Stream* log_stream = nullptr);
+
+  OutputBuffer& output_buffer() { return *buf_; }
+  std::unique_ptr<OutputBuffer> ReleaseOutputBuffer();
+
+  void Clear();
+
+  Result WriteToFile(string_view filename) {
+    return buf_->WriteToFile(filename);
+  }
+
+ protected:
+  Result WriteDataImpl(size_t offset, const void* data, size_t size) override;
+  Result MoveDataImpl(size_t dst_offset,
+                      size_t src_offset,
+                      size_t size) override;
+  Result TruncateImpl(size_t size) override;
+
+ private:
+  std::unique_ptr<OutputBuffer> buf_;
+};
+
+class FileStream : public Stream {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(FileStream);
+  explicit FileStream(string_view filename, Stream* log_stream = nullptr);
+  explicit FileStream(FILE*, Stream* log_stream = nullptr);
+  FileStream(FileStream&&);
+  FileStream& operator=(FileStream&&);
+  ~FileStream() override;
+
+  static std::unique_ptr<FileStream> CreateStdout();
+  static std::unique_ptr<FileStream> CreateStderr();
+
+  bool is_open() const { return file_ != nullptr; }
+
+  void Flush() override;
+
+ protected:
+  Result WriteDataImpl(size_t offset, const void* data, size_t size) override;
+  Result MoveDataImpl(size_t dst_offset,
+                      size_t src_offset,
+                      size_t size) override;
+  Result TruncateImpl(size_t size) override;
+
+ private:
+  FILE* file_;
+  size_t offset_;
+  bool should_close_;
+};
+
+}  // namespace wabt
+
+#endif /* WABT_STREAM_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.cc
new file mode 100644 (file)
index 0000000..bb32410
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * 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/string-view.h"
+
+#include <algorithm>
+#include <limits>
+
+namespace wabt {
+
+void string_view::remove_prefix(size_type n) {
+  assert(n <= size_);
+  data_ += n;
+  size_ -= n;
+}
+
+void string_view::remove_suffix(size_type n) {
+  assert(n <= size_);
+  size_ -= n;
+}
+
+void string_view::swap(string_view& s) noexcept {
+  std::swap(data_, s.data_);
+  std::swap(size_, s.size_);
+}
+
+string_view::operator std::string() const {
+  return std::string(data_, size_);
+}
+
+std::string string_view::to_string() const {
+  return std::string(data_, size_);
+}
+
+constexpr string_view::size_type string_view::max_size() const noexcept {
+  return std::numeric_limits<size_type>::max();
+}
+
+string_view::size_type string_view::copy(char* s,
+                                         size_type n,
+                                         size_type pos) const {
+  assert(pos <= size_);
+  size_t count = std::min(n, size_ - pos);
+  traits_type::copy(s, data_ + pos, count);
+  return count;
+}
+
+string_view string_view::substr(size_type pos, size_type n) const {
+  assert(pos <= size_);
+  size_t count = std::min(n, size_ - pos);
+  return string_view(data_ + pos, count);
+}
+
+int string_view::compare(string_view s) const noexcept {
+  size_type rlen = std::min(size_, s.size_);
+  int result = traits_type::compare(data_, s.data_, rlen);
+  if (result != 0 || size_ == s.size_) {
+    return result;
+  }
+  return size_ < s.size_ ? -1 : 1;
+}
+
+int string_view::compare(size_type pos1, size_type n1, string_view s) const {
+  return substr(pos1, n1).compare(s);
+}
+
+int string_view::compare(size_type pos1,
+                         size_type n1,
+                         string_view s,
+                         size_type pos2,
+                         size_type n2) const {
+  return substr(pos1, n1).compare(s.substr(pos2, n2));
+}
+
+int string_view::compare(const char* s) const {
+  return compare(string_view(s));
+}
+
+int string_view::compare(size_type pos1, size_type n1, const char* s) const {
+  return substr(pos1, n1).compare(string_view(s));
+}
+
+int string_view::compare(size_type pos1,
+                         size_type n1,
+                         const char* s,
+                         size_type n2) const {
+  return substr(pos1, n1).compare(string_view(s, n2));
+}
+
+string_view::size_type string_view::find(string_view s, size_type pos) const
+    noexcept {
+  pos = std::min(pos, size_);
+  const_iterator iter = std::search(begin() + pos, end(), s.begin(), s.end());
+  return iter == end() ? npos : iter - begin();
+}
+
+string_view::size_type string_view::find(char c, size_type pos) const noexcept {
+  return find(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find(const char* s,
+                                         size_type pos,
+                                         size_type n) const {
+  return find(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::find(const char* s, size_type pos) const {
+  return find(string_view(s), pos);
+}
+
+string_view::size_type string_view::rfind(string_view s, size_type pos) const
+    noexcept {
+  pos = std::min(std::min(pos, size_ - s.size_) + s.size_, size_);
+  reverse_iterator iter = std::search(reverse_iterator(begin() + pos), rend(),
+                                      s.rbegin(), s.rend());
+  return iter == rend() ? npos : (rend() - iter - s.size_);
+}
+
+string_view::size_type string_view::rfind(char c, size_type pos) const
+    noexcept {
+  return rfind(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::rfind(const char* s,
+                                          size_type pos,
+                                          size_type n) const {
+  return rfind(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::rfind(const char* s, size_type pos) const {
+  return rfind(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_first_of(string_view s,
+                                                  size_type pos) const
+    noexcept {
+  pos = std::min(pos, size_);
+  const_iterator iter =
+      std::find_first_of(begin() + pos, end(), s.begin(), s.end());
+  return iter == end() ? npos : iter - begin();
+}
+
+string_view::size_type string_view::find_first_of(char c, size_type pos) const
+    noexcept {
+  return find_first_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_first_of(const char* s,
+                                                  size_type pos,
+                                                  size_type n) const {
+  return find_first_of(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::find_first_of(const char* s,
+                                                  size_type pos) const {
+  return find_first_of(string_view(s), pos);
+}
+
+string_view::size_type string_view::find_last_of(string_view s,
+                                                 size_type pos) const noexcept {
+  pos = std::min(pos, size_ - 1);
+  reverse_iterator iter = std::find_first_of(
+      reverse_iterator(begin() + (pos + 1)), rend(), s.begin(), s.end());
+  return iter == rend() ? npos : (rend() - iter - 1);
+}
+
+string_view::size_type string_view::find_last_of(char c, size_type pos) const
+    noexcept {
+  return find_last_of(string_view(&c, 1), pos);
+}
+
+string_view::size_type string_view::find_last_of(const char* s,
+                                                 size_type pos,
+                                                 size_type n) const {
+  return find_last_of(string_view(s, n), pos);
+}
+
+string_view::size_type string_view::find_last_of(const char* s,
+                                                 size_type pos) const {
+  return find_last_of(string_view(s), pos);
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/string-view.h
new file mode 100644 (file)
index 0000000..534e675
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * 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_STRING_VIEW_H_
+#define WABT_STRING_VIEW_H_
+
+#include <cassert>
+#include <functional>
+#include <iterator>
+#include <ostream>
+#include <string>
+
+#include "src/hash-util.h"
+
+namespace wabt {
+
+// This is a simplified implemention of C++17's basic_string_view template.
+//
+// Missing features:
+// * Not a template
+// * No allocator support
+// * Some functions are not implemented
+// * Asserts instead of exceptions
+// * Some functions are not constexpr because we don't compile in C++17 mode
+
+class string_view {
+ public:
+  typedef std::char_traits<char> traits_type;
+  typedef char value_type;
+  typedef char* pointer;
+  typedef const char* const_pointer;
+  typedef char& reference;
+  typedef const char& const_reference;
+  typedef const char* const_iterator;
+  typedef const_iterator iterator;
+  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
+  typedef const_reverse_iterator reverse_iterator;
+  typedef std::size_t size_type;
+  typedef std::ptrdiff_t difference_type;
+  static const size_type npos = size_type(-1);
+
+  // construction and assignment
+  constexpr string_view() noexcept;
+  constexpr string_view(const string_view&) noexcept = default;
+  string_view& operator=(const string_view&) noexcept = default;
+  string_view(const std::string& str) noexcept;
+  /*constexpr*/ string_view(const char* str);
+  constexpr string_view(const char* str, size_type len);
+
+  // iterator support
+  constexpr const_iterator begin() const noexcept;
+  constexpr const_iterator end() const noexcept;
+  constexpr const_iterator cbegin() const noexcept;
+  constexpr const_iterator cend() const noexcept;
+  const_reverse_iterator rbegin() const noexcept;
+  const_reverse_iterator rend() const noexcept;
+  const_reverse_iterator crbegin() const noexcept;
+  const_reverse_iterator crend() const noexcept;
+
+  // capacity
+  constexpr size_type size() const noexcept;
+  constexpr size_type length() const noexcept;
+  constexpr size_type max_size() const noexcept;
+  constexpr bool empty() const noexcept;
+
+  // element access
+  constexpr const_reference operator[](size_type pos) const;
+  /*constexpr*/ const_reference at(size_type pos) const;
+  /*constexpr*/ const_reference front() const;
+  /*constexpr*/ const_reference back() const;
+  constexpr const_pointer data() const noexcept;
+
+  // modifiers
+  /*constexpr*/ void remove_prefix(size_type n);
+  /*constexpr*/ void remove_suffix(size_type n);
+  /*constexpr*/ void swap(string_view& s) noexcept;
+
+  // string operations
+  explicit operator std::string() const;
+  std::string to_string() const;
+  size_type copy(char* s, size_type n, size_type pos = 0) const;
+  /*constexpr*/ string_view substr(size_type pos = 0, size_type n = npos) const;
+  /*constexpr*/ int compare(string_view s) const noexcept;
+  /*constexpr*/ int compare(size_type pos1, size_type n1, string_view s) const;
+  /*constexpr*/ int compare(size_type pos1,
+                            size_type n1,
+                            string_view s,
+                            size_type pos2,
+                            size_type n2) const;
+  /*constexpr*/ int compare(const char* s) const;
+  /*constexpr*/ int compare(size_type pos1, size_type n1, const char* s) const;
+  /*constexpr*/ int compare(size_type pos1,
+                            size_type n1,
+                            const char* s,
+                            size_type n2) const;
+  /*constexpr*/ size_type find(string_view s, size_type pos = 0) const noexcept;
+  /*constexpr*/ size_type find(char c, size_type pos = 0) const noexcept;
+  /*constexpr*/ size_type find(const char* s, size_type pos, size_type n) const;
+  /*constexpr*/ size_type find(const char* s, size_type pos = 0) const;
+  /*constexpr*/ size_type rfind(string_view s, size_type pos = npos) const
+      noexcept;
+  /*constexpr*/ size_type rfind(char c, size_type pos = npos) const noexcept;
+  /*constexpr*/ size_type rfind(const char* s,
+                                size_type pos,
+                                size_type n) const;
+  /*constexpr*/ size_type rfind(const char* s, size_type pos = npos) const;
+  /*constexpr*/ size_type find_first_of(string_view s, size_type pos = 0) const
+      noexcept;
+  /*constexpr*/ size_type find_first_of(char c, size_type pos = 0) const
+      noexcept;
+  /*constexpr*/ size_type find_first_of(const char* s,
+                                        size_type pos,
+                                        size_type n) const;
+  /*constexpr*/ size_type find_first_of(const char* s, size_type pos = 0) const;
+  /*constexpr*/ size_type find_last_of(string_view s,
+                                       size_type pos = npos) const noexcept;
+  /*constexpr*/ size_type find_last_of(char c, size_type pos = npos) const
+      noexcept;
+  /*constexpr*/ size_type find_last_of(const char* s,
+                                       size_type pos,
+                                       size_type n) const;
+  /*constexpr*/ size_type find_last_of(const char* s,
+                                       size_type pos = npos) const;
+
+// TODO(binji): These are defined by C++17 basic_string_view but not
+// implemented here.
+#if 0
+  constexpr size_type find_first_not_of(string_view s, size_type pos = 0) const
+      noexcept;
+  constexpr size_type find_first_not_of(char c, size_type pos = 0) const
+      noexcept;
+  constexpr size_type find_first_not_of(const char* s,
+                                        size_type pos,
+                                        size_type n) const;
+  constexpr size_type find_first_not_of(const char* s, size_type pos = 0) const;
+  constexpr size_type find_last_not_of(string_view s,
+                                       size_type pos = npos) const noexcept;
+  constexpr size_type find_last_not_of(char c, size_type pos = npos) const
+      noexcept;
+  constexpr size_type find_last_not_of(const char* s,
+                                       size_type pos,
+                                       size_type n) const;
+  constexpr size_type find_last_not_of(const char* s,
+                                       size_type pos = npos) const;
+#endif
+
+ private:
+  const char* data_;
+  size_type size_;
+};
+
+// non-member comparison functions
+inline bool operator==(string_view x, string_view y) noexcept {
+  return x.compare(y) == 0;
+}
+
+inline bool operator!=(string_view x, string_view y) noexcept {
+  return x.compare(y) != 0;
+}
+
+inline bool operator<(string_view x, string_view y) noexcept {
+  return x.compare(y) < 0;
+}
+
+inline bool operator>(string_view x, string_view y) noexcept {
+  return x.compare(y) > 0;
+}
+
+inline bool operator<=(string_view x, string_view y) noexcept {
+  return x.compare(y) <= 0;
+}
+
+inline bool operator>=(string_view x, string_view y) noexcept {
+  return x.compare(y) >= 0;
+}
+
+// non-member append.
+inline std::string& operator+=(std::string& x, string_view y) {
+  x.append(y.data(), y.size());
+  return x;
+}
+
+inline std::string operator+(string_view x, string_view y) {
+  std::string s;
+  s.reserve(x.size() + y.size());
+  s.append(x.data(), x.size());
+  s.append(y.data(), y.size());
+  return s;
+}
+
+inline std::string operator+(const std::string& x, string_view y) {
+  return string_view(x) + y;
+}
+
+inline std::string operator+(string_view x, const std::string& y) {
+  return x + string_view(y);
+}
+
+inline std::string operator+(const char* x, string_view y) {
+  return string_view(x) + y;
+}
+
+inline std::string operator+(string_view x, const char* y) {
+  return x + string_view(y);
+}
+
+inline void cat_concatenate(std::string&) {}
+
+template<typename T, typename ...Ts>
+void cat_concatenate(std::string& s, const T& t, const Ts&... args) {
+    s += t;
+    cat_concatenate(s, args...);
+}
+
+inline size_t cat_compute_size() { return 0; }
+
+template<typename T, typename ...Ts>
+size_t cat_compute_size(const T& t, const Ts&... args) {
+    return string_view(t).size() + cat_compute_size(args...);
+}
+
+// Is able to concatenate any combination of string/string_view/char*
+template<typename ...Ts> std::string cat(const Ts&... args) {
+    std::string s;
+    s.reserve(cat_compute_size(args...));
+    cat_concatenate(s, args...);
+    return s;
+}
+
+inline constexpr string_view::string_view() noexcept
+    : data_(nullptr), size_(0) {}
+
+inline string_view::string_view(const std::string& str) noexcept
+    : data_(str.data()), size_(str.size()) {}
+
+inline string_view::string_view(const char* str)
+    : data_(str), size_(traits_type::length(str)) {}
+
+inline constexpr string_view::string_view(const char* str, size_type len)
+    : data_(str), size_(len) {}
+
+inline constexpr string_view::const_iterator string_view::begin() const
+    noexcept {
+  return data_;
+}
+
+inline constexpr string_view::const_iterator string_view::end() const noexcept {
+  return data_ + size_;
+}
+
+inline constexpr string_view::const_iterator string_view::cbegin() const
+    noexcept {
+  return data_;
+}
+
+inline constexpr string_view::const_iterator string_view::cend() const
+    noexcept {
+  return data_ + size_;
+}
+
+inline string_view::const_reverse_iterator string_view::rbegin() const
+    noexcept {
+  return const_reverse_iterator(end());
+}
+
+inline string_view::const_reverse_iterator string_view::rend() const noexcept {
+  return const_reverse_iterator(begin());
+}
+
+inline string_view::const_reverse_iterator string_view::crbegin() const
+    noexcept {
+  return const_reverse_iterator(cend());
+}
+
+inline string_view::const_reverse_iterator string_view::crend() const noexcept {
+  return const_reverse_iterator(cbegin());
+}
+
+constexpr inline string_view::size_type string_view::size() const noexcept {
+  return size_;
+}
+
+constexpr inline string_view::size_type string_view::length() const noexcept {
+  return size_;
+}
+
+constexpr inline bool string_view::empty() const noexcept {
+  return size_ == 0;
+}
+
+constexpr inline string_view::const_reference string_view::operator[](
+    size_type pos) const {
+  return data_[pos];
+}
+
+inline string_view::const_reference string_view::at(size_type pos) const {
+  assert(pos < size_);
+  return data_[pos];
+}
+
+inline string_view::const_reference string_view::front() const {
+  assert(!empty());
+  return *data_;
+}
+
+inline string_view::const_reference string_view::back() const {
+  assert(!empty());
+  return data_[size_ - 1];
+}
+
+constexpr inline string_view::const_pointer string_view::data() const noexcept {
+  return data_;
+}
+
+inline std::ostream& operator<<(std::ostream& os, string_view sv) {
+    os.write(sv.data(), sv.size());
+    return os;
+}
+
+}  // namespace wabt
+
+namespace std {
+
+// hash support
+template <>
+struct hash<::wabt::string_view> {
+  ::wabt::hash_code operator()(const ::wabt::string_view& sv) {
+    return ::wabt::HashRange(sv.begin(), sv.end());
+  }
+};
+
+}  // namespace std
+
+#endif  // WABT_STRING_VIEW_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-binary-reader.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-binary-reader.cc
new file mode 100644 (file)
index 0000000..a96ccdb
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2018 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 "gtest/gtest.h"
+
+#include "src/binary-reader.h"
+#include "src/binary-reader-nop.h"
+#include "src/leb128.h"
+#include "src/opcode.h"
+
+using namespace wabt;
+
+namespace {
+
+struct BinaryReaderError : BinaryReaderNop {
+  bool OnError(const Error& error) override {
+    first_error = error;
+    return true;  // Error handled.
+  }
+
+  Error first_error;
+};
+
+}  // End of anonymous namespace
+
+TEST(BinaryReader, DisabledOpcodes) {
+  // Use the default features.
+  ReadBinaryOptions options;
+
+  // Loop through all opcodes.
+  for (uint32_t i = 0; i < static_cast<uint32_t>(Opcode::Invalid); ++i) {
+    Opcode opcode(static_cast<Opcode::Enum>(i));
+    if (opcode.IsEnabled(options.features)) {
+      continue;
+    }
+
+    // Use a shorter name to make the clang-formatted table below look nicer.
+    std::vector<uint8_t> b = opcode.GetBytes();
+    assert(b.size() <= 3);
+    b.resize(3);
+
+    uint8_t data[] = {
+        0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00,  // magic + version
+        0x01, 0x04, 0x01, 0x60, 0x00, 0x00,  // type section: 1 type, (func)
+        0x03, 0x02, 0x01, 0x00,              // func section: 1 func, type 0
+        0x0a, 0x07, 0x01, 0x05, 0x00,        // code section: 1 func, 0 locals
+        b[0], b[1], b[2],  // The instruction, padded with zeroes
+        0x0b,              // end
+    };
+    const size_t size = sizeof(data);
+
+    BinaryReaderError reader;
+    Result result = ReadBinary(data, size, &reader, options);
+    EXPECT_EQ(Result::Error, result);
+
+    // This relies on the binary reader checking whether the opcode is allowed
+    // before reading any further data needed by the instruction.
+    const std::string& message = reader.first_error.message;
+    EXPECT_EQ(0u, message.find("unexpected opcode"))
+        << "Got error message: " << message;
+  }
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-circular-array.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-circular-array.cc
new file mode 100644 (file)
index 0000000..aefea51
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * 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 "gtest/gtest.h"
+
+#include <memory>
+
+#include "src/circular-array.h"
+
+using namespace wabt;
+
+namespace {
+
+struct TestObject {
+  static int construct_count;
+  static int destruct_count;
+
+  TestObject(int data = 0, int data2 = 0) : data(data), data2(data2) {
+    construct_count++;
+  }
+
+  TestObject(const TestObject& other) {
+    *this = other;
+    construct_count++;
+  }
+
+  TestObject& operator=(const TestObject& other) {
+    data = other.data;
+    data2 = other.data2;
+    return *this;
+  }
+
+  TestObject(TestObject&& other) { *this = std::move(other); }
+
+  TestObject& operator=(TestObject&& other) {
+    data = other.data;
+    data2 = other.data2;
+    other.moved = true;
+    return *this;
+  }
+
+  ~TestObject() {
+    if (!moved) {
+      destruct_count++;
+    }
+  }
+
+  int data = 0;
+  int data2 = 0;
+  bool moved = false;
+};
+
+// static
+int TestObject::construct_count = 0;
+// static
+int TestObject::destruct_count = 0;
+
+class CircularArrayTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Reset to 0 even if the previous test leaked objects to keep the tests
+    // independent.
+    TestObject::construct_count = 0;
+    TestObject::destruct_count = 0;
+  }
+
+  virtual void TearDown() {
+    ASSERT_EQ(0, TestObject::construct_count - TestObject::destruct_count)
+        << "construct count: " << TestObject::construct_count
+        << ", destruct_count: " << TestObject::destruct_count;
+  }
+
+  template <size_t N>
+  void AssertCircularArrayEq(const CircularArray<TestObject, N>& ca,
+                             const std::vector<int>& expected) {
+    if (expected.empty()) {
+      ASSERT_EQ(0U, ca.size());
+      ASSERT_TRUE(ca.empty());
+    } else {
+      ASSERT_EQ(expected.size(), ca.size());
+      ASSERT_FALSE(ca.empty());
+
+      ASSERT_EQ(expected.front(), ca.front().data);
+      ASSERT_EQ(expected.back(), ca.back().data);
+
+      for (size_t i = 0; i < ca.size(); ++i) {
+        ASSERT_EQ(expected[i], ca.at(i).data);
+        ASSERT_EQ(expected[i], ca[i].data);
+      }
+    }
+  }
+};
+
+}  // end anonymous namespace
+
+// Basic API tests
+
+TEST_F(CircularArrayTest, default_constructor) {
+  CircularArray<TestObject, 2> ca;
+}
+
+TEST_F(CircularArrayTest, at) {
+  CircularArray<TestObject, 2> ca;
+  ca.push_back(TestObject(1));
+  ca.push_back(TestObject(2));
+
+  ASSERT_EQ(1, ca.at(0).data);
+  ASSERT_EQ(2, ca.at(1).data);
+}
+
+TEST_F(CircularArrayTest, const_at) {
+  CircularArray<TestObject, 2> ca;
+  const auto& cca = ca;
+
+  ca.push_back(TestObject(1));
+  ca.push_back(TestObject(2));
+
+  ASSERT_EQ(1, cca.at(0).data);
+  ASSERT_EQ(2, cca.at(1).data);
+}
+
+TEST_F(CircularArrayTest, operator_brackets) {
+  CircularArray<TestObject, 2> ca;
+  ca.push_back(TestObject(1));
+  ca.push_back(TestObject(2));
+
+  ASSERT_EQ(1, ca[0].data);
+  ASSERT_EQ(2, ca[1].data);
+}
+
+TEST_F(CircularArrayTest, const_operator_brackets) {
+  CircularArray<TestObject, 2> ca;
+  const auto& cca = ca;
+
+  ca.push_back(TestObject(1));
+  ca.push_back(TestObject(2));
+
+  ASSERT_EQ(1, cca[0].data);
+  ASSERT_EQ(2, cca[1].data);
+}
+
+TEST_F(CircularArrayTest, back) {
+  CircularArray<TestObject, 2> ca;
+
+  ca.push_back(TestObject(1));
+  ASSERT_EQ(1, ca.back().data);
+
+  ca.push_back(TestObject(2));
+  ASSERT_EQ(2, ca.back().data);
+}
+
+TEST_F(CircularArrayTest, const_back) {
+  CircularArray<TestObject, 2> ca;
+  const auto& cca = ca;
+
+  ca.push_back(TestObject(1));
+  ASSERT_EQ(1, cca.back().data);
+
+  ca.push_back(TestObject(2));
+  ASSERT_EQ(2, cca.back().data);
+}
+
+TEST_F(CircularArrayTest, empty) {
+  CircularArray<TestObject, 2> ca;
+
+  ASSERT_TRUE(ca.empty());
+
+  ca.push_back(TestObject(1));
+  ASSERT_FALSE(ca.empty());
+
+  ca.push_back(TestObject(2));
+  ASSERT_FALSE(ca.empty());
+
+  ca.pop_back();
+  ASSERT_FALSE(ca.empty());
+
+  ca.pop_back();
+  ASSERT_TRUE(ca.empty());
+}
+
+TEST_F(CircularArrayTest, front) {
+  CircularArray<TestObject, 2> ca;
+
+  ca.push_back(TestObject(1));
+  ASSERT_EQ(1, ca.front().data);
+
+  ca.push_back(TestObject(2));
+  ASSERT_EQ(1, ca.front().data);
+}
+
+TEST_F(CircularArrayTest, const_front) {
+  CircularArray<TestObject, 2> ca;
+  const auto& cca = ca;
+
+  ca.push_back(TestObject(1));
+  ASSERT_EQ(1, cca.front().data);
+
+  ca.push_back(TestObject(2));
+  ASSERT_EQ(1, cca.front().data);
+}
+
+TEST_F(CircularArrayTest, size) {
+  CircularArray<TestObject, 2> ca;
+
+  ASSERT_EQ(0U, ca.size());
+
+  ca.push_back(TestObject(1));
+  ASSERT_EQ(1U, ca.size());
+
+  ca.push_back(TestObject(2));
+  ASSERT_EQ(2U, ca.size());
+
+  ca.pop_back();
+  ASSERT_EQ(1U, ca.size());
+
+  ca.pop_back();
+  ASSERT_EQ(0U, ca.size());
+}
+
+TEST_F(CircularArrayTest, clear) {
+  CircularArray<TestObject, 2> ca;
+
+  ca.push_back(TestObject(1));
+  ca.push_back(TestObject(2));
+  ASSERT_EQ(2U, ca.size());
+
+  ca.clear();
+  ASSERT_EQ(0U, ca.size());
+}
+
+// More involved tests
+
+TEST_F(CircularArrayTest, circular) {
+  CircularArray<TestObject, 4> ca;
+
+  ca.push_back(TestObject(1));
+  AssertCircularArrayEq(ca, {1});
+
+  ca.push_back(TestObject(2));
+  AssertCircularArrayEq(ca, {1, 2});
+
+  ca.push_back(TestObject(3));
+  AssertCircularArrayEq(ca, {1, 2, 3});
+
+  ca.pop_front();
+  AssertCircularArrayEq(ca, {2, 3});
+
+  ca.push_back(TestObject(4));
+  AssertCircularArrayEq(ca, {2, 3, 4});
+
+  ca.pop_front();
+  AssertCircularArrayEq(ca, {3, 4});
+
+  ca.pop_front();
+  AssertCircularArrayEq(ca, {4});
+
+  ca.push_back(TestObject(5));
+  AssertCircularArrayEq(ca, {4, 5});
+
+  ca.push_back(TestObject(6));
+  AssertCircularArrayEq(ca, {4, 5, 6});
+
+  ca.pop_back();
+  AssertCircularArrayEq(ca, {4, 5});
+
+  ca.pop_back();
+  AssertCircularArrayEq(ca, {4});
+
+  ca.pop_front();
+  AssertCircularArrayEq(ca, {});
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-filenames.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-filenames.cc
new file mode 100644 (file)
index 0000000..5b0282f
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 "gtest/gtest.h"
+
+#include "src/filenames.h"
+
+using namespace wabt;
+
+namespace {
+
+void assert_string_view_eq(const char* s, string_view sv) {
+  size_t len = std::strlen(s);
+  ASSERT_EQ(len, sv.size());
+  for (size_t i = 0; i < len; ++i) {
+    ASSERT_EQ(s[i], sv[i]);
+  }
+}
+
+}  // end anonymous namespace
+
+TEST(filenames, GetBasename) {
+  assert_string_view_eq("foo.txt", GetBasename("/bar/dir/foo.txt"));
+  assert_string_view_eq("foo.txt", GetBasename("bar/dir/foo.txt"));
+  assert_string_view_eq("foo.txt", GetBasename("/foo.txt"));
+  assert_string_view_eq("foo.txt", GetBasename("\\bar\\dir\\foo.txt"));
+  assert_string_view_eq("foo.txt", GetBasename("bar\\dir\\foo.txt"));
+  assert_string_view_eq("foo.txt", GetBasename("\\foo.txt"));
+  assert_string_view_eq("foo.txt", GetBasename("foo.txt"));
+  assert_string_view_eq("foo", GetBasename("foo"));
+  assert_string_view_eq("", GetBasename(""));
+}
+
+TEST(filenames, GetExtension) {
+  assert_string_view_eq(".txt", GetExtension("/bar/dir/foo.txt"));
+  assert_string_view_eq(".txt", GetExtension("bar/dir/foo.txt"));
+  assert_string_view_eq(".txt", GetExtension("foo.txt"));
+  assert_string_view_eq("", GetExtension("foo"));
+  assert_string_view_eq("", GetExtension(""));
+}
+
+TEST(filenames, StripExtension) {
+  assert_string_view_eq("/bar/dir/foo", StripExtension("/bar/dir/foo.txt"));
+  assert_string_view_eq("bar/dir/foo", StripExtension("bar/dir/foo.txt"));
+  assert_string_view_eq("foo", StripExtension("foo.txt"));
+  assert_string_view_eq("foo", StripExtension("foo"));
+  assert_string_view_eq("", StripExtension(""));
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-hexfloat.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-hexfloat.cc
new file mode 100644 (file)
index 0000000..7b49351
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+ * 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 <cstdio>
+#include <thread>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "src/literal.h"
+
+#define FOREACH_UINT32_MULTIPLIER 1
+
+#define FOREACH_UINT32(bits) \
+  uint32_t last_bits = 0;    \
+  uint32_t bits = shard;     \
+  int last_top_byte = -1;    \
+  for (; bits >= last_bits;  \
+       last_bits = bits, bits += num_threads_ * FOREACH_UINT32_MULTIPLIER)
+
+#define LOG_COMPLETION(bits)                                                  \
+  if (shard == 0) {                                                           \
+    int top_byte = bits >> 24;                                                \
+    if (top_byte != last_top_byte) {                                          \
+      printf("value: 0x%08x (%d%%)\r", bits,                                  \
+             static_cast<int>(static_cast<double>(bits) * 100 / UINT32_MAX)); \
+      fflush(stdout);                                                         \
+      last_top_byte = top_byte;                                               \
+    }                                                                         \
+  }
+
+#define LOG_DONE()     \
+  if (shard == 0) {    \
+    printf("done.\n"); \
+    fflush(stdout);    \
+  }
+
+using namespace wabt;
+
+template <typename T, typename F>
+T bit_cast(F value) {
+  T result;
+  memcpy(&result, &value, sizeof(result));
+  return result;
+}
+
+static bool is_infinity_or_nan(uint32_t float_bits) {
+  return ((float_bits >> 23) & 0xff) == 0xff;
+}
+
+static bool is_infinity_or_nan(uint64_t double_bits) {
+  return ((double_bits >> 52) & 0x7ff) == 0x7ff;
+}
+
+class ThreadedTest : public ::testing::Test {
+ protected:
+  static const int kDefaultNumThreads = 2;
+
+  virtual void SetUp() {
+    num_threads_ = std::thread::hardware_concurrency();
+    if (num_threads_ == 0)
+      num_threads_ = kDefaultNumThreads;
+  }
+
+  virtual void RunShard(int shard) = 0;
+
+  void RunThreads() {
+    std::vector<std::thread> threads;
+
+    for (int i = 0; i < num_threads_; ++i) {
+      threads.emplace_back(&ThreadedTest::RunShard, this, i);
+    }
+
+    for (std::thread& thread : threads) {
+      thread.join();
+    }
+  }
+
+  int num_threads_;
+};
+
+/* floats */
+class AllFloatsParseTest : public ThreadedTest {
+ protected:
+  virtual void RunShard(int shard) {
+    char buffer[100];
+    FOREACH_UINT32(bits) {
+      LOG_COMPLETION(bits);
+      if (is_infinity_or_nan(bits))
+        continue;
+
+      float value = bit_cast<float>(bits);
+      int len = snprintf(buffer, sizeof(buffer), "%a", value);
+
+      uint32_t me;
+      ASSERT_EQ(Result::Ok,
+                ParseFloat(LiteralType::Hexfloat, buffer, buffer + len, &me));
+      ASSERT_EQ(me, bits);
+    }
+    LOG_DONE();
+  }
+};
+
+TEST_F(AllFloatsParseTest, Run) {
+  RunThreads();
+}
+
+class AllFloatsWriteTest : public ThreadedTest {
+ protected:
+  virtual void RunShard(int shard) {
+    char buffer[100];
+    FOREACH_UINT32(bits) {
+      LOG_COMPLETION(bits);
+      if (is_infinity_or_nan(bits))
+        continue;
+
+      WriteFloatHex(buffer, sizeof(buffer), bits);
+
+      char* endptr;
+      float them_float = strtof(buffer, &endptr);
+      uint32_t them_bits = bit_cast<uint32_t>(them_float);
+      ASSERT_EQ(bits, them_bits);
+    }
+    LOG_DONE();
+  }
+};
+
+TEST_F(AllFloatsWriteTest, Run) {
+  RunThreads();
+}
+
+class AllFloatsRoundtripTest : public ThreadedTest {
+ protected:
+  static LiteralType ClassifyFloat(uint32_t float_bits) {
+    if (is_infinity_or_nan(float_bits)) {
+      if (float_bits & 0x7fffff) {
+        return LiteralType::Nan;
+      } else {
+        return LiteralType::Infinity;
+      }
+    } else {
+      return LiteralType::Hexfloat;
+    }
+  }
+
+  virtual void RunShard(int shard) {
+    char buffer[100];
+    FOREACH_UINT32(bits) {
+      LOG_COMPLETION(bits);
+      WriteFloatHex(buffer, sizeof(buffer), bits);
+      int len = strlen(buffer);
+
+      uint32_t new_bits;
+      ASSERT_EQ(Result::Ok, ParseFloat(ClassifyFloat(bits), buffer,
+                                       buffer + len, &new_bits));
+      ASSERT_EQ(new_bits, bits);
+    }
+    LOG_DONE();
+  }
+};
+
+TEST_F(AllFloatsRoundtripTest, Run) {
+  RunThreads();
+}
+
+/* doubles */
+class ManyDoublesParseTest : public ThreadedTest {
+ protected:
+  virtual void RunShard(int shard) {
+    char buffer[100];
+    FOREACH_UINT32(halfbits) {
+      LOG_COMPLETION(halfbits);
+      uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
+      if (is_infinity_or_nan(bits))
+        continue;
+
+      double value = bit_cast<double>(bits);
+      int len = snprintf(buffer, sizeof(buffer), "%a", value);
+
+      uint64_t me;
+      ASSERT_EQ(Result::Ok,
+                ParseDouble(LiteralType::Hexfloat, buffer, buffer + len, &me));
+      ASSERT_EQ(me, bits);
+    }
+    LOG_DONE();
+  }
+};
+
+TEST_F(ManyDoublesParseTest, Run) {
+  RunThreads();
+}
+
+class ManyDoublesWriteTest : public ThreadedTest {
+ protected:
+  virtual void RunShard(int shard) {
+    char buffer[100];
+    FOREACH_UINT32(halfbits) {
+      LOG_COMPLETION(halfbits);
+      uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
+      if (is_infinity_or_nan(bits))
+        continue;
+
+      WriteDoubleHex(buffer, sizeof(buffer), bits);
+
+      char* endptr;
+      double them_double = strtod(buffer, &endptr);
+      uint64_t them_bits = bit_cast<uint64_t>(them_double);
+      ASSERT_EQ(bits, them_bits);
+    }
+    LOG_DONE();
+  }
+};
+
+TEST_F(ManyDoublesWriteTest, Run) {
+  RunThreads();
+}
+
+class ManyDoublesRoundtripTest : public ThreadedTest {
+ protected:
+  static LiteralType ClassifyDouble(uint64_t double_bits) {
+    if (is_infinity_or_nan(double_bits)) {
+      if (double_bits & 0xfffffffffffffULL) {
+        return LiteralType::Nan;
+      } else {
+        return LiteralType::Infinity;
+      }
+    } else {
+      return LiteralType::Hexfloat;
+    }
+  }
+
+  virtual void RunShard(int shard) {
+    char buffer[100];
+    FOREACH_UINT32(halfbits) {
+      LOG_COMPLETION(halfbits);
+      uint64_t bits = (static_cast<uint64_t>(halfbits) << 32) | halfbits;
+      WriteDoubleHex(buffer, sizeof(buffer), bits);
+      int len = strlen(buffer);
+
+      uint64_t new_bits;
+      ASSERT_EQ(Result::Ok, ParseDouble(ClassifyDouble(bits), buffer,
+                                        buffer + len, &new_bits));
+      ASSERT_EQ(new_bits, bits);
+    }
+    LOG_DONE();
+  }
+};
+
+TEST_F(ManyDoublesRoundtripTest, Run) {
+  RunThreads();
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-interp.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-interp.cc
new file mode 100644 (file)
index 0000000..d911aee
--- /dev/null
@@ -0,0 +1,693 @@
+/*
+ * 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 "gtest/gtest.h"
+
+#include "src/binary-reader.h"
+#include "src/error-formatter.h"
+
+#include "src/interp/binary-reader-interp.h"
+#include "src/interp/interp.h"
+
+using namespace wabt;
+using namespace wabt::interp;
+
+class InterpTest : public ::testing::Test {
+ public:
+  void ReadModule(const std::vector<u8>& data) {
+    Errors errors;
+    ReadBinaryOptions options;
+    Result result = ReadBinaryInterp(data.data(), data.size(), options, &errors,
+                                     &module_desc_);
+    ASSERT_EQ(Result::Ok, result)
+        << FormatErrorsToString(errors, Location::Type::Binary);
+  }
+
+  void Instantiate(const RefVec& imports = RefVec{}) {
+    mod_ = Module::New(store_, module_desc_);
+    RefPtr<Trap> trap;
+    inst_ = Instance::Instantiate(store_, mod_.ref(), imports, &trap);
+    ASSERT_TRUE(inst_) << trap->message();
+  }
+
+  DefinedFunc::Ptr GetFuncExport(interp::Index index) {
+    EXPECT_LT(index, inst_->exports().size());
+    return store_.UnsafeGet<DefinedFunc>(inst_->exports()[index]);
+  }
+
+  void ExpectBufferStrEq(OutputBuffer& buf, const char* str) {
+    std::string buf_str(buf.data.begin(), buf.data.end());
+    EXPECT_STREQ(buf_str.c_str(), str);
+  }
+
+  Store store_;
+  ModuleDesc module_desc_;
+  Module::Ptr mod_;
+  Instance::Ptr inst_;
+};
+
+
+TEST_F(InterpTest, Empty) {
+  ASSERT_TRUE(mod_.empty());
+  ReadModule({0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00});
+  Instantiate();
+  ASSERT_FALSE(mod_.empty());
+}
+
+TEST_F(InterpTest, MVP) {
+  // (module
+  //   (type (;0;) (func (param i32) (result i32)))
+  //   (type (;1;) (func (param f32) (result f32)))
+  //   (type (;2;) (func))
+  //   (import "foo" "bar" (func (;0;) (type 0)))
+  //   (func (;1;) (type 1) (param f32) (result f32)
+  //     (f32.const 0x1.5p+5 (;=42;)))
+  //   (func (;2;) (type 2))
+  //   (table (;0;) 1 2 funcref)
+  //   (memory (;0;) 1)
+  //   (global (;0;) i32 (i32.const 1))
+  //   (export "quux" (func 1))
+  //   (start 2)
+  //   (elem (;0;) (i32.const 0) 0 1)
+  //   (data (;0;) (i32.const 2) "hello"))
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0e, 0x03, 0x60,
+      0x01, 0x7f, 0x01, 0x7f, 0x60, 0x01, 0x7d, 0x01, 0x7d, 0x60, 0x00, 0x00,
+      0x02, 0x0b, 0x01, 0x03, 0x66, 0x6f, 0x6f, 0x03, 0x62, 0x61, 0x72, 0x00,
+      0x00, 0x03, 0x03, 0x02, 0x01, 0x02, 0x04, 0x05, 0x01, 0x70, 0x01, 0x01,
+      0x02, 0x05, 0x03, 0x01, 0x00, 0x01, 0x06, 0x06, 0x01, 0x7f, 0x00, 0x41,
+      0x01, 0x0b, 0x07, 0x08, 0x01, 0x04, 0x71, 0x75, 0x75, 0x78, 0x00, 0x01,
+      0x08, 0x01, 0x02, 0x09, 0x08, 0x01, 0x00, 0x41, 0x00, 0x0b, 0x02, 0x00,
+      0x01, 0x0a, 0x0c, 0x02, 0x07, 0x00, 0x43, 0x00, 0x00, 0x28, 0x42, 0x0b,
+      0x02, 0x00, 0x0b, 0x0b, 0x0b, 0x01, 0x00, 0x41, 0x02, 0x0b, 0x05, 0x68,
+      0x65, 0x6c, 0x6c, 0x6f,
+  });
+
+  EXPECT_EQ(3u, module_desc_.func_types.size());
+  EXPECT_EQ(1u, module_desc_.imports.size());
+  EXPECT_EQ(2u, module_desc_.funcs.size());
+  EXPECT_EQ(1u, module_desc_.tables.size());
+  EXPECT_EQ(1u, module_desc_.memories.size());
+  EXPECT_EQ(1u, module_desc_.globals.size());
+  EXPECT_EQ(0u, module_desc_.events.size());
+  EXPECT_EQ(1u, module_desc_.exports.size());
+  EXPECT_EQ(1u, module_desc_.starts.size());
+  EXPECT_EQ(1u, module_desc_.elems.size());
+  EXPECT_EQ(1u, module_desc_.datas.size());
+}
+
+namespace {
+
+// (func (export "fac") (param $n i32) (result i32)
+//   (local $result i32)
+//   (local.set $result (i32.const 1))
+//   (loop (result i32)
+//     (local.set $result
+//       (i32.mul
+//         (br_if 1 (local.get $result) (i32.eqz (local.get $n)))
+//         (local.get $n)))
+//     (local.set $n (i32.sub (local.get $n) (i32.const 1)))
+//     (br 0)))
+const std::vector<u8> s_fac_module = {
+    0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01,
+    0x60, 0x01, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07, 0x07,
+    0x01, 0x03, 0x66, 0x61, 0x63, 0x00, 0x00, 0x0a, 0x22, 0x01, 0x20,
+    0x01, 0x01, 0x7f, 0x41, 0x01, 0x21, 0x01, 0x03, 0x7f, 0x20, 0x01,
+    0x20, 0x00, 0x45, 0x0d, 0x01, 0x20, 0x00, 0x6c, 0x21, 0x01, 0x20,
+    0x00, 0x41, 0x01, 0x6b, 0x21, 0x00, 0x0c, 0x00, 0x0b, 0x0b,
+};
+
+}  // namespace
+
+TEST_F(InterpTest, Disassemble) {
+  ReadModule(s_fac_module);
+
+  MemoryStream stream;
+  module_desc_.istream.Disassemble(&stream);
+  auto buf = stream.ReleaseOutputBuffer();
+
+  ExpectBufferStrEq(*buf,
+R"(   0| alloca 1
+   8| i32.const 1
+  16| local.set $2, %[-1]
+  24| local.get $1
+  32| local.get $3
+  40| i32.eqz %[-1]
+  44| br_unless @60, %[-1]
+  52| br @116
+  60| local.get $3
+  68| i32.mul %[-2], %[-1]
+  72| local.set $2, %[-1]
+  80| local.get $2
+  88| i32.const 1
+  96| i32.sub %[-2], %[-1]
+ 100| local.set $3, %[-1]
+ 108| br @24
+ 116| drop_keep $2 $1
+ 128| return
+)");
+}
+
+TEST_F(InterpTest, Fac) {
+  ReadModule(s_fac_module);
+  Instantiate();
+  auto func = GetFuncExport(0);
+
+  Values results;
+  Trap::Ptr trap;
+  Result result = func->Call(store_, {Value::Make(5)}, results, &trap);
+
+  ASSERT_EQ(Result::Ok, result);
+  EXPECT_EQ(1u, results.size());
+  EXPECT_EQ(120u, results[0].Get<u32>());
+}
+
+TEST_F(InterpTest, Fac_Trace) {
+  ReadModule(s_fac_module);
+  Instantiate();
+  auto func = GetFuncExport(0);
+
+  Values results;
+  Trap::Ptr trap;
+  MemoryStream stream;
+  Result result = func->Call(store_, {Value::Make(2)}, results, &trap, &stream);
+  ASSERT_EQ(Result::Ok, result);
+
+  auto buf = stream.ReleaseOutputBuffer();
+  ExpectBufferStrEq(*buf,
+R"(#0.    0: V:1  | alloca 1
+#0.    8: V:2  | i32.const 1
+#0.   16: V:3  | local.set $2, 1
+#0.   24: V:2  | local.get $1
+#0.   32: V:3  | local.get $3
+#0.   40: V:4  | i32.eqz 2
+#0.   44: V:4  | br_unless @60, 0
+#0.   60: V:3  | local.get $3
+#0.   68: V:4  | i32.mul 1, 2
+#0.   72: V:3  | local.set $2, 2
+#0.   80: V:2  | local.get $2
+#0.   88: V:3  | i32.const 1
+#0.   96: V:4  | i32.sub 2, 1
+#0.  100: V:3  | local.set $3, 1
+#0.  108: V:2  | br @24
+#0.   24: V:2  | local.get $1
+#0.   32: V:3  | local.get $3
+#0.   40: V:4  | i32.eqz 1
+#0.   44: V:4  | br_unless @60, 0
+#0.   60: V:3  | local.get $3
+#0.   68: V:4  | i32.mul 2, 1
+#0.   72: V:3  | local.set $2, 2
+#0.   80: V:2  | local.get $2
+#0.   88: V:3  | i32.const 1
+#0.   96: V:4  | i32.sub 1, 1
+#0.  100: V:3  | local.set $3, 0
+#0.  108: V:2  | br @24
+#0.   24: V:2  | local.get $1
+#0.   32: V:3  | local.get $3
+#0.   40: V:4  | i32.eqz 0
+#0.   44: V:4  | br_unless @60, 1
+#0.   52: V:3  | br @116
+#0.  116: V:3  | drop_keep $2 $1
+#0.  128: V:1  | return
+)");
+}
+
+TEST_F(InterpTest, Local_Trace) {
+  // (func (export "a")
+  //   (local i32 i64 f32 f64)
+  //   (local.set 0 (i32.const 0))
+  //   (local.set 1 (i64.const 1))
+  //   (local.set 2 (f32.const 2))
+  //   (local.set 3 (f64.const 3)))
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
+      0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01,
+      0x61, 0x00, 0x00, 0x0a, 0x26, 0x01, 0x24, 0x04, 0x01, 0x7f, 0x01,
+      0x7e, 0x01, 0x7d, 0x01, 0x7c, 0x41, 0x00, 0x21, 0x00, 0x42, 0x01,
+      0x21, 0x01, 0x43, 0x00, 0x00, 0x00, 0x40, 0x21, 0x02, 0x44, 0x00,
+      0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x40, 0x21, 0x03, 0x0b,
+  });
+
+  Instantiate();
+  auto func = GetFuncExport(0);
+
+  Values results;
+  Trap::Ptr trap;
+  MemoryStream stream;
+  Result result = func->Call(store_, {}, results, &trap, &stream);
+  ASSERT_EQ(Result::Ok, result);
+
+  auto buf = stream.ReleaseOutputBuffer();
+  ExpectBufferStrEq(*buf,
+R"(#0.    0: V:0  | alloca 4
+#0.    8: V:4  | i32.const 0
+#0.   16: V:5  | local.set $5, 0
+#0.   24: V:4  | i64.const 1
+#0.   36: V:5  | local.set $4, 1
+#0.   44: V:4  | f32.const 2
+#0.   52: V:5  | local.set $3, 2
+#0.   60: V:4  | f64.const 3
+#0.   72: V:5  | local.set $2, 3
+#0.   80: V:4  | drop_keep $4 $0
+#0.   92: V:0  | return
+)");
+}
+
+TEST_F(InterpTest, HostFunc) {
+  // (import "" "f" (func $f (param i32) (result i32)))
+  // (func (export "g") (result i32)
+  //   (call $f (i32.const 1)))
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x0a,
+      0x02, 0x60, 0x01, 0x7f, 0x01, 0x7f, 0x60, 0x00, 0x01, 0x7f,
+      0x02, 0x06, 0x01, 0x00, 0x01, 0x66, 0x00, 0x00, 0x03, 0x02,
+      0x01, 0x01, 0x07, 0x05, 0x01, 0x01, 0x67, 0x00, 0x01, 0x0a,
+      0x08, 0x01, 0x06, 0x00, 0x41, 0x01, 0x10, 0x00, 0x0b,
+  });
+
+  auto host_func =
+      HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
+                    [](Thread& thread, const Values& params, Values& results,
+                       Trap::Ptr* out_trap) -> Result {
+                      results[0] = Value::Make(params[0].Get<u32>() + 1);
+                      return Result::Ok;
+                    });
+
+  Instantiate({host_func->self()});
+
+  Values results;
+  Trap::Ptr trap;
+  Result result = GetFuncExport(0)->Call(store_, {}, results, &trap);
+
+  ASSERT_EQ(Result::Ok, result);
+  EXPECT_EQ(1u, results.size());
+  EXPECT_EQ(2u, results[0].Get<u32>());
+}
+
+TEST_F(InterpTest, HostFunc_PingPong) {
+  // (import "" "f" (func $f (param i32) (result i32)))
+  // (func (export "g") (param i32) (result i32)
+  //   (call $f (i32.add (local.get 0) (i32.const 1))))
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+      0x01, 0x7f, 0x01, 0x7f, 0x02, 0x06, 0x01, 0x00, 0x01, 0x66, 0x00, 0x00,
+      0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, 0x67, 0x00, 0x01, 0x0a,
+      0x0b, 0x01, 0x09, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x10, 0x00, 0x0b,
+  });
+
+  auto host_func = HostFunc::New(
+      store_, FuncType{{ValueType::I32}, {ValueType::I32}},
+      [&](Thread& thread, const Values& params, Values& results,
+          Trap::Ptr* out_trap) -> Result {
+        auto val = params[0].Get<u32>();
+        if (val < 10) {
+          return GetFuncExport(0)->Call(store_, {Value::Make(val * 2)}, results,
+                                        out_trap);
+        }
+        results[0] = Value::Make(val);
+        return Result::Ok;
+      });
+
+  Instantiate({host_func->self()});
+
+  // Should produce the following calls:
+  //  g(1) -> f(2) -> g(4) -> f(5) -> g(10) -> f(11) -> return 11
+
+  Values results;
+  Trap::Ptr trap;
+  Result result = GetFuncExport(0)->Call(store_, {Value::Make(1)}, results, &trap);
+
+  ASSERT_EQ(Result::Ok, result);
+  EXPECT_EQ(1u, results.size());
+  EXPECT_EQ(11u, results[0].Get<u32>());
+}
+
+TEST_F(InterpTest, HostFunc_PingPong_SameThread) {
+  // (import "" "f" (func $f (param i32) (result i32)))
+  // (func (export "g") (param i32) (result i32)
+  //   (call $f (i32.add (local.get 0) (i32.const 1))))
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x06, 0x01, 0x60,
+      0x01, 0x7f, 0x01, 0x7f, 0x02, 0x06, 0x01, 0x00, 0x01, 0x66, 0x00, 0x00,
+      0x03, 0x02, 0x01, 0x00, 0x07, 0x05, 0x01, 0x01, 0x67, 0x00, 0x01, 0x0a,
+      0x0b, 0x01, 0x09, 0x00, 0x20, 0x00, 0x41, 0x01, 0x6a, 0x10, 0x00, 0x0b,
+  });
+
+  auto thread = Thread::New(store_, {});
+
+  auto host_func =
+      HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
+                    [&](Thread& t, const Values& params, Values& results,
+                        Trap::Ptr* out_trap) -> Result {
+                      auto val = params[0].Get<u32>();
+                      if (val < 10) {
+                        return GetFuncExport(0)->Call(t, {Value::Make(val * 2)},
+                                                      results, out_trap);
+                      }
+                      results[0] = Value::Make(val);
+                      return Result::Ok;
+                    });
+
+  Instantiate({host_func->self()});
+
+  // Should produce the following calls:
+  //  g(1) -> f(2) -> g(4) -> f(5) -> g(10) -> f(11) -> return 11
+
+  Values results;
+  Trap::Ptr trap;
+  Result result = GetFuncExport(0)->Call(*thread, {Value::Make(1)}, results, &trap);
+
+  ASSERT_EQ(Result::Ok, result);
+  EXPECT_EQ(1u, results.size());
+  EXPECT_EQ(11u, results[0].Get<u32>());
+}
+
+TEST_F(InterpTest, HostTrap) {
+  // (import "host" "a" (func $0))
+  // (func $1 call $0)
+  // (start $1)
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
+      0x60, 0x00, 0x00, 0x02, 0x0a, 0x01, 0x04, 0x68, 0x6f, 0x73, 0x74,
+      0x01, 0x61, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x08, 0x01, 0x01,
+      0x0a, 0x06, 0x01, 0x04, 0x00, 0x10, 0x00, 0x0b,
+  });
+
+  auto host_func =
+      HostFunc::New(store_, FuncType{{}, {}},
+                    [&](Thread& thread, const Values& params, Values& results,
+                        Trap::Ptr* out_trap) -> Result {
+                      *out_trap = Trap::New(store_, "boom");
+                      return Result::Error;
+                    });
+
+  mod_ = Module::New(store_, module_desc_);
+  RefPtr<Trap> trap;
+  Instance::Instantiate(store_, mod_.ref(), {host_func->self()}, &trap);
+
+  ASSERT_TRUE(trap);
+  ASSERT_EQ("boom", trap->message());
+}
+
+TEST_F(InterpTest, Rot13) {
+  // (import "host" "mem" (memory $mem 1))
+  // (import "host" "fill_buf" (func $fill_buf (param i32 i32) (result i32)))
+  // (import "host" "buf_done" (func $buf_done (param i32 i32)))
+  //
+  // (func $rot13c (param $c i32) (result i32)
+  //   (local $uc i32)
+  //
+  //   ;; No change if < 'A'.
+  //   (if (i32.lt_u (get_local $c) (i32.const 65))
+  //     (return (get_local $c)))
+  //
+  //   ;; Clear 5th bit of c, to force uppercase. 0xdf = 0b11011111
+  //   (set_local $uc (i32.and (get_local $c) (i32.const 0xdf)))
+  //
+  //   ;; In range ['A', 'M'] return |c| + 13.
+  //   (if (i32.le_u (get_local $uc) (i32.const 77))
+  //     (return (i32.add (get_local $c) (i32.const 13))))
+  //
+  //   ;; In range ['N', 'Z'] return |c| - 13.
+  //   (if (i32.le_u (get_local $uc) (i32.const 90))
+  //     (return (i32.sub (get_local $c) (i32.const 13))))
+  //
+  //   ;; No change for everything else.
+  //   (return (get_local $c))
+  // )
+  //
+  // (func (export "rot13")
+  //   (local $size i32)
+  //   (local $i i32)
+  //
+  //   ;; Ask host to fill memory [0, 1024) with data.
+  //   (call $fill_buf (i32.const 0) (i32.const 1024))
+  //
+  //   ;; The host returns the size filled.
+  //   (set_local $size)
+  //
+  //   ;; Loop over all bytes and rot13 them.
+  //   (block $exit
+  //     (loop $top
+  //       ;; if (i >= size) break
+  //       (if (i32.ge_u (get_local $i) (get_local $size)) (br $exit))
+  //
+  //       ;; mem[i] = rot13c(mem[i])
+  //       (i32.store8
+  //         (get_local $i)
+  //         (call $rot13c
+  //           (i32.load8_u (get_local $i))))
+  //
+  //       ;; i++
+  //       (set_local $i (i32.add (get_local $i) (i32.const 1)))
+  //       (br $top)
+  //     )
+  //   )
+  //
+  //   (call $buf_done (i32.const 0) (get_local $size))
+  // )
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x14, 0x04, 0x60,
+      0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x60, 0x02, 0x7f, 0x7f, 0x00, 0x60, 0x01,
+      0x7f, 0x01, 0x7f, 0x60, 0x00, 0x00, 0x02, 0x2d, 0x03, 0x04, 0x68, 0x6f,
+      0x73, 0x74, 0x03, 0x6d, 0x65, 0x6d, 0x02, 0x00, 0x01, 0x04, 0x68, 0x6f,
+      0x73, 0x74, 0x08, 0x66, 0x69, 0x6c, 0x6c, 0x5f, 0x62, 0x75, 0x66, 0x00,
+      0x00, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x08, 0x62, 0x75, 0x66, 0x5f, 0x64,
+      0x6f, 0x6e, 0x65, 0x00, 0x01, 0x03, 0x03, 0x02, 0x02, 0x03, 0x07, 0x09,
+      0x01, 0x05, 0x72, 0x6f, 0x74, 0x31, 0x33, 0x00, 0x03, 0x0a, 0x74, 0x02,
+      0x39, 0x01, 0x01, 0x7f, 0x20, 0x00, 0x41, 0xc1, 0x00, 0x49, 0x04, 0x40,
+      0x20, 0x00, 0x0f, 0x0b, 0x20, 0x00, 0x41, 0xdf, 0x01, 0x71, 0x21, 0x01,
+      0x20, 0x01, 0x41, 0xcd, 0x00, 0x4d, 0x04, 0x40, 0x20, 0x00, 0x41, 0x0d,
+      0x6a, 0x0f, 0x0b, 0x20, 0x01, 0x41, 0xda, 0x00, 0x4d, 0x04, 0x40, 0x20,
+      0x00, 0x41, 0x0d, 0x6b, 0x0f, 0x0b, 0x20, 0x00, 0x0f, 0x0b, 0x38, 0x01,
+      0x02, 0x7f, 0x41, 0x00, 0x41, 0x80, 0x08, 0x10, 0x00, 0x21, 0x00, 0x02,
+      0x40, 0x03, 0x40, 0x20, 0x01, 0x20, 0x00, 0x4f, 0x04, 0x40, 0x0c, 0x02,
+      0x0b, 0x20, 0x01, 0x20, 0x01, 0x2d, 0x00, 0x00, 0x10, 0x02, 0x3a, 0x00,
+      0x00, 0x20, 0x01, 0x41, 0x01, 0x6a, 0x21, 0x01, 0x0c, 0x00, 0x0b, 0x0b,
+      0x41, 0x00, 0x20, 0x00, 0x10, 0x01, 0x0b,
+  });
+
+  auto host_func =
+      HostFunc::New(store_, FuncType{{ValueType::I32}, {ValueType::I32}},
+                    [](Thread& thread, const Values& params, Values& results,
+                       Trap::Ptr* out_trap) -> Result {
+                      results[0] = Value::Make(params[0].Get<u32>() + 1);
+                      return Result::Ok;
+                    });
+
+  std::string string_data = "Hello, WebAssembly!";
+
+  auto memory = Memory::New(store_, MemoryType{Limits{1}});
+
+  auto fill_buf = [&](Thread& thread, const Values& params, Values& results,
+                      Trap::Ptr* out_trap) -> Result {
+    // (param $ptr i32) (param $max_size i32) (result $size i32)
+    EXPECT_EQ(2u, params.size());
+    EXPECT_EQ(1u, results.size());
+
+    u32 ptr = params[0].Get<u32>();
+    u32 max_size = params[1].Get<u32>();
+    u32 size = std::min(max_size, u32(string_data.size()));
+
+    EXPECT_LT(ptr + size, memory->ByteSize());
+
+    std::copy(string_data.begin(), string_data.begin() + size,
+              memory->UnsafeData() + ptr);
+
+    results[0].Set(size);
+    return Result::Ok;
+  };
+  auto fill_buf_func = HostFunc::New(
+      store_, FuncType{{ValueType::I32, ValueType::I32}, {ValueType::I32}},
+      fill_buf);
+
+  auto buf_done = [&](Thread& thread, const Values& params, Values& results,
+                      Trap::Ptr* out_trap) -> Result {
+    // (param $ptr i32) (param $size i32)
+    EXPECT_EQ(2u, params.size());
+    EXPECT_EQ(0u, results.size());
+
+    u32 ptr = params[0].Get<u32>();
+    u32 size = params[1].Get<u32>();
+
+    EXPECT_LT(ptr + size, memory->ByteSize());
+
+    string_data.resize(size);
+    std::copy(memory->UnsafeData() + ptr, memory->UnsafeData() + ptr + size,
+              string_data.begin());
+
+    return Result::Ok;
+  };
+  auto buf_done_func = HostFunc::New(
+      store_, FuncType{{ValueType::I32, ValueType::I32}, {}}, buf_done);
+
+  Instantiate({memory->self(), fill_buf_func->self(), buf_done_func->self()});
+
+  auto rot13 = GetFuncExport(0);
+
+  Values results;
+  Trap::Ptr trap;
+  ASSERT_EQ(Result::Ok, rot13->Call(store_, {}, results, &trap));
+
+  ASSERT_EQ("Uryyb, JroNffrzoyl!", string_data);
+
+  ASSERT_EQ(Result::Ok, rot13->Call(store_, {}, results, &trap));
+
+  ASSERT_EQ("Hello, WebAssembly!", string_data);
+}
+
+class InterpGCTest : public InterpTest {
+ public:
+  void SetUp() override {
+    before_new = store_.object_count();
+  }
+
+  void TearDown() override {
+    // Reset instance and module, in case they were allocated.
+    inst_.reset();
+    mod_.reset();
+
+    store_.Collect();
+    EXPECT_EQ(before_new, store_.object_count());
+  }
+
+  size_t before_new;
+};
+
+TEST_F(InterpGCTest, Collect_Basic) {
+  auto foreign = Foreign::New(store_, nullptr);
+  auto after_new = store_.object_count();
+  EXPECT_EQ(before_new + 1, after_new);
+
+  // Remove root, but object is not destroyed until collect.
+  foreign.reset();
+  EXPECT_EQ(after_new, store_.object_count());
+}
+
+TEST_F(InterpGCTest, Collect_GlobalCycle) {
+  auto gt = GlobalType{ValueType::ExternRef, Mutability::Var};
+  auto g1 = Global::New(store_, gt, Value::Make(Ref::Null));
+  auto g2 = Global::New(store_, gt, Value::Make(g1->self()));
+  g1->Set(store_, g2->self());
+
+  auto after_new = store_.object_count();
+  EXPECT_EQ(before_new + 2, after_new);
+
+  // Remove g1 root, but it's kept alive by g2.
+  g1.reset();
+  store_.Collect();
+  EXPECT_EQ(after_new, store_.object_count());
+
+  // Remove g2 root, now both should be removed.
+  g2.reset();
+}
+
+TEST_F(InterpGCTest, Collect_TableCycle) {
+  auto tt = TableType{ValueType::ExternRef, Limits{2}};
+  auto t1 = Table::New(store_, tt);
+  auto t2 = Table::New(store_, tt);
+  auto t3 = Table::New(store_, tt);
+
+  t1->Set(store_, 0, t1->self());  // t1 references itself.
+  t2->Set(store_, 0, t3->self());
+  t3->Set(store_, 0, t2->self());  // t2 and t3 reference each other.
+  t3->Set(store_, 1, t1->self());  // t3 also references t1.
+
+  auto after_new = store_.object_count();
+  EXPECT_EQ(before_new + 3, after_new);
+
+  // Remove t1 and t2 roots, but their kept alive by t3.
+  t1.reset();
+  t2.reset();
+  store_.Collect();
+  EXPECT_EQ(after_new, store_.object_count());
+
+  // Remove t3 root, now all should be removed.
+  t3.reset();
+}
+
+TEST_F(InterpGCTest, Collect_Func) {
+  ReadModule(s_fac_module);
+  Instantiate();
+  auto func = GetFuncExport(0);
+
+  auto after_new = store_.object_count();
+  EXPECT_EQ(before_new + 3, after_new);  // module, instance, func.
+
+  // Reset module and instance roots, but they'll be kept alive by the func.
+  mod_.reset();
+  inst_.reset();
+  store_.Collect();
+  EXPECT_EQ(after_new, store_.object_count());
+}
+
+TEST_F(InterpGCTest, Collect_InstanceImport) {
+  // (import "" "f" (func))
+  // (import "" "t" (table 0 funcref))
+  // (import "" "m" (memory 0))
+  // (import "" "g" (global i32))
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
+      0x60, 0x00, 0x00, 0x02, 0x19, 0x04, 0x00, 0x01, 0x66, 0x00, 0x00,
+      0x00, 0x01, 0x74, 0x01, 0x70, 0x00, 0x00, 0x00, 0x01, 0x6d, 0x02,
+      0x00, 0x00, 0x00, 0x01, 0x67, 0x03, 0x7f, 0x00,
+  });
+  auto f = HostFunc::New(store_, FuncType{{}, {}},
+                         [](Thread& thread, const Values&, Values&,
+                            Trap::Ptr*) -> Result { return Result::Ok; });
+  auto t = Table::New(store_, TableType{ValueType::FuncRef, Limits{0}});
+  auto m = Memory::New(store_, MemoryType{Limits{0}});
+  auto g = Global::New(store_, GlobalType{ValueType::I32, Mutability::Const},
+                       Value::Make(5));
+
+  Instantiate({f->self(), t->self(), m->self(), g->self()});
+  auto after_new = store_.object_count();
+  EXPECT_EQ(before_new + 6, after_new);  // module, instance, f, t, m, g
+
+  // Instance keeps all imports alive.
+  f.reset();
+  t.reset();
+  m.reset();
+  g.reset();
+  store_.Collect();
+  EXPECT_EQ(after_new, store_.object_count());
+}
+
+TEST_F(InterpGCTest, Collect_InstanceExport) {
+  // (func (export "f"))
+  // (global (export "g") i32 (i32.const 0))
+  // (table (export "t") 0 funcref)
+  // (memory (export "m") 0)
+  ReadModule({
+      0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01,
+      0x60, 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x04, 0x04, 0x01, 0x70,
+      0x00, 0x00, 0x05, 0x03, 0x01, 0x00, 0x00, 0x06, 0x06, 0x01, 0x7f,
+      0x00, 0x41, 0x00, 0x0b, 0x07, 0x11, 0x04, 0x01, 0x66, 0x00, 0x00,
+      0x01, 0x67, 0x03, 0x00, 0x01, 0x74, 0x01, 0x00, 0x01, 0x6d, 0x02,
+      0x00, 0x0a, 0x04, 0x01, 0x02, 0x00, 0x0b,
+  });
+  Instantiate();
+  auto after_new = store_.object_count();
+  EXPECT_EQ(before_new + 6, after_new);  // module, instance, f, t, m, g
+
+  // Instance keeps all exports alive.
+  store_.Collect();
+  EXPECT_EQ(after_new, store_.object_count());
+}
+
+// TODO: Test for Thread keeping references alive as locals/params/stack values.
+// This requires better tracking of references than currently exists in the
+// interpreter. (see TODOs in Select/LocalGet/GlobalGet)
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-intrusive-list.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-intrusive-list.cc
new file mode 100644 (file)
index 0000000..dfc3dbb
--- /dev/null
@@ -0,0 +1,584 @@
+/*
+ * 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 "gtest/gtest.h"
+
+#include <memory>
+
+#include "src/intrusive-list.h"
+#include "src/make-unique.h"
+
+using namespace wabt;
+
+namespace {
+
+struct TestObject : intrusive_list_base<TestObject> {
+  static int creation_count;
+
+  TestObject(int data = 0, int data2 = 0) : data(data), data2(data2) {
+    ++creation_count;
+  }
+
+  // Allow move.
+  TestObject(TestObject&& other) {
+    // Don't increment creation_count; we're moving from other.
+    *this = std::move(other);
+  }
+
+  TestObject& operator=(TestObject&& other) {
+    data = other.data;
+    data2 = other.data2;
+    other.moved = true;
+    return *this;
+  }
+
+  // Disallow copy.
+  TestObject(const TestObject&) = delete;
+  TestObject& operator=(const TestObject&) = delete;
+
+  ~TestObject() {
+    if (!moved) {
+      creation_count--;
+    }
+  }
+
+  int data;
+  int data2;
+  bool moved = false;
+};
+
+// static
+int TestObject::creation_count = 0;
+
+typedef intrusive_list<TestObject> TestObjectList;
+
+class IntrusiveListTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    // Reset to 0 even if the previous test leaked objects to keep the tests
+    // independent.
+    TestObject::creation_count = 0;
+  }
+
+  virtual void TearDown() { ASSERT_EQ(0, TestObject::creation_count); }
+
+  TestObjectList NewList(const std::vector<int>& data_values) {
+    TestObjectList result;
+    for (auto data_value : data_values)
+      result.emplace_back(data_value);
+    return result;
+  }
+
+  void AssertListEq(const TestObjectList& list,
+                    const std::vector<int>& expected) {
+    size_t count = 0;
+    for (const TestObject& node : list) {
+      ASSERT_EQ(expected[count++], node.data);
+    }
+    ASSERT_EQ(count, expected.size());
+  }
+
+  void AssertListEq(const TestObjectList& list,
+                    const std::vector<int>& expected,
+                    const std::vector<int>& expected2) {
+    assert(expected.size() == expected2.size());
+    size_t count = 0;
+    for (const TestObject& node : list) {
+      ASSERT_EQ(expected[count], node.data);
+      ASSERT_EQ(expected2[count], node.data2);
+      count++;
+    }
+    ASSERT_EQ(count, expected.size());
+  }
+};
+
+}  // end anonymous namespace
+
+TEST_F(IntrusiveListTest, default_constructor) {
+  TestObjectList list;
+}
+
+TEST_F(IntrusiveListTest, node_constructor) {
+  TestObjectList list(MakeUnique<TestObject>(1));
+  AssertListEq(list, {1});
+}
+
+TEST_F(IntrusiveListTest, node_move_constructor) {
+  TestObjectList list(TestObject(1));
+  AssertListEq(list, {1});
+}
+
+TEST_F(IntrusiveListTest, move_constructor) {
+  TestObjectList list1 = NewList({1, 2, 3});
+  TestObjectList list2(std::move(list1));
+  AssertListEq(list1, {});
+  AssertListEq(list2, {1, 2, 3});
+}
+
+TEST_F(IntrusiveListTest, move_assignment_operator) {
+  TestObjectList list1 = NewList({1, 2, 3});
+  TestObjectList list2;
+
+  list2 = std::move(list1);
+  AssertListEq(list1, {});
+  AssertListEq(list2, {1, 2, 3});
+}
+
+namespace {
+
+class IntrusiveListIteratorTest : public IntrusiveListTest {
+ protected:
+  virtual void SetUp() {
+    IntrusiveListTest::SetUp();
+
+    list_.emplace_back(1);
+    list_.emplace_back(2);
+    list_.emplace_back(3);
+  }
+
+  virtual void TearDown() {
+    list_.clear();
+
+    IntrusiveListTest::TearDown();
+  }
+
+  template <typename Iter>
+  void TestForward(Iter first, Iter last, const std::vector<int>& expected) {
+    size_t count = 0;
+    while (first != last) {
+      ASSERT_EQ(expected[count], first->data);
+      ++first;
+      ++count;
+    }
+    ASSERT_EQ(count, expected.size());
+  }
+
+  template <typename Iter>
+  void TestBackward(Iter first, Iter last, const std::vector<int>& expected) {
+    size_t count = 0;
+    while (first != last) {
+      --last;
+      ASSERT_EQ(expected[count], last->data);
+      ++count;
+    }
+    ASSERT_EQ(count, expected.size());
+  }
+
+  TestObjectList list_;
+  const TestObjectList& clist_ = list_;
+};
+
+}  // end of anonymous namespace
+
+TEST_F(IntrusiveListIteratorTest, begin_end_forward) {
+  TestForward(list_.begin(), list_.end(), {1, 2, 3});
+  TestForward(clist_.begin(), clist_.end(), {1, 2, 3});
+}
+
+TEST_F(IntrusiveListIteratorTest, rbegin_rend_forward) {
+  TestForward(list_.rbegin(), list_.rend(), {3, 2, 1});
+  TestForward(clist_.rbegin(), clist_.rend(), {3, 2, 1});
+}
+
+TEST_F(IntrusiveListIteratorTest, cbegin_cend_forward) {
+  TestForward(list_.cbegin(), list_.cend(), {1, 2, 3});
+  TestForward(clist_.cbegin(), clist_.cend(), {1, 2, 3});
+}
+
+TEST_F(IntrusiveListIteratorTest, crbegin_crend_forward) {
+  TestForward(list_.crbegin(), list_.crend(), {3, 2, 1});
+  TestForward(clist_.crbegin(), clist_.crend(), {3, 2, 1});
+}
+
+TEST_F(IntrusiveListIteratorTest, begin_end_backward) {
+  TestBackward(list_.begin(), list_.end(), {3, 2, 1});
+  TestBackward(clist_.begin(), clist_.end(), {3, 2, 1});
+}
+
+TEST_F(IntrusiveListIteratorTest, rbegin_rend_backward) {
+  TestBackward(list_.rbegin(), list_.rend(), {1, 2, 3});
+  TestBackward(clist_.rbegin(), clist_.rend(), {1, 2, 3});
+}
+
+TEST_F(IntrusiveListIteratorTest, cbegin_cend_backward) {
+  TestBackward(list_.cbegin(), list_.cend(), {3, 2, 1});
+  TestBackward(clist_.cbegin(), clist_.cend(), {3, 2, 1});
+}
+
+TEST_F(IntrusiveListIteratorTest, crbegin_crend_backward) {
+  TestBackward(list_.crbegin(), list_.crend(), {1, 2, 3});
+  TestBackward(clist_.crbegin(), clist_.crend(), {1, 2, 3});
+}
+
+TEST_F(IntrusiveListTest, size_empty) {
+  TestObjectList list;
+  ASSERT_EQ(0U, list.size());
+  ASSERT_TRUE(list.empty());
+
+  list.emplace_back(1);
+  ASSERT_EQ(1U, list.size());
+  ASSERT_FALSE(list.empty());
+}
+
+TEST_F(IntrusiveListTest, front_back) {
+  TestObjectList list;
+
+  list.emplace_back(1);
+  ASSERT_EQ(1, list.front().data);
+  ASSERT_EQ(1, list.back().data);
+
+  list.emplace_back(2);
+  ASSERT_EQ(1, list.front().data);
+  ASSERT_EQ(2, list.back().data);
+
+  const TestObjectList& clist = list;
+  ASSERT_EQ(1, clist.front().data);
+  ASSERT_EQ(2, clist.back().data);
+}
+
+TEST_F(IntrusiveListTest, emplace_front) {
+  TestObjectList list;
+
+  // Pass an additional arg to show that forwarding works properly.
+  list.emplace_front(1, 100);
+  list.emplace_front(2, 200);
+  list.emplace_front(3, 300);
+  list.emplace_front(4, 400);
+
+  AssertListEq(list, {4, 3, 2, 1}, {400, 300, 200, 100});
+}
+
+TEST_F(IntrusiveListTest, emplace_back) {
+  TestObjectList list;
+
+  // Pass an additional arg to show that forwarding works properly.
+  list.emplace_back(1, 100);
+  list.emplace_back(2, 200);
+  list.emplace_back(3, 300);
+  list.emplace_back(4, 400);
+
+  AssertListEq(list, {1, 2, 3, 4}, {100, 200, 300, 400});
+}
+
+TEST_F(IntrusiveListTest, push_front_pointer) {
+  TestObjectList list;
+
+  list.push_front(MakeUnique<TestObject>(1));
+  list.push_front(MakeUnique<TestObject>(2));
+  list.push_front(MakeUnique<TestObject>(3));
+
+  AssertListEq(list, {3, 2, 1});
+}
+
+TEST_F(IntrusiveListTest, push_back_pointer) {
+  TestObjectList list;
+
+  list.push_back(MakeUnique<TestObject>(1));
+  list.push_back(MakeUnique<TestObject>(2));
+  list.push_back(MakeUnique<TestObject>(3));
+
+  AssertListEq(list, {1, 2, 3});
+}
+
+TEST_F(IntrusiveListTest, push_front_move) {
+  TestObjectList list;
+
+  list.push_front(TestObject(1));
+  list.push_front(TestObject(2));
+  list.push_front(TestObject(3));
+
+  AssertListEq(list, {3, 2, 1});
+}
+
+TEST_F(IntrusiveListTest, push_back_move) {
+  TestObjectList list;
+
+  list.push_back(TestObject(1));
+  list.push_back(TestObject(2));
+  list.push_back(TestObject(3));
+
+  AssertListEq(list, {1, 2, 3});
+}
+
+TEST_F(IntrusiveListTest, pop_front) {
+  TestObjectList list = NewList({1, 2, 3, 4});
+
+  list.pop_front();
+  AssertListEq(list, {2, 3, 4});
+  list.pop_front();
+  AssertListEq(list, {3, 4});
+  list.pop_front();
+  AssertListEq(list, {4});
+  list.pop_front();
+  AssertListEq(list, {});
+}
+
+TEST_F(IntrusiveListTest, pop_back) {
+  TestObjectList list = NewList({1, 2, 3, 4});
+
+  list.pop_back();
+  AssertListEq(list, {1, 2, 3});
+  list.pop_back();
+  AssertListEq(list, {1, 2});
+  list.pop_back();
+  AssertListEq(list, {1});
+  list.pop_back();
+  AssertListEq(list, {});
+}
+
+TEST_F(IntrusiveListTest, extract_front) {
+  TestObjectList list = NewList({1, 2, 3});
+
+  std::unique_ptr<TestObject> t1(list.extract_front());
+  ASSERT_EQ(1, t1->data);
+  AssertListEq(list, {2, 3});
+
+  std::unique_ptr<TestObject> t2(list.extract_front());
+  ASSERT_EQ(2, t2->data);
+  AssertListEq(list, {3});
+
+  std::unique_ptr<TestObject> t3(list.extract_front());
+  ASSERT_EQ(3, t3->data);
+  AssertListEq(list, {});
+}
+
+TEST_F(IntrusiveListTest, extract_back) {
+  TestObjectList list = NewList({1, 2, 3});
+
+  std::unique_ptr<TestObject> t1(list.extract_back());
+  ASSERT_EQ(3, t1->data);
+  AssertListEq(list, {1, 2});
+
+  std::unique_ptr<TestObject> t2(list.extract_back());
+  ASSERT_EQ(2, t2->data);
+  AssertListEq(list, {1});
+
+  std::unique_ptr<TestObject> t3(list.extract_back());
+  ASSERT_EQ(1, t3->data);
+  AssertListEq(list, {});
+}
+
+TEST_F(IntrusiveListTest, emplace) {
+  TestObjectList list;
+
+  // Pass an additional arg to show that forwarding works properly.
+  list.emplace(list.begin(), 2, 200);
+  list.emplace(list.end(), 4, 400);
+  list.emplace(std::next(list.begin()), 3, 300);
+  list.emplace(list.begin(), 1, 100);
+
+  AssertListEq(list, {1, 2, 3, 4}, {100, 200, 300, 400});
+}
+
+TEST_F(IntrusiveListTest, insert_pointer) {
+  TestObjectList list;
+
+  list.insert(list.begin(), MakeUnique<TestObject>(2));
+  list.insert(list.end(), MakeUnique<TestObject>(4));
+  list.insert(std::next(list.begin()), MakeUnique<TestObject>(3));
+  list.insert(list.begin(), MakeUnique<TestObject>(1));
+
+  AssertListEq(list, {1, 2, 3, 4});
+}
+
+TEST_F(IntrusiveListTest, insert_move) {
+  TestObjectList list;
+
+  list.insert(list.begin(), TestObject(2));
+  list.insert(list.end(), TestObject(4));
+  list.insert(std::next(list.begin()), TestObject(3));
+  list.insert(list.begin(), TestObject(1));
+
+  AssertListEq(list, {1, 2, 3, 4});
+}
+
+TEST_F(IntrusiveListTest, extract) {
+  TestObjectList list = NewList({1, 2, 3, 4});
+
+  TestObjectList::iterator t1_iter = std::next(list.begin(), 0);
+  TestObjectList::iterator t2_iter = std::next(list.begin(), 1);
+  TestObjectList::iterator t3_iter = std::next(list.begin(), 2);
+  TestObjectList::iterator t4_iter = std::next(list.begin(), 3);
+
+  std::unique_ptr<TestObject> t2(list.extract(t2_iter));
+  ASSERT_EQ(2, t2->data);
+  AssertListEq(list, {1, 3, 4});
+
+  std::unique_ptr<TestObject> t4(list.extract(t4_iter));
+  ASSERT_EQ(4, t4->data);
+  AssertListEq(list, {1, 3});
+
+  std::unique_ptr<TestObject> t1(list.extract(t1_iter));
+  ASSERT_EQ(1, t1->data);
+  AssertListEq(list, {3});
+
+  std::unique_ptr<TestObject> t3(list.extract(t3_iter));
+  ASSERT_EQ(3, t3->data);
+  AssertListEq(list, {});
+}
+
+TEST_F(IntrusiveListTest, erase) {
+  TestObjectList list = NewList({1, 2, 3, 4});
+
+  TestObjectList::iterator t1_iter = std::next(list.begin(), 0);
+  TestObjectList::iterator t2_iter = std::next(list.begin(), 1);
+  TestObjectList::iterator t3_iter = std::next(list.begin(), 2);
+  TestObjectList::iterator t4_iter = std::next(list.begin(), 3);
+
+  // erase returns an iterator to the following node.
+  ASSERT_EQ(3, list.erase(t2_iter)->data);
+  AssertListEq(list, {1, 3, 4});
+
+  ASSERT_EQ(list.end(), list.erase(t4_iter));
+  AssertListEq(list, {1, 3});
+
+  ASSERT_EQ(3, list.erase(t1_iter)->data);
+  AssertListEq(list, {3});
+
+  ASSERT_EQ(list.end(), list.erase(t3_iter));
+  AssertListEq(list, {});
+}
+
+TEST_F(IntrusiveListTest, erase_range) {
+  TestObjectList list = NewList({1, 2, 3, 4, 5, 6});
+
+  // OK to erase an empty range.
+  list.erase(list.begin(), list.begin());
+  list.erase(list.end(), list.end());
+
+  // Erase the first element (1).
+  list.erase(list.begin(), std::next(list.begin()));
+  AssertListEq(list, {2, 3, 4, 5, 6});
+
+  // Erase the last element (6).
+  list.erase(std::prev(list.end()), list.end());
+  AssertListEq(list, {2, 3, 4, 5});
+
+  // Erase [3, 4] => [2, 5]
+  list.erase(std::next(list.begin()), std::prev(list.end()));
+  AssertListEq(list, {2, 5});
+
+  // Erase the rest.
+  list.erase(list.begin(), list.end());
+  AssertListEq(list, {});
+}
+
+TEST_F(IntrusiveListTest, swap) {
+  TestObjectList list1 = NewList({1, 2, 3, 4});
+
+  TestObjectList list2 = NewList({100, 200, 300});
+
+  AssertListEq(list1, {1, 2, 3, 4});
+  AssertListEq(list2, {100, 200, 300});
+
+  list1.swap(list2);
+
+  AssertListEq(list1, {100, 200, 300});
+  AssertListEq(list2, {1, 2, 3, 4});
+}
+
+TEST_F(IntrusiveListTest, clear) {
+  TestObjectList list = NewList({1, 2, 3, 4});
+
+  ASSERT_FALSE(list.empty());
+
+  list.clear();
+
+  ASSERT_EQ(0U, list.size());
+  ASSERT_TRUE(list.empty());
+}
+
+TEST_F(IntrusiveListTest, splice_list) {
+  TestObjectList list1 = NewList({1, 2, 3});
+
+  // Splice at beginning.
+  TestObjectList list2 = NewList({100, 200});
+  list1.splice(list1.begin(), list2);
+  AssertListEq(list1, {100, 200, 1, 2, 3});
+  AssertListEq(list2, {});
+
+  // Splice at end.
+  TestObjectList list3 = NewList({500, 600, 700});
+  list1.splice(list1.end(), list3);
+  AssertListEq(list1, {100, 200, 1, 2, 3, 500, 600, 700});
+  AssertListEq(list3, {});
+
+  // Splice in the middle.
+  TestObjectList list4 = NewList({400});
+  list1.splice(std::next(list1.begin(), 4), list4);
+  AssertListEq(list1, {100, 200, 1, 2, 400, 3, 500, 600, 700});
+  AssertListEq(list4, {});
+}
+
+TEST_F(IntrusiveListTest, splice_list_move) {
+  TestObjectList list1 = NewList({1, 2, 3});
+
+  // Splice at beginning.
+  list1.splice(list1.begin(), NewList({100, 200}));
+  AssertListEq(list1, {100, 200, 1, 2, 3});
+
+  // Splice at end.
+  list1.splice(list1.end(), NewList({500, 600, 700}));
+  AssertListEq(list1, {100, 200, 1, 2, 3, 500, 600, 700});
+
+  // Splice in the middle.
+  list1.splice(std::next(list1.begin(), 4), NewList({400}));
+  AssertListEq(list1, {100, 200, 1, 2, 400, 3, 500, 600, 700});
+}
+
+TEST_F(IntrusiveListTest, splice_node) {
+  TestObjectList list1 = NewList({1, 2, 3});
+
+  // Splice at beginning.
+  TestObjectList list2 = NewList({100, 200});
+  list1.splice(list1.begin(), list2, list2.begin());
+  AssertListEq(list1, {100, 1, 2, 3});
+  AssertListEq(list2, {200});
+
+  // Splice at end.
+  TestObjectList list3 = NewList({500, 600, 700});
+  list1.splice(list1.end(), list3, std::next(list3.begin(), 2));
+  AssertListEq(list1, {100, 1, 2, 3, 700});
+  AssertListEq(list3, {500, 600});
+
+  // Splice in the middle.
+  TestObjectList list4 = NewList({400});
+  list1.splice(std::next(list1.begin(), 3), list4, list4.begin());
+  AssertListEq(list1, {100, 1, 2, 400, 3, 700});
+  AssertListEq(list4, {});
+}
+
+TEST_F(IntrusiveListTest, splice_range) {
+  TestObjectList list1 = NewList({1, 2, 3});
+
+  // Splice at beginning.
+  TestObjectList list2 = NewList({100, 200, 300});
+  list1.splice(list1.begin(), list2, list2.begin(), std::prev(list2.end()));
+  AssertListEq(list1, {100, 200, 1, 2, 3});
+  AssertListEq(list2, {300});
+
+  // Splice at end.
+  TestObjectList list3 = NewList({500, 600, 700});
+  list1.splice(list1.end(), list3, std::next(list3.begin()), list3.end());
+  AssertListEq(list1, {100, 200, 1, 2, 3, 600, 700});
+  AssertListEq(list3, {500});
+
+  // Splice in the middle.
+  TestObjectList list4 = NewList({400});
+  list1.splice(std::next(list1.begin(), 4), list4, list4.begin(), list4.end());
+  AssertListEq(list1, {100, 200, 1, 2, 400, 3, 600, 700});
+  AssertListEq(list4, {});
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-literal.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-literal.cc
new file mode 100644 (file)
index 0000000..bce7a0b
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+ * Copyright 2018 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 <cassert>
+#include <cstdio>
+#include <thread>
+#include <vector>
+
+#include "gtest/gtest.h"
+
+#include "src/literal.h"
+
+using namespace wabt;
+
+namespace {
+
+enum ParseIntTypeCombo {
+  UnsignedOnly,
+  SignedAndUnsigned,
+  Both,
+};
+
+template <typename T, typename F>
+void AssertIntEquals(T expected,
+                     const char* s,
+                     F&& parse_int,
+                     ParseIntTypeCombo parse_type = Both) {
+  const char* const end = s + strlen(s);
+  T actual;
+  if (parse_type == UnsignedOnly || parse_type == Both) {
+    ASSERT_EQ(Result::Ok,
+              parse_int(s, end, &actual, ParseIntType::UnsignedOnly))
+        << s;
+    ASSERT_EQ(expected, actual);
+  } else {
+    ASSERT_EQ(Result::Error,
+              parse_int(s, end, &actual, ParseIntType::UnsignedOnly))
+        << s;
+  }
+
+  if (parse_type == SignedAndUnsigned || parse_type == Both) {
+    ASSERT_EQ(Result::Ok,
+              parse_int(s, end, &actual, ParseIntType::SignedAndUnsigned))
+        << s;
+    ASSERT_EQ(expected, actual);
+  } else {
+    ASSERT_EQ(Result::Error,
+              parse_int(s, end, &actual, ParseIntType::SignedAndUnsigned))
+        << s;
+  }
+}
+
+void AssertInt8Equals(uint8_t expected,
+                      const char* s,
+                      ParseIntTypeCombo parse_type = Both) {
+  AssertIntEquals(expected, s, ParseInt8, parse_type);
+}
+
+void AssertInt16Equals(uint16_t expected,
+                       const char* s,
+                       ParseIntTypeCombo parse_type = Both) {
+  AssertIntEquals(expected, s, ParseInt16, parse_type);
+}
+
+void AssertInt32Equals(uint32_t expected,
+                       const char* s,
+                       ParseIntTypeCombo parse_type = Both) {
+  AssertIntEquals(expected, s, ParseInt32, parse_type);
+}
+
+void AssertInt64Equals(uint64_t expected,
+                       const char* s,
+                       ParseIntTypeCombo parse_type = Both) {
+  AssertIntEquals(expected, s, ParseInt64, parse_type);
+}
+
+void AssertUint128Equals(v128 expected,
+                         const char* s) {
+  const char* const end = s + strlen(s);
+  v128 actual;
+  ASSERT_EQ(Result::Ok, ParseUint128(s, end, &actual)) << s;
+  ASSERT_EQ(expected, actual);
+}
+
+void AssertInt8Fails(const char* s) {
+  const char* const end = s + strlen(s);
+  uint8_t actual;
+  ASSERT_EQ(Result::Error,
+            ParseInt8(s, end, &actual, ParseIntType::SignedAndUnsigned))
+      << s;
+  ASSERT_EQ(Result::Error,
+            ParseInt8(s, end, &actual, ParseIntType::UnsignedOnly))
+      << s;
+}
+
+void AssertInt16Fails(const char* s) {
+  const char* const end = s + strlen(s);
+  uint16_t actual;
+  ASSERT_EQ(Result::Error,
+            ParseInt16(s, end, &actual, ParseIntType::SignedAndUnsigned))
+      << s;
+  ASSERT_EQ(Result::Error,
+            ParseInt16(s, end, &actual, ParseIntType::UnsignedOnly))
+      << s;
+}
+
+void AssertInt32Fails(const char* s) {
+  const char* const end = s + strlen(s);
+  uint32_t actual;
+  ASSERT_EQ(Result::Error,
+            ParseInt32(s, end, &actual, ParseIntType::SignedAndUnsigned))
+      << s;
+  ASSERT_EQ(Result::Error,
+            ParseInt32(s, end, &actual, ParseIntType::UnsignedOnly))
+      << s;
+}
+
+void AssertInt64Fails(const char* s) {
+  const char* const end = s + strlen(s);
+  uint64_t actual;
+  ASSERT_EQ(Result::Error,
+            ParseInt64(s, end, &actual, ParseIntType::SignedAndUnsigned))
+      << s;
+  ASSERT_EQ(Result::Error,
+            ParseInt64(s, end, &actual, ParseIntType::UnsignedOnly))
+      << s;
+}
+
+void AssertUint64Equals(uint64_t expected, const char* s) {
+  uint64_t actual;
+  ASSERT_EQ(Result::Ok, ParseUint64(s, s + strlen(s), &actual)) << s;
+  ASSERT_EQ(expected, actual);
+}
+
+void AssertUint64Fails(const char* s) {
+  uint64_t actual_bits;
+  ASSERT_EQ(Result::Error, ParseUint64(s, s + strlen(s), &actual_bits)) << s;
+}
+
+void AssertUint128Fails(const char* s) {
+  v128 actual;
+  ASSERT_EQ(Result::Error, ParseUint128(s, s + strlen(s), &actual)) << s;
+}
+
+void AssertHexFloatEquals(uint32_t expected_bits, const char* s) {
+  uint32_t actual_bits;
+  ASSERT_EQ(Result::Ok,
+            ParseFloat(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
+      << s;
+  ASSERT_EQ(expected_bits, actual_bits) << s;
+}
+
+void AssertHexFloatFails(const char* s) {
+  uint32_t actual_bits;
+  ASSERT_EQ(Result::Error,
+            ParseFloat(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
+      << s;
+}
+
+void AssertHexDoubleEquals(uint64_t expected_bits, const char* s) {
+  uint64_t actual_bits;
+  ASSERT_EQ(Result::Ok,
+            ParseDouble(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
+      << s;
+  ASSERT_EQ(expected_bits, actual_bits);
+}
+
+void AssertHexDoubleFails(const char* s) {
+  uint64_t actual_bits;
+  ASSERT_EQ(Result::Error,
+            ParseDouble(LiteralType::Hexfloat, s, s + strlen(s), &actual_bits))
+      << s;
+}
+
+}  // end anonymous namespace
+
+TEST(ParseInt8, Both) {
+  AssertInt8Equals(0, "0");
+  AssertInt8Equals(100, "100");
+  AssertInt8Equals(123, "123");
+  AssertInt8Equals(127, "127");
+  AssertInt8Equals(255, "255");
+  AssertInt8Equals(0xca, "0xca");
+  AssertInt8Equals(0x7f, "0x7f");
+  AssertInt8Equals(0x80, "0x80");
+  AssertInt8Equals(0xff, "0xff");
+}
+
+TEST(ParseInt8, SignedAndUnsigned) {
+  AssertInt8Equals(128, "-128", SignedAndUnsigned);
+  AssertInt8Equals(-0x80, "-0x80", SignedAndUnsigned);
+  AssertInt8Equals(255, "-1", SignedAndUnsigned);
+  AssertInt8Equals(-1, "-0x1", SignedAndUnsigned);
+  AssertInt8Equals(1, "+1", SignedAndUnsigned);
+  AssertInt8Equals(-0x7b, "-0x7B", SignedAndUnsigned);
+  AssertInt8Equals(0xab, "+0xab", SignedAndUnsigned);
+}
+
+TEST(ParseInt8, Invalid) {
+  AssertInt8Fails("");
+  AssertInt8Fails("-100hello");
+  AssertInt8Fails("0XAB");
+  AssertInt8Fails("0xga");
+  AssertInt8Fails("two");
+}
+
+TEST(ParseInt8, Underscores) {
+  AssertInt8Equals(123, "12_3", Both);
+  AssertInt8Equals(123, "+12_3", SignedAndUnsigned);
+  AssertInt8Equals(-123, "-1_23", SignedAndUnsigned);
+  AssertInt8Equals(19, "1______9", Both);
+  AssertInt8Equals(0xab, "0xa_b", Both);
+  AssertInt8Equals(0xab, "+0xa_b", SignedAndUnsigned);
+  AssertInt8Equals(-0x7b, "-0x7_b", SignedAndUnsigned);
+}
+
+TEST(ParseInt8, Overflow) {
+  AssertInt8Fails("256");
+  AssertInt8Fails("-129");
+  AssertInt8Fails("0x100");
+  AssertInt8Fails("-0x81");
+  AssertInt8Fails("1231231231231231231231");
+}
+
+TEST(ParseInt16, Both) {
+  AssertInt16Equals(0, "0");
+  AssertInt16Equals(1000, "1000");
+  AssertInt16Equals(12345, "12345");
+  AssertInt16Equals(32767, "32767");
+  AssertInt16Equals(65535, "65535");
+  AssertInt16Equals(0xcafe, "0xcafe");
+  AssertInt16Equals(0x7fff, "0x7fff");
+  AssertInt16Equals(0x8000, "0x8000");
+  AssertInt16Equals(0xffff, "0xffff");
+}
+
+TEST(ParseInt16, SignedAndUnsigned) {
+  AssertInt16Equals(32768, "-32768", SignedAndUnsigned);
+  AssertInt16Equals(-0x8000, "-0x8000", SignedAndUnsigned);
+  AssertInt16Equals(65535, "-1", SignedAndUnsigned);
+  AssertInt16Equals(-1, "-0x1", SignedAndUnsigned);
+  AssertInt16Equals(1, "+1", SignedAndUnsigned);
+  AssertInt16Equals(-0x7bcd, "-0x7BCD", SignedAndUnsigned);
+  AssertInt16Equals(0xabcd, "+0xabcd", SignedAndUnsigned);
+}
+
+TEST(ParseInt16, Invalid) {
+  AssertInt16Fails("");
+  AssertInt16Fails("-100hello");
+  AssertInt16Fails("0XABCD");
+  AssertInt16Fails("0xgabb");
+  AssertInt16Fails("two");
+}
+
+TEST(ParseInt16, Underscores) {
+  AssertInt16Equals(12345, "12_345", Both);
+  AssertInt16Equals(12345, "+12_345", SignedAndUnsigned);
+  AssertInt16Equals(-12345, "-123_45", SignedAndUnsigned);
+  AssertInt16Equals(19, "1______9", Both);
+  AssertInt16Equals(0xabcd, "0xa_b_c_d", Both);
+  AssertInt16Equals(0xabcd, "+0xa_b_c_d", SignedAndUnsigned);
+  AssertInt16Equals(-0x7bcd, "-0x7_b_c_d", SignedAndUnsigned);
+}
+
+TEST(ParseInt16, Overflow) {
+  AssertInt16Fails("65536");
+  AssertInt16Fails("-32769");
+  AssertInt16Fails("0x10000");
+  AssertInt16Fails("-0x8001");
+  AssertInt16Fails("1231231231231231231231");
+}
+
+TEST(ParseInt32, Both) {
+  AssertInt32Equals(0, "0");
+  AssertInt32Equals(1000, "1000");
+  AssertInt32Equals(123456789, "123456789");
+  AssertInt32Equals(2147483647, "2147483647");
+  AssertInt32Equals(4294967295u, "4294967295");
+  AssertInt32Equals(0xcafef00du, "0xcafef00d");
+  AssertInt32Equals(0x7fffffff, "0x7fffffff");
+  AssertInt32Equals(0x80000000u, "0x80000000");
+  AssertInt32Equals(0xffffffffu, "0xffffffff");
+}
+
+TEST(ParseInt32, SignedAndUnsigned) {
+  AssertInt32Equals(2147483648, "-2147483648", SignedAndUnsigned);
+  AssertInt32Equals(-0x80000000u, "-0x80000000", SignedAndUnsigned);
+  AssertInt32Equals(4294967295u, "-1", SignedAndUnsigned);
+  AssertInt32Equals(-1, "-0x1", SignedAndUnsigned);
+  AssertInt32Equals(1, "+1", SignedAndUnsigned);
+  AssertInt32Equals(-0xabcd, "-0xABCD", SignedAndUnsigned);
+  AssertInt32Equals(0xabcd, "+0xabcd", SignedAndUnsigned);
+}
+
+TEST(ParseInt32, Invalid) {
+  AssertInt32Fails("");
+  AssertInt32Fails("-100hello");
+  AssertInt32Fails("0XABCDEF");
+  AssertInt32Fails("0xgabba");
+  AssertInt32Fails("two");
+}
+
+TEST(ParseInt32, Underscores) {
+  AssertInt32Equals(123456789, "12_345_6789", Both);
+  AssertInt32Equals(123456789, "+12_345_6789", SignedAndUnsigned);
+  AssertInt32Equals(-123456789, "-12345_6789", SignedAndUnsigned);
+  AssertInt32Equals(19, "1______9", Both);
+  AssertInt32Equals(0xabcd, "0xa_b_c_d", Both);
+  AssertInt32Equals(0xabcd, "+0xa_b_c_d", SignedAndUnsigned);
+  AssertInt32Equals(-0xabcd, "-0xa_b_c_d", SignedAndUnsigned);
+}
+
+TEST(ParseInt32, Overflow) {
+  AssertInt32Fails("4294967296");
+  AssertInt32Fails("-2147483649");
+  AssertInt32Fails("0x100000000");
+  AssertInt32Fails("-0x80000001");
+  AssertInt32Fails("1231231231231231231231");
+}
+
+TEST(ParseInt64, Both) {
+  AssertInt64Equals(0, "0");
+  AssertInt64Equals(1000, "1000");
+  AssertInt64Equals(123456789, "123456789");
+  AssertInt64Equals(9223372036854775807ull, "9223372036854775807");
+  AssertInt64Equals(18446744073709551615ull, "18446744073709551615");
+  AssertInt64Equals(0x7fffffffffffffffull, "0x7fffffffffffffff");
+  AssertInt64Equals(0x8000000000000000ull, "0x8000000000000000");
+  AssertInt64Equals(0xffffffffffffffffull, "0xffffffffffffffff");
+}
+
+TEST(ParseInt64, SignedAndUnsigned) {
+  AssertInt64Equals(9223372036854775808ull, "-9223372036854775808",
+                    SignedAndUnsigned);
+  AssertInt64Equals(18446744073709551615ull, "-1", SignedAndUnsigned);
+  AssertInt64Equals(-1, "-0x1", SignedAndUnsigned);
+  AssertInt64Equals(1, "+1", SignedAndUnsigned);
+  AssertInt64Equals(-0x0bcdefabcdefabcdull, "-0x0BCDEFABCDEFABCD",
+                    SignedAndUnsigned);
+  AssertInt64Equals(0xabcdefabcdefabcdull, "+0xabcdefabcdefabcd",
+                    SignedAndUnsigned);
+}
+
+TEST(ParseInt64, Invalid) {
+  AssertInt64Fails("");
+  AssertInt64Fails("-100hello");
+  AssertInt64Fails("0XABCDEF");
+  AssertInt64Fails("0xgabba");
+  AssertInt64Fails("two");
+}
+
+TEST(ParseInt64, Underscores) {
+  AssertInt64Equals(123456789, "12_345_6789", Both);
+  AssertInt64Equals(123456789, "+12_345_6789", SignedAndUnsigned);
+  AssertInt64Equals(-123456789, "-12345_6789", SignedAndUnsigned);
+  AssertInt64Equals(19, "1______9", Both);
+  AssertInt64Equals(0xabcd, "0xa_b_c_d", Both);
+  AssertInt64Equals(0xabcd, "+0xa_b_c_d", SignedAndUnsigned);
+  AssertInt64Equals(-0xabcd, "-0xa_b_c_d", SignedAndUnsigned);
+}
+
+TEST(ParseInt64, Overflow) {
+  AssertInt64Fails("18446744073709551616");
+  AssertInt64Fails("-9223372036854775809");
+  AssertInt32Fails("0x10000000000000000");
+  AssertInt32Fails("-0x80000000000000001");
+  AssertInt64Fails("1231231231231231231231");
+}
+
+TEST(ParseUint64, Basic) {
+  AssertUint64Equals(0, "0");
+  AssertUint64Equals(1000, "1000");
+  AssertUint64Equals(123456789, "123456789");
+  AssertUint64Equals(1844674407370955161ull, "1844674407370955161");
+  AssertUint64Equals(18446744073709551615ull, "18446744073709551615");
+
+  AssertUint64Equals(0, "0x0");
+  AssertUint64Equals(0x1000, "0x1000");
+  AssertUint64Equals(0x123456789, "0x123456789");
+  AssertUint64Equals(0xabcdef, "0xabcdef");
+  AssertUint64Equals(0xffffffffffffffull, "0xffffffffffffff");
+  AssertUint64Equals(0xfffffffffffffffull, "0xfffffffffffffff");
+
+  AssertUint64Equals(0xabcdefabcdefabcdull, "0xabcdefabcdefabcd");
+}
+
+TEST(ParseUint64, NoOctal) {
+  AssertUint64Equals(100, "0100");
+  AssertUint64Equals(888, "0000888");
+}
+
+TEST(ParseUint64, Invalid) {
+  AssertUint64Fails("");
+  AssertUint64Fails("-100");
+  AssertUint64Fails("0XABCDEF");
+  AssertUint64Fails("0xgabba");
+  AssertUint64Fails("two");
+}
+
+TEST(ParseUint64, Underscores) {
+  AssertUint64Equals(123456789, "12_345_6789");
+  AssertUint64Equals(19, "1______9");
+  AssertUint64Equals(0xabcd, "0xa_b_c_d");
+}
+
+TEST(ParseUint64, Overflow) {
+  AssertUint64Fails("0x10000000000000000");
+  AssertUint64Fails("18446744073709551616");
+  AssertUint64Fails("62857453058642199420");
+  AssertUint64Fails("82000999361882825820");
+  AssertUint64Fails("126539114687237086210");
+  AssertUint64Fails("10000000000000000000000000000000000000000");
+}
+
+TEST(ParseUint128, Basic) {
+  AssertUint128Equals({0, 0, 0, 0}, "0");
+  AssertUint128Equals({1, 0, 0, 0}, "1");
+  AssertUint128Equals({0x100f0e0d, 0x0c0b0a09, 0x08070605, 0x04030201},
+                      "5332529520247008778714484145835150861");
+  AssertUint128Equals({0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff},
+                      "340282366920938463463374607431768211455");
+  AssertUint128Equals({0, 0, 1, 0}, "18446744073709551616");
+}
+
+TEST(ParseUint128, Invalid) {
+  AssertUint128Fails("");
+  AssertUint128Fails("-1");
+  AssertUint128Fails("340282366920938463463374607431768211456");
+  AssertUint128Fails("123a456");
+}
+
+TEST(ParseFloat, NonCanonical) {
+  AssertHexFloatEquals(0x3f800000, "0x00000000000000000000001.0p0");
+  AssertHexFloatEquals(0x3f800000, "0x1.00000000000000000000000p0");
+  AssertHexFloatEquals(0x3f800000, "0x0.0000000000000000000001p88");
+}
+
+TEST(ParseFloat, Basic) {
+  AssertHexFloatEquals(0, "0x0p0");
+  AssertHexFloatEquals(0x3f800000, "0x1");
+}
+
+TEST(ParseFloat, Rounding) {
+  // |------- 23 bits -----| V-- extra bit
+  //
+  // 11111111111111111111101 0  ==> no rounding
+  AssertHexFloatEquals(0x7f7ffffd, "0x1.fffffap127");
+  // 11111111111111111111101 1  ==> round up
+  AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffbp127");
+  // 11111111111111111111110 0  ==> no rounding
+  AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffcp127");
+  // 11111111111111111111110 1  ==> round down
+  AssertHexFloatEquals(0x7f7ffffe, "0x1.fffffdp127");
+  // 11111111111111111111111 0  ==> no rounding
+  AssertHexFloatEquals(0x7f7fffff, "0x1.fffffep127");
+}
+
+// Duplicate the spec tests here for easier debugging.
+TEST(ParseFloat, RoundingSpec) {
+  static const struct {
+    const char* input;
+    uint32_t output;
+  } kTests[] = {
+    {"+0x1.00000100000000000p-50", 0x26800000},
+    {"-0x1.00000100000000000p-50", 0xa6800000},
+    {"+0x1.00000100000000001p-50", 0x26800001},
+    {"-0x1.00000100000000001p-50", 0xa6800001},
+    {"+0x1.000001fffffffffffp-50", 0x26800001},
+    {"-0x1.000001fffffffffffp-50", 0xa6800001},
+    {"+0x1.00000200000000000p-50", 0x26800001},
+    {"-0x1.00000200000000000p-50", 0xa6800001},
+    {"+0x1.00000200000000001p-50", 0x26800001},
+    {"-0x1.00000200000000001p-50", 0xa6800001},
+    {"+0x1.000002fffffffffffp-50", 0x26800001},
+    {"-0x1.000002fffffffffffp-50", 0xa6800001},
+    {"+0x1.00000300000000000p-50", 0x26800002},
+    {"-0x1.00000300000000000p-50", 0xa6800002},
+    {"+0x1.00000300000000001p-50", 0x26800002},
+    {"-0x1.00000300000000001p-50", 0xa6800002},
+    {"+0x1.000003fffffffffffp-50", 0x26800002},
+    {"-0x1.000003fffffffffffp-50", 0xa6800002},
+    {"+0x1.00000400000000000p-50", 0x26800002},
+    {"-0x1.00000400000000000p-50", 0xa6800002},
+    {"+0x1.00000400000000001p-50", 0x26800002},
+    {"-0x1.00000400000000001p-50", 0xa6800002},
+    {"+0x1.000004fffffffffffp-50", 0x26800002},
+    {"-0x1.000004fffffffffffp-50", 0xa6800002},
+    {"+0x1.00000500000000000p-50", 0x26800002},
+    {"-0x1.00000500000000000p-50", 0xa6800002},
+    {"+0x1.00000500000000001p-50", 0x26800003},
+    {"-0x1.00000500000000001p-50", 0xa6800003},
+    {"+0x4000.004000000p-64", 0x26800000},
+    {"-0x4000.004000000p-64", 0xa6800000},
+    {"+0x4000.004000001p-64", 0x26800001},
+    {"-0x4000.004000001p-64", 0xa6800001},
+    {"+0x4000.007ffffffp-64", 0x26800001},
+    {"-0x4000.007ffffffp-64", 0xa6800001},
+    {"+0x4000.008000000p-64", 0x26800001},
+    {"-0x4000.008000000p-64", 0xa6800001},
+    {"+0x4000.008000001p-64", 0x26800001},
+    {"-0x4000.008000001p-64", 0xa6800001},
+    {"+0x4000.00bffffffp-64", 0x26800001},
+    {"-0x4000.00bffffffp-64", 0xa6800001},
+    {"+0x4000.00c000000p-64", 0x26800002},
+    {"-0x4000.00c000000p-64", 0xa6800002},
+    {"+0x4000.00c000001p-64", 0x26800002},
+    {"-0x4000.00c000001p-64", 0xa6800002},
+    {"+0x4000.00fffffffp-64", 0x26800002},
+    {"-0x4000.00fffffffp-64", 0xa6800002},
+    {"+0x4000.010000001p-64", 0x26800002},
+    {"-0x4000.010000001p-64", 0xa6800002},
+    {"+0x4000.013ffffffp-64", 0x26800002},
+    {"-0x4000.013ffffffp-64", 0xa6800002},
+    {"+0x4000.014000001p-64", 0x26800003},
+    {"-0x4000.014000001p-64", 0xa6800003},
+    {"+0x1.00000100000000000p+50", 0x58800000},
+    {"-0x1.00000100000000000p+50", 0xd8800000},
+    {"+0x1.00000100000000001p+50", 0x58800001},
+    {"-0x1.00000100000000001p+50", 0xd8800001},
+    {"+0x1.000001fffffffffffp+50", 0x58800001},
+    {"-0x1.000001fffffffffffp+50", 0xd8800001},
+    {"+0x1.00000200000000000p+50", 0x58800001},
+    {"-0x1.00000200000000000p+50", 0xd8800001},
+    {"+0x1.00000200000000001p+50", 0x58800001},
+    {"-0x1.00000200000000001p+50", 0xd8800001},
+    {"+0x1.000002fffffffffffp+50", 0x58800001},
+    {"-0x1.000002fffffffffffp+50", 0xd8800001},
+    {"+0x1.00000300000000000p+50", 0x58800002},
+    {"-0x1.00000300000000000p+50", 0xd8800002},
+    {"+0x1.00000300000000001p+50", 0x58800002},
+    {"-0x1.00000300000000001p+50", 0xd8800002},
+    {"+0x1.000003fffffffffffp+50", 0x58800002},
+    {"-0x1.000003fffffffffffp+50", 0xd8800002},
+    {"+0x1.00000400000000000p+50", 0x58800002},
+    {"-0x1.00000400000000000p+50", 0xd8800002},
+    {"+0x1.00000400000000001p+50", 0x58800002},
+    {"-0x1.00000400000000001p+50", 0xd8800002},
+    {"+0x1.000004fffffffffffp+50", 0x58800002},
+    {"-0x1.000004fffffffffffp+50", 0xd8800002},
+    {"+0x1.00000500000000000p+50", 0x58800002},
+    {"-0x1.00000500000000000p+50", 0xd8800002},
+    {"+0x1.00000500000000001p+50", 0x58800003},
+    {"-0x1.00000500000000001p+50", 0xd8800003},
+    {"+0x4000004000000", 0x58800000},
+    {"-0x4000004000000", 0xd8800000},
+    {"+0x4000004000001", 0x58800001},
+    {"-0x4000004000001", 0xd8800001},
+    {"+0x4000007ffffff", 0x58800001},
+    {"-0x4000007ffffff", 0xd8800001},
+    {"+0x4000008000000", 0x58800001},
+    {"-0x4000008000000", 0xd8800001},
+    {"+0x4000008000001", 0x58800001},
+    {"-0x4000008000001", 0xd8800001},
+    {"+0x400000bffffff", 0x58800001},
+    {"-0x400000bffffff", 0xd8800001},
+    {"+0x400000c000000", 0x58800002},
+    {"-0x400000c000000", 0xd8800002},
+    {"+0x0.00000100000000000p-126", 0x0},
+    {"-0x0.00000100000000000p-126", 0x80000000},
+    {"+0x0.00000100000000001p-126", 0x1},
+    {"-0x0.00000100000000001p-126", 0x80000001},
+    {"+0x0.00000101000000000p-126", 0x1},
+    {"+0x0.000001fffffffffffp-126", 0x1},
+    {"-0x0.000001fffffffffffp-126", 0x80000001},
+    {"+0x0.00000200000000000p-126", 0x1},
+    {"-0x0.00000200000000000p-126", 0x80000001},
+    {"+0x0.00000200000000001p-126", 0x1},
+    {"-0x0.00000200000000001p-126", 0x80000001},
+    {"+0x0.000002fffffffffffp-126", 0x1},
+    {"-0x0.000002fffffffffffp-126", 0x80000001},
+    {"+0x0.00000300000000000p-126", 0x2},
+    {"-0x0.00000300000000000p-126", 0x80000002},
+    {"+0x0.00000300000000001p-126", 0x2},
+    {"-0x0.00000300000000001p-126", 0x80000002},
+    {"+0x0.000003fffffffffffp-126", 0x2},
+    {"-0x0.000003fffffffffffp-126", 0x80000002},
+    {"+0x0.00000400000000000p-126", 0x2},
+    {"-0x0.00000400000000000p-126", 0x80000002},
+    {"+0x0.00000400000000001p-126", 0x2},
+    {"-0x0.00000400000000001p-126", 0x80000002},
+    {"+0x0.000004fffffffffffp-126", 0x2},
+    {"-0x0.000004fffffffffffp-126", 0x80000002},
+    {"+0x0.00000500000000000p-126", 0x2},
+    {"-0x0.00000500000000000p-126", 0x80000002},
+    {"+0x0.00000500000000001p-126", 0x3},
+    {"-0x0.00000500000000001p-126", 0x80000003},
+    {"+0x1.fffffe8p127", 0x7f7fffff},
+    {"-0x1.fffffe8p127", 0xff7fffff},
+    {"+0x1.fffffefffffff8p127", 0x7f7fffff},
+    {"-0x1.fffffefffffff8p127", 0xff7fffff},
+    {"+0x1.fffffefffffffffffp127", 0x7f7fffff},
+    {"-0x1.fffffefffffffffffp127", 0xff7fffff},
+  };
+
+  for (auto test: kTests) {
+    AssertHexFloatEquals(test.output, test.input);
+  }
+}
+
+TEST(ParseFloat, OutOfRange) {
+  AssertHexFloatFails("0x1p128");
+  AssertHexFloatFails("-0x1p128");
+  AssertHexFloatFails("0x1.ffffffp127");
+  AssertHexFloatFails("-0x1.ffffffp127");
+}
+
+TEST(ParseDouble, NonCanonical) {
+  AssertHexDoubleEquals(0x3ff0000000000000, "0x00000000000000000000001.0p0");
+  AssertHexDoubleEquals(0x3ff0000000000000, "0x1.00000000000000000000000p0");
+  AssertHexDoubleEquals(0x3ff0000000000000, "0x0.0000000000000000000001p88");
+}
+
+TEST(ParseDouble, Rounding) {
+  // |-------------------- 52 bits ---------------------| V-- extra bit
+  //
+  // 1111111111111111111111111111111111111111111111111101 0  ==> no rounding
+  AssertHexDoubleEquals(0x7feffffffffffffd, "0x1.ffffffffffffd0p1023");
+  // 1111111111111111111111111111111111111111111111111101 1  ==> round up
+  AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffd8p1023");
+  // 1111111111111111111111111111111111111111111111111110 0  ==> no rounding
+  AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe0p1023");
+  // 1111111111111111111111111111111111111111111111111110 1  ==> round down
+  AssertHexDoubleEquals(0x7feffffffffffffe, "0x1.ffffffffffffe8p1023");
+  // 1111111111111111111111111111111111111111111111111111 0  ==> no rounding
+  AssertHexDoubleEquals(0x7fefffffffffffff, "0x1.fffffffffffff0p1023");
+}
+
+TEST(ParseDouble, OutOfRange) {
+  AssertHexDoubleFails("0x1p1024");
+  AssertHexDoubleFails("-0x1p1024");
+  AssertHexDoubleFails("0x1.fffffffffffff8p1023");
+  AssertHexDoubleFails("-0x1.fffffffffffff8p1023");
+}
+
+// Duplicate the spec tests here for easier debugging.
+TEST(ParseDouble, RoundingSpec) {
+  static const struct {
+    const char* input;
+    uint64_t output;
+  } kTests[] = {
+    {"+0x1.000000000000080000000000p-600", 1905022642377719808ull},
+    {"-0x1.000000000000080000000000p-600", 11128394679232495616ull},
+    {"+0x1.000000000000080000000001p-600", 1905022642377719809ull},
+    {"-0x1.000000000000080000000001p-600", 11128394679232495617ull},
+    {"+0x1.0000000000000fffffffffffp-600", 1905022642377719809ull},
+    {"-0x1.0000000000000fffffffffffp-600", 11128394679232495617ull},
+    {"+0x1.000000000000100000000000p-600", 1905022642377719809ull},
+    {"-0x1.000000000000100000000000p-600", 11128394679232495617ull},
+    {"+0x1.000000000000100000000001p-600", 1905022642377719809ull},
+    {"-0x1.000000000000100000000001p-600", 11128394679232495617ull},
+    {"+0x1.00000000000017ffffffffffp-600", 1905022642377719809ull},
+    {"-0x1.00000000000017ffffffffffp-600", 11128394679232495617ull},
+    {"+0x1.000000000000180000000000p-600", 1905022642377719810ull},
+    {"-0x1.000000000000180000000000p-600", 11128394679232495618ull},
+    {"+0x1.000000000000180000000001p-600", 1905022642377719810ull},
+    {"-0x1.000000000000180000000001p-600", 11128394679232495618ull},
+    {"+0x1.0000000000001fffffffffffp-600", 1905022642377719810ull},
+    {"-0x1.0000000000001fffffffffffp-600", 11128394679232495618ull},
+    {"+0x1.000000000000200000000000p-600", 1905022642377719810ull},
+    {"-0x1.000000000000200000000000p-600", 11128394679232495618ull},
+    {"+0x1.000000000000200000000001p-600", 1905022642377719810ull},
+    {"-0x1.000000000000200000000001p-600", 11128394679232495618ull},
+    {"+0x1.00000000000027ffffffffffp-600", 1905022642377719810ull},
+    {"-0x1.00000000000027ffffffffffp-600", 11128394679232495618ull},
+    {"+0x1.000000000000280000000001p-600", 1905022642377719811ull},
+    {"-0x1.000000000000280000000001p-600", 11128394679232495619ull},
+    {"+0x8000000.000000400000000000p-627", 1905022642377719808ull},
+    {"-0x8000000.000000400000000000p-627", 11128394679232495616ull},
+    {"+0x8000000.000000400000000001p-627", 1905022642377719809ull},
+    {"-0x8000000.000000400000000001p-627", 11128394679232495617ull},
+    {"+0x8000000.0000007fffffffffffp-627", 1905022642377719809ull},
+    {"-0x8000000.0000007fffffffffffp-627", 11128394679232495617ull},
+    {"+0x8000000.000000800000000000p-627", 1905022642377719809ull},
+    {"-0x8000000.000000800000000000p-627", 11128394679232495617ull},
+    {"+0x8000000.000000800000000001p-627", 1905022642377719809ull},
+    {"-0x8000000.000000800000000001p-627", 11128394679232495617ull},
+    {"+0x8000000.000000bfffffffffffp-627", 1905022642377719809ull},
+    {"-0x8000000.000000bfffffffffffp-627", 11128394679232495617ull},
+    {"+0x8000000.000000c00000000000p-627", 1905022642377719810ull},
+    {"-0x8000000.000000c00000000000p-627", 11128394679232495618ull},
+    {"+0x8000000.000000c00000000001p-627", 1905022642377719810ull},
+    {"-0x8000000.000000c00000000001p-627", 11128394679232495618ull},
+    {"+0x8000000.000000ffffffffffffp-627", 1905022642377719810ull},
+    {"-0x8000000.000000ffffffffffffp-627", 11128394679232495618ull},
+    {"+0x8000000.000001000000000000p-627", 1905022642377719810ull},
+    {"-0x8000000.000001000000000000p-627", 11128394679232495618ull},
+    {"+0x8000000.000001000000000001p-627", 1905022642377719810ull},
+    {"-0x8000000.000001000000000001p-627", 11128394679232495618ull},
+    {"+0x8000000.0000013fffffffffffp-627", 1905022642377719810ull},
+    {"-0x8000000.0000013fffffffffffp-627", 11128394679232495618ull},
+    {"+0x8000000.000001400000000001p-627", 1905022642377719811ull},
+    {"-0x8000000.000001400000000001p-627", 11128394679232495619ull},
+    {"+0x1.000000000000080000000000p+600", 7309342195222315008ull},
+    {"-0x1.000000000000080000000000p+600", 16532714232077090816ull},
+    {"+0x1.000000000000080000000001p+600", 7309342195222315009ull},
+    {"-0x1.000000000000080000000001p+600", 16532714232077090817ull},
+    {"+0x1.0000000000000fffffffffffp+600", 7309342195222315009ull},
+    {"-0x1.0000000000000fffffffffffp+600", 16532714232077090817ull},
+    {"+0x1.000000000000100000000000p+600", 7309342195222315009ull},
+    {"-0x1.000000000000100000000000p+600", 16532714232077090817ull},
+    {"+0x1.000000000000100000000001p+600", 7309342195222315009ull},
+    {"-0x1.000000000000100000000001p+600", 16532714232077090817ull},
+    {"+0x1.00000000000017ffffffffffp+600", 7309342195222315009ull},
+    {"-0x1.00000000000017ffffffffffp+600", 16532714232077090817ull},
+    {"+0x1.000000000000180000000000p+600", 7309342195222315010ull},
+    {"-0x1.000000000000180000000000p+600", 16532714232077090818ull},
+    {"+0x1.000000000000180000000001p+600", 7309342195222315010ull},
+    {"-0x1.000000000000180000000001p+600", 16532714232077090818ull},
+    {"+0x1.0000000000001fffffffffffp+600", 7309342195222315010ull},
+    {"-0x1.0000000000001fffffffffffp+600", 16532714232077090818ull},
+    {"+0x1.000000000000200000000000p+600", 7309342195222315010ull},
+    {"-0x1.000000000000200000000000p+600", 16532714232077090818ull},
+    {"+0x1.000000000000200000000001p+600", 7309342195222315010ull},
+    {"-0x1.000000000000200000000001p+600", 16532714232077090818ull},
+    {"+0x1.00000000000027ffffffffffp+600", 7309342195222315010ull},
+    {"-0x1.00000000000027ffffffffffp+600", 16532714232077090818ull},
+    {"+0x1.000000000000280000000000p+600", 7309342195222315010ull},
+    {"-0x1.000000000000280000000000p+600", 16532714232077090818ull},
+    {"+0x1.000000000000280000000001p+600", 7309342195222315011ull},
+    {"-0x1.000000000000280000000001p+600", 16532714232077090819ull},
+    {"+0x2000000000000100000000000", 5044031582654955520ull},
+    {"-0x2000000000000100000000000", 14267403619509731328ull},
+    {"+0x2000000000000100000000001", 5044031582654955521ull},
+    {"-0x2000000000000100000000001", 14267403619509731329ull},
+    {"+0x20000000000001fffffffffff", 5044031582654955521ull},
+    {"-0x20000000000001fffffffffff", 14267403619509731329ull},
+    {"+0x2000000000000200000000000", 5044031582654955521ull},
+    {"-0x2000000000000200000000000", 14267403619509731329ull},
+    {"+0x2000000000000200000000001", 5044031582654955521ull},
+    {"-0x2000000000000200000000001", 14267403619509731329ull},
+    {"+0x20000000000002fffffffffff", 5044031582654955521ull},
+    {"-0x20000000000002fffffffffff", 14267403619509731329ull},
+    {"+0x2000000000000300000000000", 5044031582654955522ull},
+    {"-0x2000000000000300000000000", 14267403619509731330ull},
+    {"+0x2000000000000300000000001", 5044031582654955522ull},
+    {"-0x2000000000000300000000001", 14267403619509731330ull},
+    {"+0x20000000000003fffffffffff", 5044031582654955522ull},
+    {"-0x20000000000003fffffffffff", 14267403619509731330ull},
+    {"+0x2000000000000400000000000", 5044031582654955522ull},
+    {"-0x2000000000000400000000000", 14267403619509731330ull},
+    {"+0x2000000000000400000000001", 5044031582654955522ull},
+    {"-0x2000000000000400000000001", 14267403619509731330ull},
+    {"+0x20000000000004fffffffffff", 5044031582654955522ull},
+    {"-0x20000000000004fffffffffff", 14267403619509731330ull},
+    {"+0x2000000000000500000000000", 5044031582654955522ull},
+    {"-0x2000000000000500000000000", 14267403619509731330ull},
+    {"+0x2000000000000500000000001", 5044031582654955523ull},
+    {"-0x2000000000000500000000001", 14267403619509731331ull},
+    {"+0x0.000000000000080000000000p-1022", 0ull},
+    {"-0x0.000000000000080000000000p-1022", 9223372036854775808ull},
+    {"+0x0.000000000000080000000001p-1022", 1ull},
+    {"-0x0.000000000000080000000001p-1022", 9223372036854775809ull},
+    {"+0x0.0000000000000fffffffffffp-1022", 1ull},
+    {"-0x0.0000000000000fffffffffffp-1022", 9223372036854775809ull},
+    {"+0x0.000000000000100000000000p-1022", 1ull},
+    {"-0x0.000000000000100000000000p-1022", 9223372036854775809ull},
+    {"+0x0.000000000000100000000001p-1022", 1ull},
+    {"-0x0.000000000000100000000001p-1022", 9223372036854775809ull},
+    {"+0x0.00000000000017ffffffffffp-1022", 1ull},
+    {"-0x0.00000000000017ffffffffffp-1022", 9223372036854775809ull},
+    {"+0x0.000000000000180000000000p-1022", 2ull},
+    {"-0x0.000000000000180000000000p-1022", 9223372036854775810ull},
+    {"+0x0.000000000000180000000001p-1022", 2ull},
+    {"-0x0.000000000000180000000001p-1022", 9223372036854775810ull},
+    {"+0x0.0000000000001fffffffffffp-1022", 2ull},
+    {"-0x0.0000000000001fffffffffffp-1022", 9223372036854775810ull},
+    {"+0x0.000000000000200000000000p-1022", 2ull},
+    {"-0x0.000000000000200000000000p-1022", 9223372036854775810ull},
+    {"+0x0.000000000000200000000001p-1022", 2ull},
+    {"-0x0.000000000000200000000001p-1022", 9223372036854775810ull},
+    {"+0x0.00000000000027ffffffffffp-1022", 2ull},
+    {"-0x0.00000000000027ffffffffffp-1022", 9223372036854775810ull},
+    {"+0x0.000000000000280000000000p-1022", 2ull},
+    {"-0x0.000000000000280000000000p-1022", 9223372036854775810ull},
+    {"+0x1.000000000000280000000001p-1022", 4503599627370499ull},
+    {"-0x1.000000000000280000000001p-1022", 9227875636482146307ull},
+    {"+0x1.fffffffffffff4p1023", 9218868437227405311ull},
+    {"-0x1.fffffffffffff4p1023", 18442240474082181119ull},
+    {"+0x1.fffffffffffff7ffffffp1023", 9218868437227405311ull},
+    {"-0x1.fffffffffffff7ffffffp1023", 18442240474082181119ull},
+  };
+
+  for (auto test: kTests) {
+    AssertHexDoubleEquals(test.output, test.input);
+  }
+}
+
+void AssertWriteUint128Equals(const v128& value, const std::string& expected) {
+  assert(expected.length() < 128);
+  char buffer[128];
+  WriteUint128(buffer, 128, value);
+  std::string actual(buffer, buffer + expected.length());
+  ASSERT_EQ(expected, actual);
+  ASSERT_EQ(buffer[expected.length()], '\0');
+}
+
+TEST(WriteUint128, Basic) {
+  AssertWriteUint128Equals({0, 0, 0, 0}, "0");
+  AssertWriteUint128Equals({1, 0, 0, 0}, "1");
+  AssertWriteUint128Equals({0x100f0e0d, 0x0c0b0a09, 0x08070605, 0x04030201},
+                           "5332529520247008778714484145835150861");
+  AssertWriteUint128Equals({0x00112233, 0x44556677, 0x8899aabb, 0xccddeeff},
+                           "272314856204801878456120017448021860915");
+  AssertWriteUint128Equals({0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff},
+                           "340282366920938463463374607431768211455");
+  AssertWriteUint128Equals({0, 0, 1, 0}, "18446744073709551616");
+}
+
+TEST(WriteUint128, BufferTooSmall) {
+  {
+    char buffer[20];
+    WriteUint128(buffer, 20, {0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff});
+    ASSERT_EQ(buffer[19], '\0');
+    std::string actual(buffer, buffer + 19);
+    ASSERT_EQ("3402823669209384634", actual);
+  }
+
+  {
+    char buffer[3];
+    WriteUint128(buffer, 3, {123, 0, 0, 0});
+    ASSERT_EQ(buffer[0], '1');
+    ASSERT_EQ(buffer[1], '2');
+    ASSERT_EQ(buffer[2], '\0');
+  }
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-option-parser.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-option-parser.cc
new file mode 100644 (file)
index 0000000..9295c58
--- /dev/null
@@ -0,0 +1,181 @@
+// Copyright 2019 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 "gtest/gtest.h"
+
+#include <string>
+
+#include "src/option-parser.h"
+
+using namespace wabt;
+
+#define ERROR_ENDING "\nTry '--help' for more information."
+
+TEST(OptionParser, LongFlag) {
+  bool flag = false;
+  OptionParser parser("prog", "desc");
+  parser.AddOption("flag", "help", [&]() { flag = true; });
+  const char* args[] = {"prog name", "--flag"};
+  parser.Parse(2, const_cast<char**>(args));
+  EXPECT_EQ(true, flag);
+}
+
+TEST(OptionParser, ShortAndLongFlag) {
+  int count = 0;
+  OptionParser parser("prog", "desc");
+  parser.AddOption('f', "flag", "help", [&]() { ++count; });
+  const char* args[] = {"prog name", "-f", "--flag", "-f", "--flag"};
+  parser.Parse(5, const_cast<char**>(args));
+  EXPECT_EQ(4, count);
+}
+
+TEST(OptionParser, ShortFlagCombined) {
+  int count = 0;
+  OptionParser parser("prog", "desc");
+  parser.AddOption('a', "a", "help", [&]() { count += 1; });
+  parser.AddOption('b', "b", "help", [&]() { count += 2; });
+  const char* args[] = {"prog name", "-aa", "-abb"};
+  parser.Parse(3, const_cast<char**>(args));
+  EXPECT_EQ(7, count);
+}
+
+TEST(OptionParser, UnknownShortOption) {
+  std::string error;
+  OptionParser parser("prog", "desc");
+  parser.SetErrorCallback([&](const char* msg) { error = msg; });
+  const char* args[] = {"prog name", "-f"};
+  parser.Parse(2, const_cast<char**>(args));
+  EXPECT_EQ(error, "prog: unknown option '-f'" ERROR_ENDING);
+}
+
+TEST(OptionParser, UnknownLongOption) {
+  std::string error;
+  OptionParser parser("prog", "desc");
+  parser.SetErrorCallback([&](const char* msg) { error = msg; });
+  const char* args[] = {"prog name", "--foo"};
+  parser.Parse(2, const_cast<char**>(args));
+  EXPECT_EQ(error, "prog: unknown option '--foo'" ERROR_ENDING);
+}
+
+TEST(OptionParser, ShortAndLongParam) {
+  std::string param;
+  OptionParser parser("prog", "desc");
+  parser.AddOption('p', "param", "metavar", "help",
+                   [&](const char* arg) { param += arg; });
+  const char* args[] = {"prog name", "-p", "h", "--param", "el", "--param=lo"};
+  parser.Parse(6, const_cast<char**>(args));
+  EXPECT_EQ("hello", param);
+}
+
+TEST(OptionParser, MissingParam) {
+  std::string error;
+  std::string param;
+  OptionParser parser("prog", "desc");
+  parser.SetErrorCallback([&](const char* msg) { error = msg; });
+  parser.AddOption('p', "param", "metavar", "help",
+                   [&](const char* arg) { param = arg; });
+  const char* args[] = {"prog name", "--param"};
+  parser.Parse(2, const_cast<char**>(args));
+  EXPECT_EQ("", param);
+  EXPECT_EQ(error, "prog: option '--param' requires argument" ERROR_ENDING);
+}
+
+TEST(OptionParser, MissingArgument) {
+  std::string error;
+  OptionParser parser("prog", "desc");
+  parser.AddArgument("arg", OptionParser::ArgumentCount::One,
+                     [&](const char* arg) {});
+  parser.SetErrorCallback([&](const char* msg) { error = msg; });
+  const char* args[] = {"prog name"};
+  parser.Parse(1, const_cast<char**>(args));
+  EXPECT_EQ(error, "prog: expected arg argument." ERROR_ENDING);
+}
+
+TEST(OptionParser, FlagCombinedAfterShortParam) {
+  std::string error;
+  std::string param;
+  bool has_x = false;
+
+  OptionParser parser("prog", "desc");
+  parser.SetErrorCallback([&](const char* msg) { error = msg; });
+  parser.AddOption('p', "p", "metavar", "help",
+                   [&](const char* arg) { param = arg; });
+  parser.AddOption('x', "x", "help", [&]() { has_x = true; });
+  const char* args[] = {"prog name", "-px", "stuff"};
+  parser.Parse(3, const_cast<char**>(args));
+  EXPECT_EQ("", param);
+  EXPECT_TRUE(has_x);
+  EXPECT_EQ(error, "prog: unexpected argument 'stuff'" ERROR_ENDING);
+}
+
+
+TEST(OptionParser, OneArgument) {
+  std::string argument;
+  OptionParser parser("prog", "desc");
+  parser.AddArgument("arg", OptionParser::ArgumentCount::One,
+                     [&](const char* arg) { argument = arg; });
+  const char* args[] = {"prog name", "hello"};
+  parser.Parse(2, const_cast<char**>(args));
+  EXPECT_EQ("hello", argument);
+}
+
+TEST(OptionParser, TooManyArguments) {
+  std::string error;
+  OptionParser parser("prog", "desc");
+  parser.SetErrorCallback([&](const char* msg) { error = msg; });
+  parser.AddArgument("arg", OptionParser::ArgumentCount::One,
+                     [&](const char* arg) {});
+  const char* args[] = {"prog name", "hello", "goodbye"};
+  parser.Parse(3, const_cast<char**>(args));
+  EXPECT_EQ(error, "prog: unexpected argument 'goodbye'" ERROR_ENDING);
+}
+
+TEST(OptionParser, OneOrMoreArguments) {
+  std::string argument;
+  OptionParser parser("prog", "desc");
+  parser.AddArgument("arg", OptionParser::ArgumentCount::OneOrMore,
+                     [&](const char* arg) { argument += arg; });
+  const char* args[] = {"prog name", "hello", "goodbye"};
+  parser.Parse(3, const_cast<char**>(args));
+  EXPECT_EQ("hellogoodbye", argument);
+}
+
+TEST(OptionParser, ZeroOrMoreArguments) {
+  std::string argument;
+  OptionParser parser("prog", "desc");
+  parser.AddArgument("arg", OptionParser::ArgumentCount::ZeroOrMore,
+                     [&](const char* arg) { argument += arg; });
+
+  const char* args_none[] = {"prog name"};
+  parser.Parse(1, const_cast<char**>(args_none));
+  EXPECT_EQ("", argument);
+
+  const char* args_many[] = {"prog name", "hello", "goodbye"};
+  parser.Parse(3, const_cast<char**>(args_many));
+  EXPECT_EQ("hellogoodbye", argument);
+}
+
+TEST(OptionParser, StopProccessing) {
+  std::string argument;
+  bool has_x = false;
+  OptionParser parser("prog", "desc");
+  parser.AddArgument("arg", OptionParser::ArgumentCount::ZeroOrMore,
+                     [&](const char* arg) { argument += arg; });
+  parser.AddOption('x', "x", "help", [&]() { has_x = true; });
+
+  const char* args_many[] = {"prog name", "-x", "--", "foo", "-x", "-y", "bar"};
+  parser.Parse(7, const_cast<char**>(args_many));
+  EXPECT_TRUE(has_x);
+  EXPECT_EQ("foo-x-ybar", argument);
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-string-view.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-string-view.cc
new file mode 100644 (file)
index 0000000..4a4499d
--- /dev/null
@@ -0,0 +1,415 @@
+/*
+ * 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 "gtest/gtest.h"
+
+#include "src/string-view.h"
+
+#include <cstring>
+#include <functional>
+
+using namespace wabt;
+
+namespace {
+
+void assert_string_view_eq(const char* s, string_view sv) {
+  size_t len = std::strlen(s);
+  ASSERT_EQ(len, sv.size());
+  for (size_t i = 0; i < len; ++i) {
+    ASSERT_EQ(s[i], sv[i]);
+  }
+}
+
+constexpr string_view::size_type npos = string_view::npos;
+
+}  // end anonymous namespace
+
+TEST(string_view, default_constructor) {
+  assert_string_view_eq("", string_view());
+}
+
+TEST(string_view, copy_constructor) {
+  string_view sv1("copy");
+  assert_string_view_eq("copy", string_view(sv1));
+
+  string_view sv2;
+  assert_string_view_eq("", string_view(sv2));
+}
+
+TEST(string_view, assignment_operator) {
+  string_view sv1;
+  sv1 = string_view("assign");
+  assert_string_view_eq("assign", sv1);
+
+  string_view sv2;
+  sv2 = string_view();
+  assert_string_view_eq("", sv2);
+}
+
+TEST(string_view, string_constructor) {
+  assert_string_view_eq("", string_view(std::string()));
+  assert_string_view_eq("string", string_view(std::string("string")));
+}
+
+TEST(string_view, cstr_constructor) {
+  assert_string_view_eq("", string_view(""));
+  assert_string_view_eq("cstr", string_view("cstr"));
+}
+
+TEST(string_view, cstr_len_constructor) {
+  assert_string_view_eq("", string_view("foo-bar-baz", 0));
+  assert_string_view_eq("foo", string_view("foo-bar-baz", 3));
+  assert_string_view_eq("foo-bar", string_view("foo-bar-baz", 7));
+}
+
+TEST(string_view, begin_end) {
+  string_view sv("012345");
+
+  char count = 0;
+  for (auto iter = sv.begin(), end = sv.end(); iter != end; ++iter) {
+    ASSERT_EQ('0' + count, *iter);
+    ++count;
+  }
+  ASSERT_EQ(6, count);
+}
+
+TEST(string_view, cbegin_cend) {
+  const string_view sv("012345");
+
+  char count = 0;
+  for (auto iter = sv.cbegin(), end = sv.cend(); iter != end; ++iter) {
+    ASSERT_EQ('0' + count, *iter);
+    ++count;
+  }
+  ASSERT_EQ(6, count);
+}
+
+TEST(string_view, rbegin_rend) {
+  string_view sv("012345");
+
+  char count = 0;
+  for (auto iter = sv.rbegin(), end = sv.rend(); iter != end; ++iter) {
+    ASSERT_EQ('5' - count, *iter);
+    ++count;
+  }
+  ASSERT_EQ(6, count);
+}
+
+TEST(string_view, crbegin_crend) {
+  const string_view sv("012345");
+
+  char count = 0;
+  for (auto iter = sv.crbegin(), end = sv.crend(); iter != end; ++iter) {
+    ASSERT_EQ('5' - count, *iter);
+    ++count;
+  }
+  ASSERT_EQ(6, count);
+}
+
+TEST(string_view, size) {
+  string_view sv1;
+  ASSERT_EQ(0U, sv1.size());
+
+  string_view sv2("");
+  ASSERT_EQ(0U, sv2.size());
+
+  string_view sv3("hello");
+  ASSERT_EQ(5U, sv3.size());
+}
+
+TEST(string_view, length) {
+  string_view sv1;
+  ASSERT_EQ(0U, sv1.length());
+
+  string_view sv2("hello");
+  ASSERT_EQ(5U, sv2.length());
+}
+
+TEST(string_view, empty) {
+  string_view sv1;
+  ASSERT_TRUE(sv1.empty());
+
+  string_view sv2("bye");
+  ASSERT_FALSE(sv2.empty());
+}
+
+TEST(string_view, operator_bracket) {
+  string_view sv("words");
+  ASSERT_EQ('w', sv[0]);
+  ASSERT_EQ('o', sv[1]);
+  ASSERT_EQ('r', sv[2]);
+  ASSERT_EQ('d', sv[3]);
+  ASSERT_EQ('s', sv[4]);
+}
+
+TEST(string_view, at) {
+  string_view sv("words");
+  ASSERT_EQ('w', sv.at(0));
+  ASSERT_EQ('o', sv.at(1));
+  ASSERT_EQ('r', sv.at(2));
+  ASSERT_EQ('d', sv.at(3));
+  ASSERT_EQ('s', sv.at(4));
+}
+
+TEST(string_view, front) {
+  string_view sv("words");
+  ASSERT_EQ('w', sv.front());
+}
+
+TEST(string_view, back) {
+  string_view sv("words");
+  ASSERT_EQ('s', sv.back());
+}
+
+TEST(string_view, data) {
+  const char* cstr = "words";
+  string_view sv(cstr);
+  ASSERT_EQ(cstr, sv.data());
+}
+
+TEST(string_view, remove_prefix) {
+  string_view sv("words");
+  sv.remove_prefix(2);
+  assert_string_view_eq("rds", sv);
+}
+
+TEST(string_view, remove_suffix) {
+  string_view sv("words");
+  sv.remove_suffix(2);
+  assert_string_view_eq("wor", sv);
+}
+
+TEST(string_view, swap) {
+  string_view sv1("hello");
+  string_view sv2("bye");
+
+  sv1.swap(sv2);
+
+  assert_string_view_eq("bye", sv1);
+  assert_string_view_eq("hello", sv2);
+}
+
+TEST(string_view, operator_std_string) {
+  string_view sv1("hi");
+  std::string s(sv1);
+
+  ASSERT_EQ(2U, s.size());
+  ASSERT_EQ('h', s[0]);
+  ASSERT_EQ('i', s[1]);
+}
+
+TEST(string_view, copy) {
+  string_view sv("words");
+  char buffer[10] = {0};
+
+  sv.copy(buffer, 10, 2);
+  ASSERT_EQ('r', buffer[0]);
+  ASSERT_EQ('d', buffer[1]);
+  ASSERT_EQ('s', buffer[2]);
+  for (int i = 3; i < 10; ++i) {
+    ASSERT_EQ(0, buffer[i]);
+  }
+}
+
+TEST(string_view, substr) {
+  string_view sv1("abcdefghij");
+  string_view sv2 = sv1.substr(2, 3);
+  assert_string_view_eq("cde", sv2);
+}
+
+TEST(string_view, compare0) {
+  ASSERT_TRUE(string_view("meat").compare(string_view("meet")) < 0);
+  ASSERT_TRUE(string_view("rest").compare(string_view("rate")) > 0);
+  ASSERT_TRUE(string_view("equal").compare(string_view("equal")) == 0);
+  ASSERT_TRUE(string_view("star").compare(string_view("start")) < 0);
+  ASSERT_TRUE(string_view("finished").compare(string_view("fin")) > 0);
+}
+
+TEST(string_view, compare1) {
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("ca")) > 0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("cd")) == 0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("cz")) < 0);
+}
+
+TEST(string_view, compare2) {
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_ca__"), 1, 2) >
+              0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_cd__"), 1, 2) ==
+              0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, string_view("_cz__"), 1, 2) <
+              0);
+}
+
+TEST(string_view, compare3) {
+  ASSERT_TRUE(string_view("abcdef").compare("aaaa") > 0);
+  ASSERT_TRUE(string_view("abcdef").compare("abcdef") == 0);
+  ASSERT_TRUE(string_view("abcdef").compare("zzzz") < 0);
+}
+
+TEST(string_view, compare4) {
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, "ca") > 0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cd") == 0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cz") < 0);
+}
+
+TEST(string_view, compare5) {
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, "ca____", 2) > 0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cd___", 2) == 0);
+  ASSERT_TRUE(string_view("abcdef").compare(2, 2, "cz__", 2) < 0);
+}
+
+TEST(string_view, find0) {
+  ASSERT_EQ(0U, string_view("find fins").find(string_view("fin")));
+  ASSERT_EQ(5U, string_view("find fins").find(string_view("fin"), 1));
+  ASSERT_EQ(npos, string_view("find fins").find(string_view("fin"), 6));
+}
+
+TEST(string_view, find1) {
+  ASSERT_EQ(0U, string_view("012340123").find('0'));
+  ASSERT_EQ(5U, string_view("012340123").find('0', 2));
+  ASSERT_EQ(npos, string_view("012340123").find('0', 6));
+}
+
+TEST(string_view, find2) {
+  ASSERT_EQ(1U, string_view("012340123").find("12345", 0, 2));
+  ASSERT_EQ(6U, string_view("012340123").find("12345", 3, 2));
+  ASSERT_EQ(npos, string_view("012340123").find("12345", 10, 2));
+}
+
+TEST(string_view, find3) {
+  ASSERT_EQ(1U, string_view("012340123").find("12"));
+  ASSERT_EQ(6U, string_view("012340123").find("12", 2));
+  ASSERT_EQ(npos, string_view("012340123").find("12", 10));
+}
+
+TEST(string_view, rfind0) {
+  ASSERT_EQ(5U, string_view("find fins").rfind(string_view("fin")));
+  ASSERT_EQ(0U, string_view("find fins").rfind(string_view("fin"), 4));
+  ASSERT_EQ(npos, string_view("find fins").rfind(string_view("no")));
+  ASSERT_EQ(npos, string_view("foo").rfind(string_view("foobar")));
+}
+
+TEST(string_view, rfind1) {
+  ASSERT_EQ(5U, string_view("012340123").rfind('0'));
+  ASSERT_EQ(0U, string_view("012340123").rfind('0', 2));
+  ASSERT_EQ(npos, string_view("012340123").rfind('9'));
+}
+
+TEST(string_view, rfind2) {
+  ASSERT_EQ(6U, string_view("012340123").rfind("12345", npos, 2));
+  ASSERT_EQ(1U, string_view("012340123").rfind("12345", 4, 2));
+  ASSERT_EQ(npos, string_view("012340123").rfind("12345", npos, 5));
+  ASSERT_EQ(npos, string_view("012").rfind("12345", npos, 5));
+}
+
+TEST(string_view, rfind3) {
+  ASSERT_EQ(6U, string_view("012340123").rfind("12"));
+  ASSERT_EQ(1U, string_view("012340123").rfind("12", 2));
+  ASSERT_EQ(npos, string_view("012340123").rfind("12", 0));
+  ASSERT_EQ(npos, string_view("012").rfind("12345"));
+}
+
+TEST(string_view, find_first_of0) {
+  ASSERT_EQ(0U, string_view("0123abc").find_first_of(string_view("0a")));
+  ASSERT_EQ(4U, string_view("0123abc").find_first_of(string_view("0a"), 1));
+  ASSERT_EQ(npos, string_view("0123abc").find_first_of(string_view("xyz")));
+}
+
+TEST(string_view, find_first_of1) {
+  ASSERT_EQ(1U, string_view("ahellohi").find_first_of('h'));
+  ASSERT_EQ(6U, string_view("ahellohi").find_first_of('h', 2));
+  ASSERT_EQ(npos, string_view("ahellohi").find_first_of('z', 2));
+}
+
+TEST(string_view, find_first_of2) {
+  ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a1b", 0, 2));
+  ASSERT_EQ(4U, string_view("0123abc").find_first_of("0a1b", 1, 2));
+  ASSERT_EQ(npos, string_view("0123abc").find_first_of("0a1b", 5, 2));
+}
+
+TEST(string_view, find_first_of3) {
+  ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a"));
+  ASSERT_EQ(0U, string_view("0123abc").find_first_of("0a", 0));
+  ASSERT_EQ(4U, string_view("0123abc").find_first_of("0a", 1));
+  ASSERT_EQ(npos, string_view("0123abc").find_first_of("0a", 5));
+}
+
+TEST(string_view, find_last_of0) {
+  ASSERT_EQ(4U, string_view("0123abc").find_last_of(string_view("0a")));
+  ASSERT_EQ(0U, string_view("0123abc").find_last_of(string_view("0a"), 1));
+  ASSERT_EQ(npos, string_view("0123abc").find_last_of(string_view("xyz")));
+}
+
+TEST(string_view, find_last_of1) {
+  ASSERT_EQ(6U, string_view("ahellohi").find_last_of('h'));
+  ASSERT_EQ(1U, string_view("ahellohi").find_last_of('h', 2));
+  ASSERT_EQ(npos, string_view("ahellohi").find_last_of('z', 2));
+}
+
+TEST(string_view, find_last_of2) {
+  ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a1b", npos, 2));
+  ASSERT_EQ(0U, string_view("0123abc").find_last_of("0a1b", 1, 2));
+  ASSERT_EQ(npos, string_view("0123abc").find_last_of("a1b", 0, 2));
+  ASSERT_EQ(npos, string_view("0123abc").find_last_of("xyz", npos, 0));
+}
+
+TEST(string_view, find_last_of3) {
+  ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a"));
+  ASSERT_EQ(4U, string_view("0123abc").find_last_of("0a", npos));
+  ASSERT_EQ(0U, string_view("0123abc").find_last_of("0a", 1));
+  ASSERT_EQ(npos, string_view("0123abc").find_last_of("a1", 0));
+}
+
+TEST(string_view, operator_equal) {
+  ASSERT_TRUE(string_view("this") == string_view("this"));
+  ASSERT_FALSE(string_view("this") == string_view("that"));
+}
+
+TEST(string_view, operator_not_equal) {
+  ASSERT_FALSE(string_view("here") != string_view("here"));
+  ASSERT_TRUE(string_view("here") != string_view("there"));
+}
+
+TEST(string_view, operator_less_than) {
+  ASSERT_TRUE(string_view("abc") < string_view("xyz"));
+  ASSERT_FALSE(string_view("later") < string_view("earlier"));
+  ASSERT_FALSE(string_view("one") < string_view("one"));
+}
+
+TEST(string_view, operator_greater_than) {
+  ASSERT_TRUE(string_view("much") > string_view("little"));
+  ASSERT_FALSE(string_view("future") > string_view("past"));
+  ASSERT_FALSE(string_view("now") > string_view("now"));
+}
+
+TEST(string_view, operator_less_than_or_equal) {
+  ASSERT_TRUE(string_view("abc") <= string_view("xyz"));
+  ASSERT_FALSE(string_view("later") <= string_view("earlier"));
+  ASSERT_TRUE(string_view("one") <= string_view("one"));
+}
+
+TEST(string_view, operator_greater_than_or_equal) {
+  ASSERT_TRUE(string_view("much") >= string_view("little"));
+  ASSERT_FALSE(string_view("future") >= string_view("past"));
+  ASSERT_TRUE(string_view("now") >= string_view("now"));
+}
+
+TEST(string_view, hash) {
+  std::hash<string_view> hasher;
+
+  ASSERT_NE(hasher(string_view("hello")), hasher(string_view("goodbye")));
+  ASSERT_EQ(hasher(string_view("same")), hasher(string_view("same")));
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-utf8.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-utf8.cc
new file mode 100644 (file)
index 0000000..8e42062
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * 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 "gtest/gtest.h"
+
+#include "src/utf8.h"
+
+using namespace wabt;
+
+namespace {
+
+void assert_is_valid_utf8(bool expected,
+                          int length,
+                          int cu0 = 0,
+                          int cu1 = 0,
+                          int cu2 = 0,
+                          int cu3 = 0) {
+  assert(length <= 4);
+  char buf[4] = {static_cast<char>(cu0), static_cast<char>(cu1),
+                 static_cast<char>(cu2), static_cast<char>(cu3)};
+  if (expected) {
+    // Make sure it fails if there are continuation bytes past the end of the
+    // string.
+    for (int bad_length = 1; bad_length < length; ++bad_length) {
+      ASSERT_FALSE(IsValidUtf8(buf, bad_length))
+          << cu0 << ", " << cu1 << ", " << cu2 << ", " << cu3;
+    }
+  }
+
+  ASSERT_TRUE(expected == IsValidUtf8(buf, length))
+      << cu0 << ", " << cu1 << ", " << cu2 << ", " << cu3;
+}
+
+bool is_in_range(int x, int low, int high) {
+  return x >= low && x < high;
+}
+
+}  // end anonymous namespace
+
+#define FOR_RANGE(var, low, high) for (int var = low; var < high; var++)
+#define FOR_EACH_BYTE(var) FOR_RANGE(var, 0, 0x100)
+
+TEST(utf8, valid_empty) {
+  assert_is_valid_utf8(true, 0);
+}
+
+TEST(utf8, valid_1_byte) {
+  FOR_RANGE(cu0, 0, 0x80) { assert_is_valid_utf8(true, 1, cu0); }
+}
+
+TEST(utf8, invalid_continuation_bytes) {
+  FOR_RANGE(cu0, 0x80, 0xc0) { assert_is_valid_utf8(false, 1, cu0); }
+}
+
+TEST(utf8, invalid_2_byte) {
+  FOR_RANGE(cu0, 0xc0, 0xc2) { assert_is_valid_utf8(false, 1, cu0); }
+}
+
+TEST(utf8, valid_2_bytes) {
+  FOR_RANGE(cu0, 0xc2, 0xe0) {
+    FOR_EACH_BYTE(cu1) {
+      bool is_valid = is_in_range(cu1, 0x80, 0xc0);
+      assert_is_valid_utf8(is_valid, 2, cu0, cu1);
+    }
+  }
+}
+
+TEST(utf8, valid_3_bytes_e0) {
+  int cu0 = 0xe0;
+  FOR_EACH_BYTE(cu1) {
+    FOR_EACH_BYTE(cu2) {
+      bool is_valid =
+          is_in_range(cu1, 0xa0, 0xc0) && is_in_range(cu2, 0x80, 0xc0);
+      assert_is_valid_utf8(is_valid, 3, cu0, cu1, cu2);
+    }
+  }
+}
+
+TEST(utf8, valid_3_bytes) {
+  FOR_RANGE(cu0, 0xe1, 0xf0) {
+    // Handle 0xed in valid_3_bytes_ed.
+    if (cu0 == 0xed) {
+      continue;
+    }
+
+    FOR_EACH_BYTE(cu1) {
+      FOR_EACH_BYTE(cu2) {
+        bool is_valid =
+            is_in_range(cu1, 0x80, 0xc0) && is_in_range(cu2, 0x80, 0xc0);
+        assert_is_valid_utf8(is_valid, 3, cu0, cu1, cu2);
+      }
+    }
+  }
+}
+
+TEST(utf8, valid_3_bytes_ed) {
+  int cu0 = 0xed;
+  FOR_EACH_BYTE(cu1) {
+    FOR_EACH_BYTE(cu2) {
+      bool is_valid =
+          is_in_range(cu1, 0x80, 0xa0) && is_in_range(cu2, 0x80, 0xc0);
+      assert_is_valid_utf8(is_valid, 3, cu0, cu1, cu2);
+    }
+  }
+}
+
+TEST(utf8, valid_4_bytes_f0) {
+  int cu0 = 0xf0;
+  FOR_EACH_BYTE(cu1) {
+    FOR_EACH_BYTE(cu2) {
+      FOR_EACH_BYTE(cu3) {
+        bool is_valid = is_in_range(cu1, 0x90, 0xc0) &&
+                        is_in_range(cu2, 0x80, 0xc0) &&
+                        is_in_range(cu3, 0x80, 0xc0);
+        assert_is_valid_utf8(is_valid, 4, cu0, cu1, cu2, cu3);
+      }
+    }
+  }
+}
+
+TEST(utf8, valid_4_bytes) {
+  FOR_RANGE(cu0, 0xf1, 0xf4) {
+    FOR_EACH_BYTE(cu1) {
+      FOR_EACH_BYTE(cu2) {
+        FOR_EACH_BYTE(cu3) {
+          bool is_valid = is_in_range(cu1, 0x80, 0xc0) &&
+                          is_in_range(cu2, 0x80, 0xc0) &&
+                          is_in_range(cu3, 0x80, 0xc0);
+          assert_is_valid_utf8(is_valid, 4, cu0, cu1, cu2, cu3);
+        }
+      }
+    }
+  }
+}
+
+TEST(utf8, valid_4_bytes_f4) {
+  int cu0 = 0xf4;
+  FOR_EACH_BYTE(cu1) {
+    FOR_EACH_BYTE(cu2) {
+      FOR_EACH_BYTE(cu3) {
+        bool is_valid = is_in_range(cu1, 0x80, 0x90) &&
+                        is_in_range(cu2, 0x80, 0xc0) &&
+                        is_in_range(cu3, 0x80, 0xc0);
+        assert_is_valid_utf8(is_valid, 4, cu0, cu1, cu2, cu3);
+      }
+    }
+  }
+}
+
+TEST(utf8, invalid_4_bytes) {
+  FOR_RANGE(cu0, 0xf5, 0x100) {
+    assert_is_valid_utf8(false, 4, cu0, 0x80, 0x80, 0x80);
+  }
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-wast-parser.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/test-wast-parser.cc
new file mode 100644 (file)
index 0000000..00a27bf
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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 "gtest/gtest.h"
+
+#include <memory>
+
+#include "src/wast-lexer.h"
+#include "src/wast-parser.h"
+
+using namespace wabt;
+
+namespace {
+
+std::string repeat(std::string s, size_t count) {
+  std::string result;
+  for (size_t i = 0; i < count; ++i) {
+    result += s;
+  }
+  return result;
+}
+
+Errors ParseInvalidModule(std::string text) {
+  auto lexer = WastLexer::CreateBufferLexer("test", text.c_str(), text.size());
+  Errors errors;
+  std::unique_ptr<Module> module;
+  Features features;
+  WastParseOptions options(features);
+  Result result = ParseWatModule(lexer.get(), &module, &errors, &options);
+  EXPECT_EQ(Result::Error, result);
+
+  return errors;
+}
+
+}  // end of anonymous namespace
+
+TEST(WastParser, LongToken) {
+  std::string text;
+  text = "(module (memory ";
+  text += repeat("a", 0x5000);
+  text += "))";
+
+  Errors errors = ParseInvalidModule(text);
+  ASSERT_EQ(1u, errors.size());
+
+  ASSERT_EQ(ErrorLevel::Error, errors[0].error_level);
+  ASSERT_EQ(1, errors[0].loc.line);
+  ASSERT_EQ(17, errors[0].loc.first_column);
+  ASSERT_STREQ(
+      R"(unexpected token "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa...", expected a natural number (e.g. 123).)",
+      errors[0].message.c_str());
+}
+
+TEST(WastParser, LongTokenSpace) {
+  std::string text;
+  text = "notparen";
+  text += repeat(" ", 0x10000);
+  text += "notmodule";
+
+  Errors errors = ParseInvalidModule(text);
+  ASSERT_EQ(2u, errors.size());
+
+  ASSERT_EQ(ErrorLevel::Error, errors[0].error_level);
+  ASSERT_EQ(1, errors[0].loc.line);
+  ASSERT_EQ(1, errors[0].loc.first_column);
+  ASSERT_STREQ(
+      R"(unexpected token "notparen", expected a module field or a module.)",
+      errors[0].message.c_str());
+
+  ASSERT_EQ(1, errors[1].loc.line);
+  ASSERT_EQ(65545, errors[1].loc.first_column);
+  ASSERT_STREQ(R"(unexpected token notmodule, expected EOF.)",
+               errors[1].message.c_str());
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.cc
new file mode 100644 (file)
index 0000000..657d37b
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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/token.h"
+
+namespace wabt {
+
+const char* GetTokenTypeName(TokenType token_type) {
+  static const char* s_names[] = {
+#define WABT_TOKEN(name, string) string,
+#define WABT_TOKEN_FIRST(name, string)
+#define WABT_TOKEN_LAST(name, string)
+#include "token.def"
+#undef WABT_TOKEN
+#undef WABT_TOKEN_FIRST
+#undef WABT_TOKEN_LAST
+  };
+
+  static_assert(
+      WABT_ARRAY_SIZE(s_names) == WABT_ENUM_COUNT(TokenType),
+      "Expected TokenType names list length to match number of TokenTypes.");
+
+  int x = static_cast<int>(token_type);
+  if (x < WABT_ENUM_COUNT(TokenType)) {
+    return s_names[x];
+  }
+
+  return "Invalid";
+}
+
+Token::Token(Location loc, TokenType token_type)
+    : loc(loc), token_type_(token_type) {
+  assert(IsTokenTypeBare(token_type_));
+}
+
+Token::Token(Location loc, TokenType token_type, Type type)
+    : loc(loc), token_type_(token_type) {
+  assert(HasType());
+  Construct(type_, type);
+}
+
+Token::Token(Location loc, TokenType token_type, string_view text)
+    : loc(loc), token_type_(token_type) {
+  assert(HasText());
+  Construct(text_, text);
+}
+
+Token::Token(Location loc, TokenType token_type, Opcode opcode)
+    : loc(loc), token_type_(token_type) {
+  assert(HasOpcode());
+  Construct(opcode_, opcode);
+}
+
+Token::Token(Location loc, TokenType token_type, const Literal& literal)
+    : loc(loc), token_type_(token_type) {
+  assert(HasLiteral());
+  Construct(literal_, literal);
+}
+
+std::string Token::to_string() const {
+  if (IsTokenTypeBare(token_type_)) {
+    return GetTokenTypeName(token_type_);
+  } else if (HasLiteral()) {
+    return literal_.text.to_string();
+  } else if (HasOpcode()) {
+    return opcode_.GetName();
+  } else if (HasText()) {
+    return text_.to_string();
+  } else if (IsTokenTypeRefKind(token_type_)) {
+    return type_.GetRefKindName();
+  } else {
+    assert(HasType());
+    return type_.GetName();
+  }
+}
+
+std::string Token::to_string_clamp(size_t max_length) const {
+  std::string s = to_string();
+  if (s.length() > max_length) {
+    return s.substr(0, max_length - 3) + "...";
+  } else {
+    return s;
+  }
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.def b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.def
new file mode 100644 (file)
index 0000000..e112335
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2018 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_TOKEN
+#error "You must define WABT_TOKEN before including this file."
+#endif
+
+/* Tokens with no additional data (i.e. bare). */
+WABT_TOKEN(Invalid, "Invalid")
+WABT_TOKEN(Array, "array")
+WABT_TOKEN(AssertExhaustion, "assert_exhaustion")
+WABT_TOKEN(AssertInvalid, "assert_invalid")
+WABT_TOKEN(AssertMalformed, "assert_malformed")
+WABT_TOKEN(AssertReturn, "assert_return")
+WABT_TOKEN(AssertTrap, "assert_trap")
+WABT_TOKEN(AssertUnlinkable, "assert_unlinkable")
+WABT_TOKEN(Bin, "bin")
+WABT_TOKEN(Item, "item")
+WABT_TOKEN(Data, "data")
+WABT_TOKEN(Declare, "declare")
+WABT_TOKEN(Delegate, "delegate")
+WABT_TOKEN(Do, "do")
+WABT_TOKEN(Elem, "elem")
+WABT_TOKEN(Eof, "EOF")
+WABT_TOKEN(Event, "event")
+WABT_TOKEN(Export, "export")
+WABT_TOKEN(Field, "field")
+WABT_TOKEN(Get, "get")
+WABT_TOKEN(Global, "global")
+WABT_TOKEN(Import, "import")
+WABT_TOKEN(Invoke, "invoke")
+WABT_TOKEN(Input, "input")
+WABT_TOKEN(Local, "local")
+WABT_TOKEN(Lpar, "(")
+WABT_TOKEN(Memory, "memory")
+WABT_TOKEN(Module, "module")
+WABT_TOKEN(Mut, "mut")
+WABT_TOKEN(NanArithmetic, "nan:arithmetic")
+WABT_TOKEN(NanCanonical, "nan:canonical")
+WABT_TOKEN(Offset, "offset")
+WABT_TOKEN(Output, "output")
+WABT_TOKEN(Param, "param")
+WABT_TOKEN(Quote, "quote")
+WABT_TOKEN(Register, "register")
+WABT_TOKEN(Result, "result")
+WABT_TOKEN(Rpar, ")")
+WABT_TOKEN(Shared, "shared")
+WABT_TOKEN(Start, "start")
+WABT_TOKEN(Struct, "struct")
+WABT_TOKEN(Table, "table")
+WABT_TOKEN(Then, "then")
+WABT_TOKEN(Type, "type")
+WABT_TOKEN(I8X16, "i8x16")
+WABT_TOKEN(I16X8, "i16x8")
+WABT_TOKEN(I32X4, "i32x4")
+WABT_TOKEN(I64X2, "i64x2")
+WABT_TOKEN(F32X4, "f32x4")
+WABT_TOKEN(F64X2, "f64x2")
+WABT_TOKEN_FIRST(Bare, Invalid)
+WABT_TOKEN_LAST(Bare, F64X2)
+
+/* Tokens with Literal data. */
+WABT_TOKEN(Float, "FLOAT")
+WABT_TOKEN(Int, "INT")
+WABT_TOKEN(Nat, "NAT")
+WABT_TOKEN_FIRST(Literal, Float)
+WABT_TOKEN_LAST(Literal, Nat)
+
+/* Tokens with Opcode data. */
+WABT_TOKEN(AtomicFence, "atomic.fence")
+WABT_TOKEN(AtomicLoad, "ATOMIC_LOAD")
+WABT_TOKEN(AtomicNotify, "ATOMIC_NOTIFY")
+WABT_TOKEN(AtomicRmw, "ATOMIC_RMW")
+WABT_TOKEN(AtomicRmwCmpxchg, "ATOMIC_RMW_CMPXCHG")
+WABT_TOKEN(AtomicStore, "ATOMIC_STORE")
+WABT_TOKEN(AtomicWait, "ATOMIC_WAIT")
+WABT_TOKEN(Binary, "BINARY")
+WABT_TOKEN(Block, "block")
+WABT_TOKEN(Br, "br")
+WABT_TOKEN(BrIf, "br_if")
+WABT_TOKEN(BrTable, "br_table")
+WABT_TOKEN(Call, "call")
+WABT_TOKEN(CallIndirect, "call_indirect")
+WABT_TOKEN(Catch, "catch")
+WABT_TOKEN(CatchAll, "catch_all")
+WABT_TOKEN(Compare, "COMPARE")
+WABT_TOKEN(Const, "CONST")
+WABT_TOKEN(Convert, "CONVERT")
+WABT_TOKEN(DataDrop, "data.drop")
+WABT_TOKEN(Drop, "drop")
+WABT_TOKEN(ElemDrop, "elem.drop")
+WABT_TOKEN(Else, "else")
+WABT_TOKEN(End, "end")
+WABT_TOKEN(GlobalGet, "global.get")
+WABT_TOKEN(GlobalSet, "global.set")
+WABT_TOKEN(If, "if")
+WABT_TOKEN(Load, "LOAD")
+WABT_TOKEN(LocalGet, "local.get")
+WABT_TOKEN(LocalSet, "local.set")
+WABT_TOKEN(LocalTee, "local.tee")
+WABT_TOKEN(Loop, "loop")
+WABT_TOKEN(MemoryCopy, "memory.copy")
+WABT_TOKEN(MemoryFill, "memory.fill")
+WABT_TOKEN(MemoryGrow, "memory.grow")
+WABT_TOKEN(MemoryInit, "memory.init")
+WABT_TOKEN(MemorySize, "memory.size")
+WABT_TOKEN(Nop, "nop")
+WABT_TOKEN(RefExtern, "ref.extern")
+WABT_TOKEN(RefFunc, "ref.func")
+WABT_TOKEN(RefIsNull, "ref.is_null")
+WABT_TOKEN(RefNull, "ref.null")
+WABT_TOKEN(Rethrow, "rethrow")
+WABT_TOKEN(ReturnCallIndirect, "return_call_indirect")
+WABT_TOKEN(ReturnCall, "return_call")
+WABT_TOKEN(Return, "return")
+WABT_TOKEN(Select, "select")
+WABT_TOKEN(SimdLaneOp, "SIMDLANEOP")
+WABT_TOKEN(SimdLoadSplat, "SIMDLOADSPLAT")
+WABT_TOKEN(SimdShuffleOp, "i8x16.shuffle")
+WABT_TOKEN(Store, "STORE")
+WABT_TOKEN(TableCopy, "table.copy")
+WABT_TOKEN(TableFill, "table.full")
+WABT_TOKEN(TableGet, "table.get")
+WABT_TOKEN(TableGrow, "table.grow")
+WABT_TOKEN(TableInit, "table.init")
+WABT_TOKEN(TableSet, "table.set")
+WABT_TOKEN(TableSize, "table.size")
+WABT_TOKEN(Ternary, "TERNARY")
+WABT_TOKEN(Throw, "throw")
+WABT_TOKEN(Try, "try")
+WABT_TOKEN(Unary, "UNARY")
+WABT_TOKEN(Unreachable, "unreachable")
+WABT_TOKEN(Unwind, "unwind")
+WABT_TOKEN_FIRST(Opcode, AtomicFence)
+WABT_TOKEN_LAST(Opcode, Unwind)
+
+/* Tokens with string data. */
+WABT_TOKEN(AlignEqNat, "align=")
+WABT_TOKEN(LparAnn, "Annotation")
+WABT_TOKEN(OffsetEqNat, "offset=")
+WABT_TOKEN(Reserved, "Reserved")
+WABT_TOKEN(Text, "TEXT")
+WABT_TOKEN(Var, "VAR")
+WABT_TOKEN_FIRST(String, AlignEqNat)
+WABT_TOKEN_LAST(String, Var)
+
+/* Tokens with Type data. */
+WABT_TOKEN(ValueType, "VALUETYPE")
+WABT_TOKEN_FIRST(Type, ValueType)
+WABT_TOKEN_LAST(Type, ValueType)
+
+/* Tokens with Type data, but are reference kinds. */
+WABT_TOKEN(Func, "func")
+WABT_TOKEN(Extern, "extern")
+WABT_TOKEN(Exn, "exn")
+WABT_TOKEN_FIRST(RefKind, Func)
+WABT_TOKEN_LAST(RefKind, Exn)
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/token.h
new file mode 100644 (file)
index 0000000..719e1ae
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * 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_TOKEN_H_
+#define WABT_TOKEN_H_
+
+#include "src/literal.h"
+#include "src/opcode.h"
+#include "src/string-view.h"
+
+namespace wabt {
+
+struct Literal {
+  Literal() = default;
+  Literal(LiteralType type, string_view text) : type(type), text(text) {}
+
+  LiteralType type;
+  string_view text;
+};
+
+enum class TokenType {
+#define WABT_TOKEN(name, string) name,
+#define WABT_TOKEN_FIRST(group, first) First_##group = first,
+#define WABT_TOKEN_LAST(group, last) Last_##group = last,
+#include "token.def"
+#undef WABT_TOKEN
+#undef WABT_TOKEN_FIRST
+#undef WABT_TOKEN_LAST
+
+  First = First_Bare,
+  Last = Last_RefKind,
+};
+
+const char* GetTokenTypeName(TokenType);
+
+inline bool IsTokenTypeBare(TokenType token_type) {
+  return token_type >= TokenType::First_Bare &&
+         token_type <= TokenType::Last_Bare;
+}
+
+inline bool IsTokenTypeString(TokenType token_type) {
+  return token_type >= TokenType::First_String &&
+         token_type <= TokenType::Last_String;
+}
+
+inline bool IsTokenTypeType(TokenType token_type) {
+  return token_type == TokenType::ValueType;
+}
+
+inline bool IsTokenTypeOpcode(TokenType token_type) {
+  return token_type >= TokenType::First_Opcode &&
+         token_type <= TokenType::Last_Opcode;
+}
+
+inline bool IsTokenTypeLiteral(TokenType token_type) {
+  return token_type >= TokenType::First_Literal &&
+         token_type <= TokenType::Last_Literal;
+}
+
+inline bool IsTokenTypeRefKind(TokenType token_type) {
+  return token_type >= TokenType::First_RefKind &&
+         token_type <= TokenType::Last_RefKind;
+}
+
+struct Token {
+  Token() : token_type_(TokenType::Invalid) {}
+  Token(Location, TokenType);
+  Token(Location, TokenType, Type);
+  Token(Location, TokenType, string_view);
+  Token(Location, TokenType, Opcode);
+  Token(Location, TokenType, const Literal&);
+
+  Location loc;
+
+  TokenType token_type() const { return token_type_; }
+
+  bool HasText() const { return IsTokenTypeString(token_type_); }
+  bool HasType() const {
+    return IsTokenTypeType(token_type_) || IsTokenTypeRefKind(token_type_);
+  }
+  bool HasOpcode() const { return IsTokenTypeOpcode(token_type_); }
+  bool HasLiteral() const { return IsTokenTypeLiteral(token_type_); }
+
+  string_view text() const {
+    assert(HasText());
+    return text_;
+  }
+
+  Type type() const {
+    assert(HasType());
+    return type_;
+  }
+
+  Opcode opcode() const {
+    assert(HasOpcode());
+    return opcode_;
+  }
+
+  const Literal& literal() const {
+    assert(HasLiteral());
+    return literal_;
+  }
+
+  std::string to_string() const;
+  std::string to_string_clamp(size_t max_length) const;
+
+ private:
+  TokenType token_type_;
+
+  union {
+    string_view text_;
+    Type type_;
+    Opcode opcode_;
+    Literal literal_;
+  };
+};
+
+}  // namespace wabt
+
+#endif  // WABT_TOKEN_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/spectest-interp.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/spectest-interp.cc
new file mode 100644 (file)
index 0000000..c27e7a9
--- /dev/null
@@ -0,0 +1,1852 @@
+/*
+ * 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 <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "src/binary-reader.h"
+#include "src/cast.h"
+#include "src/common.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/interp/binary-reader-interp.h"
+#include "src/interp/interp-util.h"
+#include "src/interp/interp.h"
+#include "src/literal.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-lexer.h"
+#include "src/wast-parser.h"
+
+using namespace wabt;
+using namespace wabt::interp;
+
+static int s_verbose;
+static const char* s_infile;
+static Thread::Options s_thread_options;
+static Stream* s_trace_stream;
+static Features s_features;
+
+static std::unique_ptr<FileStream> s_log_stream;
+static std::unique_ptr<FileStream> s_stdout_stream;
+
+enum class RunVerbosity {
+  Quiet = 0,
+  Verbose = 1,
+};
+
+static const char s_description[] =
+    R"(  read a Spectest JSON file, and run its tests in the interpreter.
+
+examples:
+  # parse test.json and run the spec tests
+  $ spectest-interp test.json
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("spectest-interp", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+  });
+  s_features.AddOptions(&parser);
+  parser.AddOption('V', "value-stack-size", "SIZE",
+                   "Size in elements of the value stack",
+                   [](const std::string& argument) {
+                     // TODO(binji): validate.
+                     s_thread_options.value_stack_size = atoi(argument.c_str());
+                   });
+  parser.AddOption('C', "call-stack-size", "SIZE",
+                   "Size in elements of the call stack",
+                   [](const std::string& argument) {
+                     // TODO(binji): validate.
+                     s_thread_options.call_stack_size = atoi(argument.c_str());
+                   });
+  parser.AddOption('t', "trace", "Trace execution",
+                   []() { s_trace_stream = s_stdout_stream.get(); });
+
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) { s_infile = argument; });
+  parser.Parse(argc, argv);
+}
+
+namespace spectest {
+
+class Command;
+typedef std::unique_ptr<Command> CommandPtr;
+typedef std::vector<CommandPtr> CommandPtrVector;
+
+class Script {
+ public:
+  std::string filename;
+  CommandPtrVector commands;
+};
+
+class Command {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(Command);
+  Command() = delete;
+  virtual ~Command() = default;
+
+  CommandType type;
+  uint32_t line = 0;
+
+ protected:
+  explicit Command(CommandType type) : type(type) {}
+};
+
+template <CommandType TypeEnum>
+class CommandMixin : public Command {
+ public:
+  static bool classof(const Command* cmd) { return cmd->type == TypeEnum; }
+  CommandMixin() : Command(TypeEnum) {}
+};
+
+enum class ModuleType {
+  Text,
+  Binary,
+};
+
+class ModuleCommand : public CommandMixin<CommandType::Module> {
+ public:
+  ModuleType module = ModuleType::Binary;
+  std::string filename;
+  std::string name;
+};
+
+class Action {
+ public:
+  ActionType type = ActionType::Invoke;
+  std::string module_name;
+  std::string field_name;
+  ValueTypes types;
+  Values args;
+};
+
+template <CommandType TypeEnum>
+class ActionCommandBase : public CommandMixin<TypeEnum> {
+ public:
+  Action action;
+};
+
+typedef ActionCommandBase<CommandType::Action> ActionCommand;
+
+class RegisterCommand : public CommandMixin<CommandType::Register> {
+ public:
+  std::string as;
+  std::string name;
+};
+
+struct ExpectedValue {
+  TypedValue value;
+  Type lane_type;             // Only valid if value.type == Type::V128.
+  // Up to 4 NaN values used, depending on |value.type| and |lane_type|:
+  //   | type  | lane_type | valid                 |
+  //   | f32   |           | nan[0]                |
+  //   | f64   |           | nan[0]                |
+  //   | v128  | f32       | nan[0] through nan[3] |
+  //   | v128  | f64       | nan[0],nan[1]         |
+  //   | *     | *         | none valid            |
+  ExpectedNan nan[4];
+};
+
+int LaneCountFromType(Type type) {
+  switch (type) {
+    case Type::I8: return 16;
+    case Type::I16: return 8;
+    case Type::I32: return 4;
+    case Type::I64: return 2;
+    case Type::F32: return 4;
+    case Type::F64: return 2;
+    default: assert(false); return 0;
+  }
+}
+
+ExpectedValue GetLane(const ExpectedValue& ev, int lane) {
+  int lane_count = LaneCountFromType(ev.lane_type);
+  assert(ev.value.type == Type::V128);
+  assert(lane < lane_count);
+
+  ExpectedValue result;
+  result.value.type = ev.lane_type;
+
+  v128 vec = ev.value.value.Get<v128>();
+
+  for (int lane = 0; lane < lane_count; ++lane) {
+    switch (ev.lane_type) {
+      case Type::I8:
+        result.nan[0] = ExpectedNan::None;
+        result.value.value.Set<u32>(vec.u8(lane));
+        break;
+
+      case Type::I16:
+        result.nan[0] = ExpectedNan::None;
+        result.value.value.Set<u32>(vec.u16(lane));
+        break;
+
+      case Type::I32:
+        result.nan[0] = ExpectedNan::None;
+        result.value.value.Set<u32>(vec.u32(lane));
+        break;
+
+      case Type::I64:
+        result.nan[0] = ExpectedNan::None;
+        result.value.value.Set<u64>(vec.u64(lane));
+        break;
+
+      case Type::F32:
+        result.nan[0] = ev.nan[lane];
+        result.value.value.Set<f32>(Bitcast<f32>(vec.f32_bits(lane)));
+        break;
+
+      case Type::F64:
+        result.nan[0] = ev.nan[lane];
+        result.value.value.Set<f64>(Bitcast<f64>(vec.f64_bits(lane)));
+        break;
+
+      default:
+        WABT_UNREACHABLE;
+    }
+  }
+  return result;
+}
+
+TypedValue GetLane(const TypedValue& tv, Type lane_type, int lane) {
+  int lane_count = LaneCountFromType(lane_type);
+  assert(tv.type == Type::V128);
+  assert(lane < lane_count);
+
+  TypedValue result;
+  result.type = lane_type;
+
+  v128 vec = tv.value.Get<v128>();
+
+  for (int lane = 0; lane < lane_count; ++lane) {
+    switch (lane_type) {
+      case Type::I8:
+        result.value.Set<u32>(vec.u8(lane));
+        break;
+
+      case Type::I16:
+        result.value.Set<u32>(vec.u16(lane));
+        break;
+
+      case Type::I32:
+        result.value.Set<u32>(vec.u32(lane));
+        break;
+
+      case Type::I64:
+        result.value.Set<u64>(vec.u64(lane));
+        break;
+
+      case Type::F32:
+        result.value.Set<f32>(Bitcast<f32>(vec.f32_bits(lane)));
+        break;
+
+      case Type::F64:
+        result.value.Set<f64>(Bitcast<f64>(vec.f64_bits(lane)));
+        break;
+
+      default:
+        WABT_UNREACHABLE;
+    }
+  }
+  return result;
+}
+
+class AssertReturnCommand : public CommandMixin<CommandType::AssertReturn> {
+ public:
+  Action action;
+  std::vector<ExpectedValue> expected;
+};
+
+template <CommandType TypeEnum>
+class AssertTrapCommandBase : public CommandMixin<TypeEnum> {
+ public:
+  Action action;
+  std::string text;
+};
+
+typedef AssertTrapCommandBase<CommandType::AssertTrap> AssertTrapCommand;
+typedef AssertTrapCommandBase<CommandType::AssertExhaustion>
+    AssertExhaustionCommand;
+
+template <CommandType TypeEnum>
+class AssertModuleCommand : public CommandMixin<TypeEnum> {
+ public:
+  ModuleType type = ModuleType::Binary;
+  std::string filename;
+  std::string text;
+};
+
+typedef AssertModuleCommand<CommandType::AssertMalformed>
+    AssertMalformedCommand;
+typedef AssertModuleCommand<CommandType::AssertInvalid> AssertInvalidCommand;
+typedef AssertModuleCommand<CommandType::AssertUnlinkable>
+    AssertUnlinkableCommand;
+typedef AssertModuleCommand<CommandType::AssertUninstantiable>
+    AssertUninstantiableCommand;
+
+// An extremely simple JSON parser that only knows how to parse the expected
+// format from wat2wasm.
+class JSONParser {
+ public:
+  JSONParser() {}
+
+  wabt::Result ReadFile(string_view spec_json_filename);
+  wabt::Result ParseScript(Script* out_script);
+
+ private:
+  void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* format, ...);
+
+  // Whether to allow parsing of expectation-only forms (e.g. `nan:canonical`,
+  // `nan:arithmetic`, etc.)
+  enum class AllowExpected { No, Yes };
+
+  void PutbackChar();
+  int ReadChar();
+  void SkipWhitespace();
+  bool Match(const char* s);
+  wabt::Result Expect(const char* s);
+  wabt::Result ExpectKey(const char* key);
+  wabt::Result ParseUint32(uint32_t* out_int);
+  wabt::Result ParseString(std::string* out_string);
+  wabt::Result ParseKeyStringValue(const char* key, std::string* out_string);
+  wabt::Result ParseOptNameStringValue(std::string* out_string);
+  wabt::Result ParseLine(uint32_t* out_line_number);
+  wabt::Result ParseType(Type* out_type);
+  wabt::Result ParseTypeObject(Type* out_type);
+  wabt::Result ParseTypeVector(TypeVector* out_types);
+  wabt::Result ParseConst(TypedValue* out_value);
+  wabt::Result ParseI32Value(uint32_t* out_value, string_view value_str);
+  wabt::Result ParseI64Value(uint64_t* out_value, string_view value_str);
+  wabt::Result ParseF32Value(uint32_t* out_value,
+                             ExpectedNan* out_nan,
+                             string_view value_str,
+                             AllowExpected);
+  wabt::Result ParseF64Value(uint64_t* out_value,
+                             ExpectedNan* out_nan,
+                             string_view value_str,
+                             AllowExpected);
+  wabt::Result ParseLaneConstValue(Type lane_type,
+                                   int lane,
+                                   ExpectedValue* out_value,
+                                   string_view value_str,
+                                   AllowExpected);
+  wabt::Result ParseConstValue(Type type,
+                               Value* out_value,
+                               ExpectedNan* out_nan,
+                               string_view value_str,
+                               AllowExpected);
+  wabt::Result ParseConstVector(ValueTypes* out_types, Values* out_values);
+  wabt::Result ParseExpectedValue(ExpectedValue* out_value, AllowExpected);
+  wabt::Result ParseExpectedValues(std::vector<ExpectedValue>* out_values);
+  wabt::Result ParseAction(Action* out_action);
+  wabt::Result ParseActionResult();
+  wabt::Result ParseModuleType(ModuleType* out_type);
+
+  std::string CreateModulePath(string_view filename);
+  wabt::Result ParseFilename(std::string* out_filename);
+  wabt::Result ParseCommand(CommandPtr* out_command);
+
+  // Parsing info.
+  std::vector<uint8_t> json_data_;
+  size_t json_offset_ = 0;
+  Location loc_;
+  Location prev_loc_;
+  bool has_prev_loc_ = false;
+};
+
+#define EXPECT(x) CHECK_RESULT(Expect(x))
+#define EXPECT_KEY(x) CHECK_RESULT(ExpectKey(x))
+#define PARSE_KEY_STRING_VALUE(key, value) \
+  CHECK_RESULT(ParseKeyStringValue(key, value))
+
+wabt::Result JSONParser::ReadFile(string_view spec_json_filename) {
+  loc_.filename = spec_json_filename;
+  loc_.line = 1;
+  loc_.first_column = 1;
+
+  return wabt::ReadFile(spec_json_filename, &json_data_);
+}
+
+void JSONParser::PrintError(const char* format, ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  fprintf(stderr, "%s:%d:%d: %s\n", loc_.filename.to_string().c_str(),
+          loc_.line, loc_.first_column, buffer);
+}
+
+void JSONParser::PutbackChar() {
+  assert(has_prev_loc_);
+  json_offset_--;
+  loc_ = prev_loc_;
+  has_prev_loc_ = false;
+}
+
+int JSONParser::ReadChar() {
+  if (json_offset_ >= json_data_.size()) {
+    return -1;
+  }
+  prev_loc_ = loc_;
+  char c = json_data_[json_offset_++];
+  if (c == '\n') {
+    loc_.line++;
+    loc_.first_column = 1;
+  } else {
+    loc_.first_column++;
+  }
+  has_prev_loc_ = true;
+  return c;
+}
+
+void JSONParser::SkipWhitespace() {
+  while (1) {
+    switch (ReadChar()) {
+      case -1:
+        return;
+
+      case ' ':
+      case '\t':
+      case '\n':
+      case '\r':
+        break;
+
+      default:
+        PutbackChar();
+        return;
+    }
+  }
+}
+
+bool JSONParser::Match(const char* s) {
+  SkipWhitespace();
+  Location start_loc = loc_;
+  size_t start_offset = json_offset_;
+  while (*s && *s == ReadChar())
+    s++;
+
+  if (*s == 0) {
+    return true;
+  } else {
+    json_offset_ = start_offset;
+    loc_ = start_loc;
+    return false;
+  }
+}
+
+wabt::Result JSONParser::Expect(const char* s) {
+  if (Match(s)) {
+    return wabt::Result::Ok;
+  } else {
+    PrintError("expected %s", s);
+    return wabt::Result::Error;
+  }
+}
+
+wabt::Result JSONParser::ExpectKey(const char* key) {
+  size_t keylen = strlen(key);
+  size_t quoted_len = keylen + 2 + 1;
+  char* quoted = static_cast<char*>(alloca(quoted_len));
+  snprintf(quoted, quoted_len, "\"%s\"", key);
+  EXPECT(quoted);
+  EXPECT(":");
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseUint32(uint32_t* out_int) {
+  uint32_t result = 0;
+  SkipWhitespace();
+  while (1) {
+    int c = ReadChar();
+    if (c >= '0' && c <= '9') {
+      uint32_t last_result = result;
+      result = result * 10 + static_cast<uint32_t>(c - '0');
+      if (result < last_result) {
+        PrintError("uint32 overflow");
+        return wabt::Result::Error;
+      }
+    } else {
+      PutbackChar();
+      break;
+    }
+  }
+  *out_int = result;
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseString(std::string* out_string) {
+  out_string->clear();
+
+  SkipWhitespace();
+  if (ReadChar() != '"') {
+    PrintError("expected string");
+    return wabt::Result::Error;
+  }
+
+  while (1) {
+    int c = ReadChar();
+    if (c == '"') {
+      break;
+    } else if (c == '\\') {
+      /* The only escape supported is \uxxxx. */
+      c = ReadChar();
+      if (c != 'u') {
+        PrintError("expected escape: \\uxxxx");
+        return wabt::Result::Error;
+      }
+      uint16_t code = 0;
+      for (int i = 0; i < 4; ++i) {
+        c = ReadChar();
+        int cval;
+        if (c >= '0' && c <= '9') {
+          cval = c - '0';
+        } else if (c >= 'a' && c <= 'f') {
+          cval = c - 'a' + 10;
+        } else if (c >= 'A' && c <= 'F') {
+          cval = c - 'A' + 10;
+        } else {
+          PrintError("expected hex char");
+          return wabt::Result::Error;
+        }
+        code = (code << 4) + cval;
+      }
+
+      if (code < 256) {
+        *out_string += code;
+      } else {
+        PrintError("only escape codes < 256 allowed, got %u\n", code);
+      }
+    } else {
+      *out_string += c;
+    }
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseKeyStringValue(const char* key,
+                                             std::string* out_string) {
+  out_string->clear();
+  EXPECT_KEY(key);
+  return ParseString(out_string);
+}
+
+wabt::Result JSONParser::ParseOptNameStringValue(std::string* out_string) {
+  out_string->clear();
+  if (Match("\"name\"")) {
+    EXPECT(":");
+    CHECK_RESULT(ParseString(out_string));
+    EXPECT(",");
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseLine(uint32_t* out_line_number) {
+  EXPECT_KEY("line");
+  CHECK_RESULT(ParseUint32(out_line_number));
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseType(Type* out_type) {
+  std::string type_str;
+  CHECK_RESULT(ParseString(&type_str));
+
+  if (type_str == "i32") {
+    *out_type = Type::I32;
+  } else if (type_str == "f32") {
+    *out_type = Type::F32;
+  } else if (type_str == "i64") {
+    *out_type = Type::I64;
+  } else if (type_str == "f64") {
+    *out_type = Type::F64;
+  } else if (type_str == "v128") {
+    *out_type = Type::V128;
+  } else if (type_str == "i8") {
+    *out_type = Type::I8;
+  } else if (type_str == "i16") {
+    *out_type = Type::I16;
+  } else if (type_str == "funcref") {
+    *out_type = Type::FuncRef;
+  } else if (type_str == "externref") {
+    *out_type = Type::ExternRef;
+  } else {
+    PrintError("unknown type: \"%s\"", type_str.c_str());
+    return wabt::Result::Error;
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseTypeObject(Type* out_type) {
+  EXPECT("{");
+  EXPECT_KEY("type");
+  CHECK_RESULT(ParseType(out_type));
+  EXPECT("}");
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseTypeVector(TypeVector* out_types) {
+  out_types->clear();
+  EXPECT("[");
+  bool first = true;
+  while (!Match("]")) {
+    if (!first) {
+      EXPECT(",");
+    }
+    Type type;
+    CHECK_RESULT(ParseTypeObject(&type));
+    first = false;
+    out_types->push_back(type);
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseConst(TypedValue* out_value) {
+  ExpectedValue expected;
+  CHECK_RESULT(ParseExpectedValue(&expected, AllowExpected::No));
+  *out_value = expected.value;
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseI32Value(uint32_t* out_value,
+                                       string_view value_str) {
+  if (Failed(ParseInt32(value_str.begin(), value_str.end(), out_value,
+                        ParseIntType::UnsignedOnly))) {
+    PrintError("invalid i32 literal");
+    return wabt::Result::Error;
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseI64Value(uint64_t* out_value,
+                                       string_view value_str) {
+  if (Failed(ParseInt64(value_str.begin(), value_str.end(), out_value,
+                        ParseIntType::UnsignedOnly))) {
+    PrintError("invalid i64 literal");
+    return wabt::Result::Error;
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseF32Value(uint32_t* out_value,
+                                       ExpectedNan* out_nan,
+                                       string_view value_str,
+                                       AllowExpected allow_expected) {
+  if (allow_expected == AllowExpected::Yes) {
+    *out_value = 0;
+    if (value_str == "nan:canonical") {
+      *out_nan = ExpectedNan::Canonical;
+      return wabt::Result::Ok;
+    } else if (value_str == "nan:arithmetic") {
+      *out_nan = ExpectedNan::Arithmetic;
+      return wabt::Result::Ok;
+    }
+  }
+
+  *out_nan = ExpectedNan::None;
+  if (Failed(ParseInt32(value_str.begin(), value_str.end(), out_value,
+                        ParseIntType::UnsignedOnly))) {
+    PrintError("invalid f32 literal");
+    return wabt::Result::Error;
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseF64Value(uint64_t* out_value,
+                                       ExpectedNan* out_nan,
+                                       string_view value_str,
+                                       AllowExpected allow_expected) {
+  if (allow_expected == AllowExpected::Yes) {
+    *out_value = 0;
+    if (value_str == "nan:canonical") {
+      *out_nan = ExpectedNan::Canonical;
+      return wabt::Result::Ok;
+    } else if (value_str == "nan:arithmetic") {
+      *out_nan = ExpectedNan::Arithmetic;
+      return wabt::Result::Ok;
+    }
+  }
+
+  *out_nan = ExpectedNan::None;
+  if (Failed(ParseInt64(value_str.begin(), value_str.end(), out_value,
+                        ParseIntType::UnsignedOnly))) {
+    PrintError("invalid f64 literal");
+    return wabt::Result::Error;
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseLaneConstValue(Type lane_type,
+                                             int lane,
+                                             ExpectedValue* out_value,
+                                             string_view value_str,
+                                             AllowExpected allow_expected) {
+  v128 v = out_value->value.value.Get<v128>();
+
+  switch (lane_type) {
+    case Type::I8: {
+      uint32_t value;
+      CHECK_RESULT(ParseI32Value(&value, value_str));
+      v.set_u8(lane, value);
+      break;
+    }
+
+    case Type::I16: {
+      uint32_t value;
+      CHECK_RESULT(ParseI32Value(&value, value_str));
+      v.set_u16(lane, value);
+      break;
+    }
+
+    case Type::I32: {
+      uint32_t value;
+      CHECK_RESULT(ParseI32Value(&value, value_str));
+      v.set_u32(lane, value);
+      break;
+    }
+
+    case Type::I64: {
+      uint64_t value;
+      CHECK_RESULT(ParseI64Value(&value, value_str));
+      v.set_u64(lane, value);
+      break;
+    }
+
+    case Type::F32: {
+      ExpectedNan nan;
+      uint32_t value_bits;
+      CHECK_RESULT(ParseF32Value(&value_bits, &nan, value_str, allow_expected));
+      v.set_f32_bits(lane, value_bits);
+      assert(lane < 4);
+      out_value->nan[lane] = nan;
+      break;
+    }
+
+    case Type::F64: {
+      ExpectedNan nan;
+      uint64_t value_bits;
+      CHECK_RESULT(ParseF64Value(&value_bits, &nan, value_str, allow_expected));
+      v.set_f64_bits(lane, value_bits);
+      assert(lane < 2);
+      out_value->nan[lane] = nan;
+      break;
+    }
+
+    default:
+      PrintError("unknown concrete type: \"%s\"", lane_type.GetName());
+      return wabt::Result::Error;
+  }
+
+  out_value->value.value.Set<v128>(v);
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseConstValue(Type type,
+                                         Value* out_value,
+                                         ExpectedNan* out_nan,
+                                         string_view value_str,
+                                         AllowExpected allow_expected) {
+  *out_nan = ExpectedNan::None;
+
+  switch (type) {
+    case Type::I32: {
+      uint32_t value;
+      CHECK_RESULT(ParseI32Value(&value, value_str));
+      out_value->Set(value);
+      break;
+    }
+
+    case Type::F32: {
+      uint32_t value_bits;
+      CHECK_RESULT(
+          ParseF32Value(&value_bits, out_nan, value_str, allow_expected));
+      out_value->Set(Bitcast<f32>(value_bits));
+      break;
+    }
+
+    case Type::I64: {
+      uint64_t value;
+      CHECK_RESULT(ParseI64Value(&value, value_str));
+      out_value->Set(value);
+      break;
+    }
+
+    case Type::F64: {
+      uint64_t value_bits;
+      CHECK_RESULT(
+          ParseF64Value(&value_bits, out_nan, value_str, allow_expected));
+      out_value->Set(Bitcast<f64>(value_bits));
+      break;
+    }
+
+    case Type::V128:
+      assert(false);  // Should use ParseLaneConstValue instead.
+      break;
+
+    case Type::FuncRef:
+      if (value_str == "null") {
+        out_value->Set(Ref::Null);
+      } else {
+        assert(allow_expected == AllowExpected::Yes);
+        out_value->Set(Ref{1});
+      }
+      break;
+
+    case Type::ExternRef:
+      if (value_str == "null") {
+        out_value->Set(Ref::Null);
+      } else {
+        uint32_t value;
+        CHECK_RESULT(ParseI32Value(&value, value_str));
+        // TODO: hack, just whatever ref is at this index; but skip null (which
+        // is always 0).
+        out_value->Set(Ref{value + 1});
+      }
+      break;
+
+    default:
+      PrintError("unknown concrete type: \"%s\"", type.GetName());
+      return wabt::Result::Error;
+  }
+
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseExpectedValue(ExpectedValue* out_value,
+                                            AllowExpected allow_expected) {
+  Type type;
+  std::string value_str;
+  EXPECT("{");
+  EXPECT_KEY("type");
+  CHECK_RESULT(ParseType(&type));
+  EXPECT(",");
+  if (type == Type::V128) {
+    Type lane_type;
+    EXPECT_KEY("lane_type");
+    CHECK_RESULT(ParseType(&lane_type));
+    EXPECT(",");
+    EXPECT_KEY("value");
+    EXPECT("[");
+
+    int lane_count = LaneCountFromType(lane_type);
+    for (int lane = 0; lane < lane_count; ++lane) {
+      CHECK_RESULT(ParseString(&value_str));
+      CHECK_RESULT(ParseLaneConstValue(lane_type, lane, out_value, value_str,
+                                       allow_expected));
+      if (lane < lane_count - 1) {
+        EXPECT(",");
+      }
+    }
+    EXPECT("]");
+    out_value->value.type = type;
+    out_value->lane_type = lane_type;
+  } else {
+    PARSE_KEY_STRING_VALUE("value", &value_str);
+    CHECK_RESULT(ParseConstValue(type, &out_value->value.value,
+                                 &out_value->nan[0], value_str,
+                                 allow_expected));
+    out_value->value.type = type;
+  }
+  EXPECT("}");
+
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseExpectedValues(
+    std::vector<ExpectedValue>* out_values) {
+  out_values->clear();
+  EXPECT("[");
+  bool first = true;
+  while (!Match("]")) {
+    if (!first) {
+      EXPECT(",");
+    }
+    ExpectedValue value;
+    CHECK_RESULT(ParseExpectedValue(&value, AllowExpected::Yes));
+    out_values->push_back(value);
+    first = false;
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseConstVector(ValueTypes* out_types, Values* out_values) {
+  out_values->clear();
+  EXPECT("[");
+  bool first = true;
+  while (!Match("]")) {
+    if (!first) {
+      EXPECT(",");
+    }
+    TypedValue tv;
+    CHECK_RESULT(ParseConst(&tv));
+    out_types->push_back(tv.type);
+    out_values->push_back(tv.value);
+    first = false;
+  }
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseAction(Action* out_action) {
+  EXPECT_KEY("action");
+  EXPECT("{");
+  EXPECT_KEY("type");
+  if (Match("\"invoke\"")) {
+    out_action->type = ActionType::Invoke;
+  } else {
+    EXPECT("\"get\"");
+    out_action->type = ActionType::Get;
+  }
+  EXPECT(",");
+  if (Match("\"module\"")) {
+    EXPECT(":");
+    CHECK_RESULT(ParseString(&out_action->module_name));
+    EXPECT(",");
+  }
+  PARSE_KEY_STRING_VALUE("field", &out_action->field_name);
+  if (out_action->type == ActionType::Invoke) {
+    EXPECT(",");
+    EXPECT_KEY("args");
+    CHECK_RESULT(ParseConstVector(&out_action->types, &out_action->args));
+  }
+  EXPECT("}");
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseActionResult() {
+  // Not needed for wabt-interp, but useful for other parsers.
+  EXPECT_KEY("expected");
+  TypeVector expected;
+  CHECK_RESULT(ParseTypeVector(&expected));
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseModuleType(ModuleType* out_type) {
+  std::string module_type_str;
+
+  PARSE_KEY_STRING_VALUE("module_type", &module_type_str);
+  if (module_type_str == "text") {
+    *out_type = ModuleType::Text;
+    return wabt::Result::Ok;
+  } else if (module_type_str == "binary") {
+    *out_type = ModuleType::Binary;
+    return wabt::Result::Ok;
+  } else {
+    PrintError("unknown module type: \"%s\"", module_type_str.c_str());
+    return wabt::Result::Error;
+  }
+}
+
+static string_view GetDirname(string_view path) {
+  // Strip everything after and including the last slash (or backslash), e.g.:
+  //
+  // s = "foo/bar/baz", => "foo/bar"
+  // s = "/usr/local/include/stdio.h", => "/usr/local/include"
+  // s = "foo.bar", => ""
+  // s = "some\windows\directory", => "some\windows"
+  size_t last_slash = path.find_last_of('/');
+  size_t last_backslash = path.find_last_of('\\');
+  if (last_slash == string_view::npos) {
+    last_slash = 0;
+  }
+  if (last_backslash == string_view::npos) {
+    last_backslash = 0;
+  }
+
+  return path.substr(0, std::max(last_slash, last_backslash));
+}
+
+std::string JSONParser::CreateModulePath(string_view filename) {
+  string_view spec_json_filename = loc_.filename;
+  string_view dirname = GetDirname(spec_json_filename);
+  std::string path;
+
+  if (dirname.size() == 0) {
+    path = filename.to_string();
+  } else {
+    path = dirname.to_string();
+    path += '/';
+    path += filename.to_string();
+  }
+
+  ConvertBackslashToSlash(&path);
+  return path;
+}
+
+wabt::Result JSONParser::ParseFilename(std::string* out_filename) {
+  PARSE_KEY_STRING_VALUE("filename", out_filename);
+  *out_filename = CreateModulePath(*out_filename);
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseCommand(CommandPtr* out_command) {
+  EXPECT("{");
+  EXPECT_KEY("type");
+  if (Match("\"module\"")) {
+    auto command = MakeUnique<ModuleCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseOptNameStringValue(&command->name));
+    CHECK_RESULT(ParseFilename(&command->filename));
+    *out_command = std::move(command);
+  } else if (Match("\"action\"")) {
+    auto command = MakeUnique<ActionCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseAction(&command->action));
+    EXPECT(",");
+    CHECK_RESULT(ParseActionResult());
+    *out_command = std::move(command);
+  } else if (Match("\"register\"")) {
+    auto command = MakeUnique<RegisterCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseOptNameStringValue(&command->name));
+    PARSE_KEY_STRING_VALUE("as", &command->as);
+    *out_command = std::move(command);
+  } else if (Match("\"assert_malformed\"")) {
+    auto command = MakeUnique<AssertMalformedCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseFilename(&command->filename));
+    EXPECT(",");
+    PARSE_KEY_STRING_VALUE("text", &command->text);
+    EXPECT(",");
+    CHECK_RESULT(ParseModuleType(&command->type));
+    *out_command = std::move(command);
+  } else if (Match("\"assert_invalid\"")) {
+    auto command = MakeUnique<AssertInvalidCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseFilename(&command->filename));
+    EXPECT(",");
+    PARSE_KEY_STRING_VALUE("text", &command->text);
+    EXPECT(",");
+    CHECK_RESULT(ParseModuleType(&command->type));
+    *out_command = std::move(command);
+  } else if (Match("\"assert_unlinkable\"")) {
+    auto command = MakeUnique<AssertUnlinkableCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseFilename(&command->filename));
+    EXPECT(",");
+    PARSE_KEY_STRING_VALUE("text", &command->text);
+    EXPECT(",");
+    CHECK_RESULT(ParseModuleType(&command->type));
+    *out_command = std::move(command);
+  } else if (Match("\"assert_uninstantiable\"")) {
+    auto command = MakeUnique<AssertUninstantiableCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseFilename(&command->filename));
+    EXPECT(",");
+    PARSE_KEY_STRING_VALUE("text", &command->text);
+    EXPECT(",");
+    CHECK_RESULT(ParseModuleType(&command->type));
+    *out_command = std::move(command);
+  } else if (Match("\"assert_return\"")) {
+    auto command = MakeUnique<AssertReturnCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseAction(&command->action));
+    EXPECT(",");
+    EXPECT_KEY("expected");
+    CHECK_RESULT(ParseExpectedValues(&command->expected));
+    *out_command = std::move(command);
+  } else if (Match("\"assert_trap\"")) {
+    auto command = MakeUnique<AssertTrapCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseAction(&command->action));
+    EXPECT(",");
+    PARSE_KEY_STRING_VALUE("text", &command->text);
+    EXPECT(",");
+    CHECK_RESULT(ParseActionResult());
+    *out_command = std::move(command);
+  } else if (Match("\"assert_exhaustion\"")) {
+    auto command = MakeUnique<AssertExhaustionCommand>();
+    EXPECT(",");
+    CHECK_RESULT(ParseLine(&command->line));
+    EXPECT(",");
+    CHECK_RESULT(ParseAction(&command->action));
+    EXPECT(",");
+    PARSE_KEY_STRING_VALUE("text", &command->text);
+    EXPECT(",");
+    CHECK_RESULT(ParseActionResult());
+    *out_command = std::move(command);
+  } else {
+    PrintError("unknown command type");
+    return wabt::Result::Error;
+  }
+  EXPECT("}");
+  return wabt::Result::Ok;
+}
+
+wabt::Result JSONParser::ParseScript(Script* out_script) {
+  EXPECT("{");
+  PARSE_KEY_STRING_VALUE("source_filename", &out_script->filename);
+  EXPECT(",");
+  EXPECT_KEY("commands");
+  EXPECT("[");
+  bool first = true;
+  while (!Match("]")) {
+    CommandPtr command;
+    if (!first) {
+      EXPECT(",");
+    }
+    CHECK_RESULT(ParseCommand(&command));
+    out_script->commands.push_back(std::move(command));
+    first = false;
+  }
+  EXPECT("}");
+  return wabt::Result::Ok;
+}
+
+struct ActionResult {
+  ValueTypes types;
+  Values values;
+  Trap::Ptr trap;
+};
+
+class CommandRunner {
+ public:
+  CommandRunner();
+  wabt::Result Run(const Script& script);
+
+  int passed() const { return passed_; }
+  int total() const { return total_; }
+
+ private:
+  using ExportMap = std::map<std::string, Extern::Ptr>;
+  using Registry = std::map<std::string, ExportMap>;
+
+  void WABT_PRINTF_FORMAT(3, 4)
+      PrintError(uint32_t line_number, const char* format, ...);
+  ActionResult RunAction(int line_number,
+                         const Action* action,
+                         RunVerbosity verbose);
+
+  interp::Module::Ptr ReadModule(string_view module_filename, Errors* errors);
+  Extern::Ptr GetImport(const std::string&, const std::string&);
+  void PopulateImports(const interp::Module::Ptr&, RefVec*);
+  void PopulateExports(const Instance::Ptr&, ExportMap*);
+
+  wabt::Result OnModuleCommand(const ModuleCommand*);
+  wabt::Result OnActionCommand(const ActionCommand*);
+  wabt::Result OnRegisterCommand(const RegisterCommand*);
+  wabt::Result OnAssertMalformedCommand(const AssertMalformedCommand*);
+  wabt::Result OnAssertUnlinkableCommand(const AssertUnlinkableCommand*);
+  wabt::Result OnAssertInvalidCommand(const AssertInvalidCommand*);
+  wabt::Result OnAssertUninstantiableCommand(
+      const AssertUninstantiableCommand*);
+  wabt::Result OnAssertReturnCommand(const AssertReturnCommand*);
+  wabt::Result OnAssertTrapCommand(const AssertTrapCommand*);
+  wabt::Result OnAssertExhaustionCommand(const AssertExhaustionCommand*);
+
+  wabt::Result CheckAssertReturnResult(const AssertReturnCommand* command,
+                                       int index,
+                                       ExpectedValue expected,
+                                       TypedValue actual,
+                                       bool print_error);
+
+  void TallyCommand(wabt::Result);
+
+  wabt::Result ReadInvalidTextModule(string_view module_filename,
+                                     const std::string& header);
+  wabt::Result ReadInvalidModule(int line_number,
+                           string_view module_filename,
+                           ModuleType module_type,
+                           const char* desc);
+  wabt::Result ReadUnlinkableModule(int line_number,
+                              string_view module_filename,
+                              ModuleType module_type,
+                              const char* desc);
+
+  Store store_;
+  Registry registry_;  // Used when importing.
+  Registry instances_;  // Used when referencing module by name in invoke.
+  ExportMap last_instance_;
+  int passed_ = 0;
+  int total_ = 0;
+
+  std::string source_filename_;
+};
+
+CommandRunner::CommandRunner() : store_(s_features) {
+  auto&& spectest = registry_["spectest"];
+
+  // Initialize print functions for the spec test.
+  struct {
+    const char* name;
+    interp::FuncType type;
+  } const print_funcs[] = {
+      {"print", interp::FuncType{{}, {}}},
+      {"print_i32", interp::FuncType{{ValueType::I32}, {}}},
+      {"print_f32", interp::FuncType{{ValueType::F32}, {}}},
+      {"print_f64", interp::FuncType{{ValueType::F64}, {}}},
+      {"print_i32_f32", interp::FuncType{{ValueType::I32, ValueType::F32}, {}}},
+      {"print_f64_f64", interp::FuncType{{ValueType::F64, ValueType::F64}, {}}},
+  };
+
+  for (auto&& print : print_funcs) {
+    auto import_name = StringPrintf("spectest.%s", print.name);
+    spectest[print.name] = HostFunc::New(
+        store_, print.type,
+        [=](Thread& inst, const Values& params, Values& results,
+            Trap::Ptr* trap) -> wabt::Result {
+          printf("called host ");
+          WriteCall(s_stdout_stream.get(), import_name, print.type, params,
+                    results, *trap);
+          return wabt::Result::Ok;
+        });
+  }
+
+  spectest["table"] =
+      interp::Table::New(store_, TableType{ValueType::FuncRef, Limits{10, 20}});
+
+  spectest["memory"] = interp::Memory::New(store_, MemoryType{Limits{1, 2}});
+
+  spectest["global_i32"] = interp::Global::New(
+      store_, GlobalType{ValueType::I32, Mutability::Const}, Value::Make(u32{666}));
+  spectest["global_i64"] = interp::Global::New(
+      store_, GlobalType{ValueType::I64, Mutability::Const}, Value::Make(u64{666}));
+  spectest["global_f32"] = interp::Global::New(
+      store_, GlobalType{ValueType::F32, Mutability::Const}, Value::Make(f32{666}));
+  spectest["global_f64"] = interp::Global::New(
+      store_, GlobalType{ValueType::F64, Mutability::Const}, Value::Make(f64{666}));
+}
+
+wabt::Result CommandRunner::Run(const Script& script) {
+  source_filename_ = script.filename;
+
+  for (const CommandPtr& command : script.commands) {
+    switch (command->type) {
+      case CommandType::Module:
+        OnModuleCommand(cast<ModuleCommand>(command.get()));
+        break;
+
+      case CommandType::Action:
+        TallyCommand(OnActionCommand(cast<ActionCommand>(command.get())));
+        break;
+
+      case CommandType::Register:
+        OnRegisterCommand(cast<RegisterCommand>(command.get()));
+        break;
+
+      case CommandType::AssertMalformed:
+        TallyCommand(OnAssertMalformedCommand(
+            cast<AssertMalformedCommand>(command.get())));
+        break;
+
+      case CommandType::AssertInvalid:
+        TallyCommand(
+            OnAssertInvalidCommand(cast<AssertInvalidCommand>(command.get())));
+        break;
+
+      case CommandType::AssertUnlinkable:
+        TallyCommand(OnAssertUnlinkableCommand(
+            cast<AssertUnlinkableCommand>(command.get())));
+        break;
+
+      case CommandType::AssertUninstantiable:
+        TallyCommand(OnAssertUninstantiableCommand(
+            cast<AssertUninstantiableCommand>(command.get())));
+        break;
+
+      case CommandType::AssertReturn:
+        TallyCommand(
+            OnAssertReturnCommand(cast<AssertReturnCommand>(command.get())));
+        break;
+
+      case CommandType::AssertTrap:
+        TallyCommand(
+            OnAssertTrapCommand(cast<AssertTrapCommand>(command.get())));
+        break;
+
+      case CommandType::AssertExhaustion:
+        TallyCommand(OnAssertExhaustionCommand(
+            cast<AssertExhaustionCommand>(command.get())));
+        break;
+    }
+  }
+
+  return wabt::Result::Ok;
+}
+
+void CommandRunner::PrintError(uint32_t line_number, const char* format, ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  printf("%s:%u: %s\n", source_filename_.c_str(), line_number, buffer);
+}
+
+ActionResult CommandRunner::RunAction(int line_number,
+                                      const Action* action,
+                                      RunVerbosity verbose) {
+  ExportMap& module = !action->module_name.empty()
+                          ? instances_[action->module_name]
+                          : last_instance_;
+  Extern::Ptr extern_ = module[action->field_name];
+  if (!extern_) {
+    PrintError(line_number, "unknown invoke \"%s.%s\"",
+               action->module_name.c_str(), action->field_name.c_str());
+    return {};
+  }
+
+  ActionResult result;
+
+  switch (action->type) {
+    case ActionType::Invoke: {
+      auto* func = cast<interp::Func>(extern_.get());
+      func->Call(store_, action->args, result.values, &result.trap,
+                 s_trace_stream);
+      result.types = func->type().results;
+      if (verbose == RunVerbosity::Verbose) {
+        WriteCall(s_stdout_stream.get(), action->field_name, func->type(),
+                  action->args, result.values, result.trap);
+      }
+      break;
+    }
+
+    case ActionType::Get: {
+      auto* global = cast<interp::Global>(extern_.get());
+      result.values.push_back(global->Get());
+      result.types.push_back(global->type().type);
+      break;
+    }
+
+    default:
+      WABT_UNREACHABLE;
+  }
+
+  return result;
+}
+
+wabt::Result CommandRunner::ReadInvalidTextModule(string_view module_filename,
+                                            const std::string& header) {
+  std::vector<uint8_t> file_data;
+  wabt::Result result = ReadFile(module_filename, &file_data);
+  std::unique_ptr<WastLexer> lexer = WastLexer::CreateBufferLexer(
+      module_filename, file_data.data(), file_data.size());
+  Errors errors;
+  if (Succeeded(result)) {
+    std::unique_ptr<wabt::Module> module;
+    WastParseOptions options(s_features);
+    result = ParseWatModule(lexer.get(), &module, &errors, &options);
+  }
+
+  auto line_finder = lexer->MakeLineFinder();
+  FormatErrorsToFile(errors, Location::Type::Text, line_finder.get(), stdout,
+                     header, PrintHeader::Once);
+  return result;
+}
+
+interp::Module::Ptr CommandRunner::ReadModule(string_view module_filename,
+                                               Errors* errors) {
+  std::vector<uint8_t> file_data;
+
+  if (Failed(ReadFile(module_filename, &file_data))) {
+    return {};
+  }
+
+  const bool kReadDebugNames = true;
+  const bool kStopOnFirstError = true;
+  const bool kFailOnCustomSectionError = true;
+  ReadBinaryOptions options(s_features, s_log_stream.get(), kReadDebugNames,
+                            kStopOnFirstError, kFailOnCustomSectionError);
+  ModuleDesc module_desc;
+  if (Failed(ReadBinaryInterp(file_data.data(), file_data.size(), options,
+                              errors, &module_desc))) {
+    return {};
+  }
+
+  if (s_verbose) {
+    module_desc.istream.Disassemble(s_stdout_stream.get());
+  }
+
+  return interp::Module::New(store_, module_desc);
+}
+
+wabt::Result CommandRunner::ReadInvalidModule(int line_number,
+                                        string_view module_filename,
+                                        ModuleType module_type,
+                                        const char* desc) {
+  std::string header = StringPrintf(
+      "%s:%d: %s passed", source_filename_.c_str(), line_number, desc);
+
+  switch (module_type) {
+    case ModuleType::Text: {
+      return ReadInvalidTextModule(module_filename, header);
+    }
+
+    case ModuleType::Binary: {
+      Errors errors;
+      auto module = ReadModule(module_filename, &errors);
+      if (!module) {
+        FormatErrorsToFile(errors, Location::Type::Binary, {}, stdout, header,
+                           PrintHeader::Once);
+        return wabt::Result::Error;
+      } else {
+        return wabt::Result::Ok;
+      }
+    }
+  }
+
+  WABT_UNREACHABLE;
+}
+
+Extern::Ptr CommandRunner::GetImport(const std::string& module,
+                                     const std::string& name) {
+  auto mod_iter = registry_.find(module);
+  if (mod_iter != registry_.end()) {
+    auto extern_iter = mod_iter->second.find(name);
+    if (extern_iter != mod_iter->second.end()) {
+      return extern_iter->second;
+    }
+  }
+  return {};
+}
+
+void CommandRunner::PopulateImports(const interp::Module::Ptr& module,
+                                    RefVec* imports) {
+  for (auto&& import : module->desc().imports) {
+    auto extern_ = GetImport(import.type.module, import.type.name);
+    imports->push_back(extern_ ? extern_.ref() : Ref::Null);
+  }
+}
+
+void CommandRunner::PopulateExports(const Instance::Ptr& instance,
+                                    ExportMap* map) {
+  map->clear();
+  interp::Module::Ptr module{store_, instance->module()};
+  for (size_t i = 0; i < module->export_types().size(); ++i) {
+    const ExportType& export_type = module->export_types()[i];
+    (*map)[export_type.name] = store_.UnsafeGet<Extern>(instance->exports()[i]);
+  }
+}
+
+wabt::Result CommandRunner::OnModuleCommand(const ModuleCommand* command) {
+  Errors errors;
+  auto module = ReadModule(command->filename, &errors);
+  FormatErrorsToFile(errors, Location::Type::Binary);
+
+  if (!module) {
+    PrintError(command->line, "error reading module: \"%s\"",
+               command->filename.c_str());
+    return wabt::Result::Error;
+  }
+
+  RefVec imports;
+  PopulateImports(module, &imports);
+
+  Trap::Ptr trap;
+  auto instance = Instance::Instantiate(store_, module.ref(), imports, &trap);
+  if (trap) {
+    assert(!instance);
+    PrintError(command->line, "error instantiating module: \"%s\"",
+               trap->message().c_str());
+    return wabt::Result::Error;
+  }
+
+  PopulateExports(instance, &last_instance_);
+  if (!command->name.empty()) {
+    instances_[command->name] = last_instance_;
+  }
+
+  return wabt::Result::Ok;
+}
+
+wabt::Result CommandRunner::OnActionCommand(const ActionCommand* command) {
+  ActionResult result =
+      RunAction(command->line, &command->action, RunVerbosity::Verbose);
+
+  if (result.trap) {
+    PrintError(command->line, "unexpected trap: %s",
+               result.trap->message().c_str());
+    return wabt::Result::Error;
+  }
+
+  return wabt::Result::Ok;
+}
+
+wabt::Result CommandRunner::OnAssertMalformedCommand(
+    const AssertMalformedCommand* command) {
+  wabt::Result result = ReadInvalidModule(command->line, command->filename,
+                                    command->type, "assert_malformed");
+  if (Succeeded(result)) {
+    PrintError(command->line, "expected module to be malformed: \"%s\"",
+               command->filename.c_str());
+    return wabt::Result::Error;
+  }
+
+  return wabt::Result::Ok;
+}
+
+wabt::Result CommandRunner::OnRegisterCommand(const RegisterCommand* command) {
+  if (!command->name.empty()) {
+    auto instance_iter = instances_.find(command->name);
+    if (instance_iter == instances_.end()) {
+      PrintError(command->line, "unknown module in register");
+      return wabt::Result::Error;
+    }
+    registry_[command->as] = instance_iter->second;
+  } else {
+    registry_[command->as] = last_instance_;
+  }
+
+  return wabt::Result::Ok;
+}
+
+wabt::Result CommandRunner::OnAssertUnlinkableCommand(
+    const AssertUnlinkableCommand* command) {
+  Errors errors;
+  auto module = ReadModule(command->filename, &errors);
+
+  if (!module) {
+    PrintError(command->line, "unable to compile unlinkable module: \"%s\"",
+               command->filename.c_str());
+    return wabt::Result::Error;
+  }
+
+  RefVec imports;
+  PopulateImports(module, &imports);
+
+  Trap::Ptr trap;
+  auto instance = Instance::Instantiate(store_, module.ref(), imports, &trap);
+  if (!trap) {
+    PrintError(command->line, "expected module to be unlinkable: \"%s\"",
+               command->filename.c_str());
+    return wabt::Result::Error;
+  }
+
+  // TODO: Change to one-line error.
+  PrintError(command->line, "assert_unlinkable passed:\n  error: %s",
+             trap->message().c_str());
+  return wabt::Result::Ok;
+}
+
+wabt::Result CommandRunner::OnAssertInvalidCommand(
+    const AssertInvalidCommand* command) {
+  wabt::Result result = ReadInvalidModule(command->line, command->filename,
+                                    command->type, "assert_invalid");
+  if (Succeeded(result)) {
+    PrintError(command->line, "expected module to be invalid: \"%s\"",
+               command->filename.c_str());
+    return wabt::Result::Error;
+  }
+
+  return wabt::Result::Ok;
+}
+
+wabt::Result CommandRunner::OnAssertUninstantiableCommand(
+    const AssertUninstantiableCommand* command) {
+  Errors errors;
+  auto module = ReadModule(command->filename, &errors);
+
+  if (!module) {
+    PrintError(command->line, "unable to compile uninstantiable module: \"%s\"",
+               command->filename.c_str());
+    return wabt::Result::Error;
+  }
+
+  RefVec imports;
+  PopulateImports(module, &imports);
+
+  Trap::Ptr trap;
+  auto instance = Instance::Instantiate(store_, module.ref(), imports, &trap);
+  if (!trap) {
+    PrintError(command->line, "expected module to be uninstantiable: \"%s\"",
+               command->filename.c_str());
+    return wabt::Result::Error;
+  }
+
+  // TODO: print error when assertion passes.
+#if 0
+  PrintError(command->line, "assert_uninstantiable passed: %s",
+             trap->message().c_str());
+#endif
+  return wabt::Result::Ok;
+}
+
+static bool WABT_VECTORCALL IsCanonicalNan(f32 val) {
+  const u32 kQuietNan = 0x7fc00000U;
+  const u32 kQuietNegNan = 0xffc00000U;
+  u32 bits = Bitcast<u32>(val);
+  return bits == kQuietNan || bits == kQuietNegNan;
+}
+
+static bool WABT_VECTORCALL IsCanonicalNan(f64 val) {
+  const u64 kQuietNan = 0x7ff8000000000000ULL;
+  const u64 kQuietNegNan = 0xfff8000000000000ULL;
+  u64 bits = Bitcast<u64>(val);
+  return bits == kQuietNan || bits == kQuietNegNan;
+}
+
+static bool WABT_VECTORCALL IsArithmeticNan(f32 val) {
+  const u32 kQuietNan = 0x7fc00000U;
+  return (Bitcast<u32>(val) & kQuietNan) == kQuietNan;
+}
+
+static bool WABT_VECTORCALL IsArithmeticNan(f64 val) {
+  const u64 kQuietNan = 0x7ff8000000000000ULL;
+  return (Bitcast<u64>(val) & kQuietNan) == kQuietNan;
+}
+
+static std::string ExpectedValueToString(const ExpectedValue& ev) {
+  // Extend TypedValueToString to print expected nan values too.
+  switch (ev.value.type) {
+    case Type::F32:
+    case Type::F64:
+      switch (ev.nan[0]) {
+        case ExpectedNan::None:
+          return TypedValueToString(ev.value);
+
+        case ExpectedNan::Arithmetic:
+          return StringPrintf("%s:nan:arithmetic", ev.value.type.GetName());
+
+        case ExpectedNan::Canonical:
+          return StringPrintf("%s:nan:canonical", ev.value.type.GetName());
+      }
+      break;
+
+    case Type::V128: {
+      int lane_count = LaneCountFromType(ev.lane_type);
+      std::string result = "v128 ";
+      for (int lane = 0; lane < lane_count; ++lane) {
+        result += ExpectedValueToString(GetLane(ev, lane));
+      }
+      return result;
+    }
+
+    default:
+      break;
+  }
+  return TypedValueToString(ev.value);
+}
+
+wabt::Result CommandRunner::CheckAssertReturnResult(
+    const AssertReturnCommand* command,
+    int index,
+    ExpectedValue expected,
+    TypedValue actual,
+    bool print_error) {
+  assert(expected.value.type == actual.type ||
+         IsReference(expected.value.type));
+  bool ok = true;
+  switch (expected.value.type) {
+    case Type::I8:
+    case Type::I16:
+    case Type::I32:
+      ok = expected.value.value.Get<u32>() == actual.value.Get<u32>();
+      break;
+
+    case Type::I64:
+      ok = expected.value.value.Get<u64>() == actual.value.Get<u64>();
+      break;
+
+    case Type::F32:
+      switch (expected.nan[0]) {
+        case ExpectedNan::Arithmetic:
+          ok = IsArithmeticNan(actual.value.Get<f32>());
+          break;
+
+        case ExpectedNan::Canonical:
+          ok = IsCanonicalNan(actual.value.Get<f32>());
+          break;
+
+        case ExpectedNan::None:
+          ok = Bitcast<u32>(expected.value.value.Get<f32>()) ==
+               Bitcast<u32>(actual.value.Get<f32>());
+          break;
+      }
+      break;
+
+    case Type::F64:
+      switch (expected.nan[0]) {
+        case ExpectedNan::Arithmetic:
+          ok = IsArithmeticNan(actual.value.Get<f64>());
+          break;
+
+        case ExpectedNan::Canonical:
+          ok = IsCanonicalNan(actual.value.Get<f64>());
+          break;
+
+        case ExpectedNan::None:
+          ok = Bitcast<u64>(expected.value.value.Get<f64>()) ==
+               Bitcast<u64>(actual.value.Get<f64>());
+          break;
+      }
+      break;
+
+    case Type::V128: {
+      // Compare each lane as if it were its own value.
+      for (int lane = 0; lane < LaneCountFromType(expected.lane_type); ++lane) {
+        ExpectedValue lane_expected = GetLane(expected, lane);
+        TypedValue lane_actual = GetLane(actual, expected.lane_type, lane);
+
+        if (Failed(CheckAssertReturnResult(command, index, lane_expected,
+                                           lane_actual, false))) {
+          PrintError(command->line,
+                     "mismatch in lane %u of result %u of assert_return: "
+                     "expected %s, got %s",
+                     lane, index, ExpectedValueToString(lane_expected).c_str(),
+                     TypedValueToString(lane_actual).c_str());
+          ok = false;
+        }
+      }
+      break;
+    }
+
+    case Type::FuncRef:
+      // A funcref expectation only requires that the reference be a function,
+      // but it doesn't check the actual index.
+      ok = (actual.type == Type::FuncRef);
+      break;
+
+    case Type::ExternRef:
+      ok = expected.value.value.Get<Ref>() == actual.value.Get<Ref>();
+      break;
+
+    default:
+      WABT_UNREACHABLE;
+  }
+
+  if (!ok && print_error) {
+    PrintError(command->line,
+               "mismatch in result %u of assert_return: expected %s, got %s",
+               index, ExpectedValueToString(expected).c_str(),
+               TypedValueToString(actual).c_str());
+  }
+  return ok ? wabt::Result::Ok : wabt::Result::Error;
+}
+
+wabt::Result CommandRunner::OnAssertReturnCommand(
+    const AssertReturnCommand* command) {
+  ActionResult action_result =
+      RunAction(command->line, &command->action, RunVerbosity::Quiet);
+
+  if (action_result.trap) {
+    PrintError(command->line, "unexpected trap: %s",
+               action_result.trap->message().c_str());
+    return wabt::Result::Error;
+  }
+
+  if (action_result.values.size() != command->expected.size()) {
+    PrintError(command->line,
+               "result length mismatch in assert_return: expected %" PRIzd
+               ", got %" PRIzd,
+               command->expected.size(), action_result.values.size());
+    return wabt::Result::Error;
+  }
+
+  wabt::Result result = wabt::Result::Ok;
+  for (size_t i = 0; i < action_result.values.size(); ++i) {
+    const ExpectedValue& expected = command->expected[i];
+    TypedValue actual{action_result.types[i], action_result.values[i]};
+
+    result |= CheckAssertReturnResult(command, i, expected, actual, true);
+  }
+
+  return result;
+}
+
+wabt::Result CommandRunner::OnAssertTrapCommand(
+    const AssertTrapCommand* command) {
+  ActionResult result =
+      RunAction(command->line, &command->action, RunVerbosity::Quiet);
+  if (!result.trap) {
+    PrintError(command->line, "expected trap: \"%s\"", command->text.c_str());
+    return wabt::Result::Error;
+  }
+
+  PrintError(command->line, "assert_trap passed: %s",
+             result.trap->message().c_str());
+  return wabt::Result::Ok;
+}
+
+wabt::Result CommandRunner::OnAssertExhaustionCommand(
+    const AssertExhaustionCommand* command) {
+  ActionResult result =
+      RunAction(command->line, &command->action, RunVerbosity::Quiet);
+  if (!result.trap || result.trap->message() != "call stack exhausted") {
+    PrintError(command->line, "expected trap: \"%s\"", command->text.c_str());
+    return wabt::Result::Error;
+  }
+
+  // TODO: print message when assertion passes.
+#if 0
+  PrintError(command->line, "assert_exhaustion passed: %s",
+             result.trap->message().c_str());
+#endif
+  return wabt::Result::Ok;
+}
+
+void CommandRunner::TallyCommand(wabt::Result result) {
+  if (Succeeded(result)) {
+    passed_++;
+  }
+  total_++;
+}
+
+static int ReadAndRunSpecJSON(string_view spec_json_filename) {
+  JSONParser parser;
+  if (parser.ReadFile(spec_json_filename) == wabt::Result::Error) {
+    return 1;
+  }
+
+  Script script;
+  if (parser.ParseScript(&script) == wabt::Result::Error) {
+    return 1;
+  }
+
+  CommandRunner runner;
+  if (runner.Run(script) == wabt::Result::Error) {
+    return 1;
+  }
+
+  printf("%d/%d tests passed.\n", runner.passed(), runner.total());
+  const int failed = runner.total() - runner.passed();
+  return failed;
+}
+
+}  // namespace spectest
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+  s_stdout_stream = FileStream::CreateStdout();
+
+  ParseOptions(argc, argv);
+  return spectest::ReadAndRunSpecJSON(s_infile);
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-decompile.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-decompile.cc
new file mode 100644 (file)
index 0000000..74491e5
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2019 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 <cassert>
+#include <cinttypes>
+#include <cstdio>
+#include <cstdlib>
+
+#include "src/apply-names.h"
+#include "src/binary-reader.h"
+#include "src/binary-reader-ir.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/generate-names.h"
+#include "src/ir.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-lexer.h"
+#include "src/decompiler.h"
+
+using namespace wabt;
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+
+  std::string infile;
+  std::string outfile;
+  Features features;
+  DecompileOptions decompile_options;
+  bool fail_on_custom_section_error = true;
+
+  {
+    const char s_description[] =
+      "  Read a file in the WebAssembly binary format, and convert it to\n"
+      "  a decompiled text file.\n"
+      "\n"
+      "examples:\n"
+      "  # parse binary file test.wasm and write text file test.dcmp\n"
+      "  $ wasm-decompile test.wasm -o test.dcmp\n";
+    OptionParser parser("wasm-decompile", s_description);
+    parser.AddOption(
+        'o', "output", "FILENAME",
+        "Output file for the decompiled file, by default use stdout",
+        [&](const char* argument) {
+          outfile = argument;
+          ConvertBackslashToSlash(&outfile);
+        });
+    features.AddOptions(&parser);
+    parser.AddOption("ignore-custom-section-errors",
+                     "Ignore errors in custom sections",
+                     [&]() { fail_on_custom_section_error = false; });
+    parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                       [&](const char* argument) {
+                         infile = argument;
+                         ConvertBackslashToSlash(&infile);
+                       });
+    parser.Parse(argc, argv);
+  }
+
+  std::vector<uint8_t> file_data;
+  Result result = ReadFile(infile.c_str(), &file_data);
+  if (Succeeded(result)) {
+    Errors errors;
+    Module module;
+    const bool kStopOnFirstError = true;
+    ReadBinaryOptions options(features, nullptr,
+                              true, kStopOnFirstError,
+                              fail_on_custom_section_error);
+    result = ReadBinaryIr(infile.c_str(), file_data.data(), file_data.size(),
+                          options, &errors, &module);
+    if (Succeeded(result)) {
+      ValidateOptions options(features);
+      result = ValidateModule(&module, &errors, options);
+      if (Succeeded(result)) {
+        result = GenerateNames(&module,
+                               static_cast<NameOpts>(NameOpts::AlphaNames));
+      }
+      if (Succeeded(result)) {
+        // Must be called after ReadBinaryIr & GenerateNames, and before
+        // ApplyNames, see comments at definition.
+        RenameAll(module);
+      }
+      if (Succeeded(result)) {
+        /* TODO(binji): This shouldn't fail; if a name can't be applied
+         * (because the index is invalid, say) it should just be skipped. */
+        Result dummy_result = ApplyNames(&module);
+        WABT_USE(dummy_result);
+      }
+      if (Succeeded(result)) {
+        auto s = Decompile(module, decompile_options);
+        FileStream stream(!outfile.empty() ? FileStream(outfile)
+                                             : FileStream(stdout));
+        stream.WriteData(s.data(), s.size());
+      }
+    }
+    FormatErrorsToFile(errors, Location::Type::Binary);
+  }
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-interp.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-interp.cc
new file mode 100644 (file)
index 0000000..e349a9e
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * 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 <algorithm>
+#include <cassert>
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "src/binary-reader.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/interp/binary-reader-interp.h"
+#include "src/interp/interp-util.h"
+#include "src/interp/interp-wasi.h"
+#include "src/interp/interp.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+
+#ifdef WITH_WASI
+#include "uvwasi.h"
+#endif
+
+using namespace wabt;
+using namespace wabt::interp;
+
+static int s_verbose;
+static const char* s_infile;
+static Thread::Options s_thread_options;
+static Stream* s_trace_stream;
+static bool s_run_all_exports;
+static bool s_host_print;
+static bool s_dummy_import_func;
+static Features s_features;
+static bool s_wasi;
+static std::vector<std::string> s_wasi_env;
+static std::vector<std::string> s_wasi_argv;
+static std::vector<std::string> s_wasi_dirs;
+
+static std::unique_ptr<FileStream> s_log_stream;
+static std::unique_ptr<FileStream> s_stdout_stream;
+static std::unique_ptr<FileStream> s_stderr_stream;
+
+static Store s_store;
+
+static const char s_description[] =
+    R"(  read a file in the wasm binary format, and run in it a stack-based
+  interpreter.
+
+examples:
+  # parse binary file test.wasm, and type-check it
+  $ wasm-interp test.wasm
+
+  # parse test.wasm and run all its exported functions
+  $ wasm-interp test.wasm --run-all-exports
+
+  # parse test.wasm, run the exported functions and trace the output
+  $ wasm-interp test.wasm --run-all-exports --trace
+
+  # parse test.wasm and run all its exported functions, setting the
+  # value stack size to 100 elements
+  $ wasm-interp test.wasm -V 100 --run-all-exports
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wasm-interp", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+  });
+  s_features.AddOptions(&parser);
+  parser.AddOption('V', "value-stack-size", "SIZE",
+                   "Size in elements of the value stack",
+                   [](const std::string& argument) {
+                     // TODO(binji): validate.
+                     s_thread_options.value_stack_size = atoi(argument.c_str());
+                   });
+  parser.AddOption('C', "call-stack-size", "SIZE",
+                   "Size in elements of the call stack",
+                   [](const std::string& argument) {
+                     // TODO(binji): validate.
+                     s_thread_options.call_stack_size = atoi(argument.c_str());
+                   });
+  parser.AddOption('t', "trace", "Trace execution",
+                   []() { s_trace_stream = s_stdout_stream.get(); });
+  parser.AddOption("wasi",
+                   "Assume input module is WASI compliant (Export "
+                   " WASI API the the module and invoke _start function)",
+                   []() { s_wasi = true; });
+  parser.AddOption(
+      'e', "env", "ENV",
+      "Pass the given environment string in the WASI runtime",
+      [](const std::string& argument) { s_wasi_env.push_back(argument); });
+  parser.AddOption(
+      'd', "dir", "DIR", "Pass the given directory the the WASI runtime",
+      [](const std::string& argument) { s_wasi_dirs.push_back(argument); });
+  parser.AddOption(
+      "run-all-exports",
+      "Run all the exported functions, in order. Useful for testing",
+      []() { s_run_all_exports = true; });
+  parser.AddOption("host-print",
+                   "Include an importable function named \"host.print\" for "
+                   "printing to stdout",
+                   []() { s_host_print = true; });
+  parser.AddOption(
+      "dummy-import-func",
+      "Provide a dummy implementation of all imported functions. The function "
+      "will log the call and return an appropriate zero value.",
+      []() { s_dummy_import_func = true; });
+
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) { s_infile = argument; });
+  parser.AddArgument(
+      "arg", OptionParser::ArgumentCount::ZeroOrMore,
+      [](const char* argument) { s_wasi_argv.push_back(argument); });
+  parser.Parse(argc, argv);
+}
+
+Result RunAllExports(const Instance::Ptr& instance, Errors* errors) {
+  Result result = Result::Ok;
+
+  auto module = s_store.UnsafeGet<Module>(instance->module());
+  auto&& module_desc = module->desc();
+
+  for (auto&& export_ : module_desc.exports) {
+    if (export_.type.type->kind != ExternalKind::Func) {
+      continue;
+    }
+    auto* func_type = cast<FuncType>(export_.type.type.get());
+    if (func_type->params.empty()) {
+      if (s_trace_stream) {
+        s_trace_stream->Writef(">>> running export \"%s\":\n",
+                               export_.type.name.c_str());
+      }
+      auto func = s_store.UnsafeGet<Func>(instance->funcs()[export_.index]);
+      Values params;
+      Values results;
+      Trap::Ptr trap;
+      result |= func->Call(s_store, params, results, &trap, s_trace_stream);
+      WriteCall(s_stdout_stream.get(), export_.type.name, *func_type, params,
+                results, trap);
+    }
+  }
+
+  return result;
+}
+
+static void BindImports(const Module::Ptr& module, RefVec& imports) {
+  auto* stream = s_stdout_stream.get();
+
+  for (auto&& import : module->desc().imports) {
+    if (import.type.type->kind == ExternKind::Func &&
+        ((s_host_print && import.type.module == "host" &&
+          import.type.name == "print") ||
+         s_dummy_import_func)) {
+      auto func_type = *cast<FuncType>(import.type.type.get());
+      auto import_name = StringPrintf("%s.%s", import.type.module.c_str(),
+                                      import.type.name.c_str());
+
+      auto host_func =
+          HostFunc::New(s_store, func_type,
+                        [=](Thread& thread, const Values& params,
+                            Values& results, Trap::Ptr* trap) -> Result {
+                          printf("called host ");
+                          WriteCall(stream, import_name, func_type, params,
+                                    results, *trap);
+                          return Result::Ok;
+                        });
+      imports.push_back(host_func.ref());
+      continue;
+    }
+
+    // By default, just push an null reference. This won't resolve, and
+    // instantiation will fail.
+    imports.push_back(Ref::Null);
+  }
+}
+
+static Result ReadModule(const char* module_filename,
+                         Errors* errors,
+                         Module::Ptr* out_module) {
+  auto* stream = s_stdout_stream.get();
+  std::vector<uint8_t> file_data;
+  CHECK_RESULT(ReadFile(module_filename, &file_data));
+
+  ModuleDesc module_desc;
+  const bool kReadDebugNames = true;
+  const bool kStopOnFirstError = true;
+  const bool kFailOnCustomSectionError = true;
+  ReadBinaryOptions options(s_features, s_log_stream.get(), kReadDebugNames,
+                            kStopOnFirstError, kFailOnCustomSectionError);
+  CHECK_RESULT(ReadBinaryInterp(file_data.data(), file_data.size(), options,
+                                errors, &module_desc));
+
+  if (s_verbose) {
+    module_desc.istream.Disassemble(stream);
+  }
+
+  *out_module = Module::New(s_store, module_desc);
+  return Result::Ok;
+}
+
+static Result InstantiateModule(RefVec& imports,
+                                const Module::Ptr& module,
+                                Instance::Ptr* out_instance) {
+  RefPtr<Trap> trap;
+  *out_instance = Instance::Instantiate(s_store, module.ref(), imports, &trap);
+  if (!*out_instance) {
+    WriteTrap(s_stderr_stream.get(), "error initializing module", trap);
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
+static Result ReadAndRunModule(const char* module_filename) {
+  Errors errors;
+  Module::Ptr module;
+  Result result = ReadModule(module_filename, &errors, &module);
+  if (!Succeeded(result)) {
+    FormatErrorsToFile(errors, Location::Type::Binary);
+    return result;
+  }
+
+  RefVec imports;
+
+#if WITH_WASI
+  uvwasi_t uvwasi;
+#endif
+
+  if (s_wasi) {
+#if WITH_WASI
+    uvwasi_errno_t err;
+    uvwasi_options_t init_options;
+
+    std::vector<const char*> argv;
+    argv.push_back(module_filename);
+    for (auto& s : s_wasi_argv) {
+      if (s_trace_stream) {
+        s_trace_stream->Writef("wasi: arg: \"%s\"\n", s.c_str());
+      }
+      argv.push_back(s.c_str());
+    }
+    argv.push_back(nullptr);
+
+    std::vector<const char*> envp;
+    for (auto& s : s_wasi_env) {
+      if (s_trace_stream) {
+        s_trace_stream->Writef("wasi: env: \"%s\"\n", s.c_str());
+      }
+      envp.push_back(s.c_str());
+    }
+    envp.push_back(nullptr);
+
+    std::vector<uvwasi_preopen_t> dirs;
+    for (auto& dir : s_wasi_dirs) {
+      if (s_trace_stream) {
+        s_trace_stream->Writef("wasi: dir: \"%s\"\n", dir.c_str());
+      }
+      dirs.push_back({dir.c_str(), dir.c_str()});
+    }
+
+    /* Setup the initialization options. */
+    init_options.in = 0;
+    init_options.out = 1;
+    init_options.err = 2;
+    init_options.fd_table_size = 3;
+    init_options.argc = argv.size() - 1;
+    init_options.argv = argv.data();
+    init_options.envp = envp.data();
+    init_options.preopenc = dirs.size();
+    init_options.preopens = dirs.data();
+    init_options.allocator = NULL;
+
+    err = uvwasi_init(&uvwasi, &init_options);
+    if (err != UVWASI_ESUCCESS) {
+      s_stderr_stream.get()->Writef("error initialiazing uvwasi: %d\n", err);
+      return Result::Error;
+    }
+    CHECK_RESULT(WasiBindImports(module, imports, s_stderr_stream.get(),
+                                 s_trace_stream));
+#else
+    s_stderr_stream.get()->Writef("wasi support not compiled in\n");
+    return Result::Error;
+#endif
+  } else {
+    BindImports(module, imports);
+  }
+  BindImports(module, imports);
+
+  Instance::Ptr instance;
+  CHECK_RESULT(InstantiateModule(imports, module, &instance));
+
+  if (s_run_all_exports) {
+    RunAllExports(instance, &errors);
+  }
+#ifdef WITH_WASI
+  if (s_wasi) {
+    CHECK_RESULT(
+        WasiRunStart(instance, &uvwasi, s_stderr_stream.get(), s_trace_stream));
+  }
+#endif
+
+  return Result::Ok;
+}
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+  s_stdout_stream = FileStream::CreateStdout();
+  s_stderr_stream = FileStream::CreateStderr();
+
+  ParseOptions(argc, argv);
+
+  wabt::Result result = ReadAndRunModule(s_infile);
+  return result != wabt::Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-objdump.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-objdump.cc
new file mode 100644 (file)
index 0000000..ca28eee
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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 <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "src/common.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+#include "src/binary-reader.h"
+#include "src/binary-reader-objdump.h"
+
+using namespace wabt;
+
+static const char s_description[] =
+R"(  Print information about the contents of wasm binaries.
+
+examples:
+  $ wasm-objdump test.wasm
+)";
+
+static ObjdumpOptions s_objdump_options;
+
+static std::vector<const char*> s_infiles;
+
+static std::unique_ptr<FileStream> s_log_stream;
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wasm-objdump", s_description);
+
+  parser.AddOption('h', "headers", "Print headers",
+                   []() { s_objdump_options.headers = true; });
+  parser.AddOption(
+      'j', "section", "SECTION", "Select just one section",
+      [](const char* argument) { s_objdump_options.section_name = argument; });
+  parser.AddOption('s', "full-contents", "Print raw section contents",
+                   []() { s_objdump_options.raw = true; });
+  parser.AddOption('d', "disassemble", "Disassemble function bodies",
+                   []() { s_objdump_options.disassemble = true; });
+  parser.AddOption("debug", "Print extra debug information", []() {
+    s_objdump_options.debug = true;
+    s_log_stream = FileStream::CreateStderr();
+    s_objdump_options.log_stream = s_log_stream.get();
+  });
+  parser.AddOption('x', "details", "Show section details",
+                   []() { s_objdump_options.details = true; });
+  parser.AddOption('r', "reloc", "Show relocations inline with disassembly",
+                   []() { s_objdump_options.relocs = true; });
+  parser.AddArgument(
+      "filename", OptionParser::ArgumentCount::OneOrMore,
+      [](const char* argument) { s_infiles.push_back(argument); });
+
+  parser.Parse(argc, argv);
+}
+
+Result dump_file(const char* filename) {
+  std::vector<uint8_t> file_data;
+  CHECK_RESULT(ReadFile(filename, &file_data));
+
+  uint8_t* data = file_data.data();
+  size_t size = file_data.size();
+
+  // Perform serveral passed over the binary in order to print out different
+  // types of information.
+  s_objdump_options.filename = filename;
+  printf("\n");
+
+  ObjdumpState state;
+
+  Result result = Result::Ok;
+
+  // Pass 0: Prepass
+  s_objdump_options.mode = ObjdumpMode::Prepass;
+  result |= ReadBinaryObjdump(data, size, &s_objdump_options, &state);
+  s_objdump_options.log_stream = nullptr;
+
+  // Pass 1: Print the section headers
+  if (s_objdump_options.headers) {
+    s_objdump_options.mode = ObjdumpMode::Headers;
+    result |= ReadBinaryObjdump(data, size, &s_objdump_options, &state);
+  }
+
+  // Pass 2: Print extra information based on section type
+  if (s_objdump_options.details) {
+    s_objdump_options.mode = ObjdumpMode::Details;
+    result |= ReadBinaryObjdump(data, size, &s_objdump_options, &state);
+  }
+
+  // Pass 3: Disassemble code section
+  if (s_objdump_options.disassemble) {
+    s_objdump_options.mode = ObjdumpMode::Disassemble;
+    result |= ReadBinaryObjdump(data, size, &s_objdump_options, &state);
+  }
+
+  // Pass 4: Dump to raw contents of the sections
+  if (s_objdump_options.raw) {
+    s_objdump_options.mode = ObjdumpMode::RawData;
+    result |= ReadBinaryObjdump(data, size, &s_objdump_options, &state);
+  }
+
+  return result;
+}
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+
+  ParseOptions(argc, argv);
+  if (!s_objdump_options.headers && !s_objdump_options.details &&
+      !s_objdump_options.disassemble && !s_objdump_options.raw) {
+    fprintf(stderr, "At least one of the following switches must be given:\n");
+    fprintf(stderr, " -d/--disassemble\n");
+    fprintf(stderr, " -h/--headers\n");
+    fprintf(stderr, " -x/--details\n");
+    fprintf(stderr, " -s/--full-contents\n");
+    return 1;
+  }
+
+  for (const char* filename: s_infiles) {
+    if (Failed(dump_file(filename))) {
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-opcodecnt.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-opcodecnt.cc
new file mode 100644 (file)
index 0000000..5d6225f
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * 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 <algorithm>
+#include <cassert>
+#include <cerrno>
+#include <cinttypes>
+#include <cstdio>
+#include <cstdlib>
+#include <map>
+#include <vector>
+
+#include "src/binary-reader.h"
+#include "src/binary-reader-opcnt.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+
+#define ERROR(fmt, ...) \
+  fprintf(stderr, "%s:%d: " fmt, __FILE__, __LINE__, __VA_ARGS__)
+
+using namespace wabt;
+
+static int s_verbose;
+static const char* s_infile;
+static const char* s_outfile;
+static size_t s_cutoff = 0;
+static const char* s_separator = ": ";
+
+static ReadBinaryOptions s_read_binary_options;
+static std::unique_ptr<FileStream> s_log_stream;
+static Features s_features;
+
+static const char s_description[] =
+R"(  Read a file in the wasm binary format, and count opcode usage for
+  instructions.
+
+examples:
+  # parse binary file test.wasm and write pcode dist file test.dist
+  $ wasm-opcodecnt test.wasm -o test.dist
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wasm-opcodecnt", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+    s_read_binary_options.log_stream = s_log_stream.get();
+  });
+  s_features.AddOptions(&parser);
+  parser.AddOption('o', "output", "FILENAME",
+                   "Output file for the opcode counts, by default use stdout",
+                   [](const char* argument) { s_outfile = argument; });
+  parser.AddOption(
+      'c', "cutoff", "N", "Cutoff for reporting counts less than N",
+      [](const std::string& argument) { s_cutoff = atol(argument.c_str()); });
+  parser.AddOption(
+      's', "separator", "SEPARATOR",
+      "Separator text between element and count when reporting counts",
+      [](const char* argument) { s_separator = argument; });
+  parser.AddArgument("filename", OptionParser::ArgumentCount::OneOrMore,
+                     [](const char* argument) { s_infile = argument; });
+  parser.Parse(argc, argv);
+}
+
+template <typename T>
+struct SortByCountDescending {
+  bool operator()(const T& lhs, const T& rhs) const {
+    return lhs.second > rhs.second;
+  }
+};
+
+template <typename T>
+struct WithinCutoff {
+  bool operator()(const T& pair) const {
+    return pair.second >= s_cutoff;
+  }
+};
+
+static size_t SumCounts(const OpcodeInfoCounts& info_counts) {
+  size_t sum = 0;
+  for (auto& pair : info_counts) {
+    sum += pair.second;
+  }
+  return sum;
+}
+
+void WriteCounts(Stream& stream, const OpcodeInfoCounts& info_counts) {
+  typedef std::pair<Opcode, size_t> OpcodeCountPair;
+
+  std::map<Opcode, size_t> counts;
+  for (auto& info_count_pair: info_counts) {
+    Opcode opcode = info_count_pair.first.opcode();
+    size_t count = info_count_pair.second;
+    counts[opcode] += count;
+  }
+
+  std::vector<OpcodeCountPair> sorted;
+  std::copy_if(counts.begin(), counts.end(), std::back_inserter(sorted),
+               WithinCutoff<OpcodeCountPair>());
+
+  // Use a stable sort to keep the elements with the same count in opcode
+  // order (since the Opcode map is sorted).
+  std::stable_sort(sorted.begin(), sorted.end(),
+                   SortByCountDescending<OpcodeCountPair>());
+
+  for (auto& pair : sorted) {
+    Opcode opcode = pair.first;
+    size_t count = pair.second;
+    stream.Writef("%s%s%" PRIzd "\n", opcode.GetName(), s_separator, count);
+  }
+}
+
+void WriteCountsWithImmediates(Stream& stream,
+                               const OpcodeInfoCounts& counts) {
+  // Remove const from the key type so we can sort below.
+  typedef std::pair<std::remove_const<OpcodeInfoCounts::key_type>::type,
+                    OpcodeInfoCounts::mapped_type>
+      OpcodeInfoCountPair;
+
+  std::vector<OpcodeInfoCountPair> sorted;
+  std::copy_if(counts.begin(), counts.end(), std::back_inserter(sorted),
+               WithinCutoff<OpcodeInfoCountPair>());
+
+  // Use a stable sort to keep the elements with the same count in opcode info
+  // order (since the OpcodeInfoCounts map is sorted).
+  std::stable_sort(sorted.begin(), sorted.end(),
+                   SortByCountDescending<OpcodeInfoCountPair>());
+
+  for (auto& pair : sorted) {
+    auto&& info = pair.first;
+    size_t count = pair.second;
+    info.Write(stream);
+    stream.Writef("%s%" PRIzd "\n", s_separator, count);
+  }
+}
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  Result result = ReadFile(s_infile, &file_data);
+  if (Failed(result)) {
+    const char* input_name = s_infile ? s_infile : "stdin";
+    ERROR("Unable to parse: %s", input_name);
+    return 1;
+  }
+
+  FileStream stream(s_outfile ? FileStream(s_outfile) : FileStream(stdout));
+
+  if (Succeeded(result)) {
+    OpcodeInfoCounts counts;
+    s_read_binary_options.features = s_features;
+    result = ReadBinaryOpcnt(file_data.data(), file_data.size(),
+                             s_read_binary_options, &counts);
+    if (Succeeded(result)) {
+      stream.Writef("Total opcodes: %" PRIzd "\n\n", SumCounts(counts));
+
+      stream.Writef("Opcode counts:\n");
+      WriteCounts(stream, counts);
+
+      stream.Writef("\nOpcode counts with immediates:\n");
+      WriteCountsWithImmediates(stream, counts);
+    }
+  }
+
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-strip.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-strip.cc
new file mode 100644 (file)
index 0000000..f838672
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2018 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"
+#include "src/binary-reader.h"
+#include "src/binary-reader-nop.h"
+#include "src/error-formatter.h"
+#include "src/leb128.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+
+using namespace wabt;
+
+static std::string s_filename;
+
+static const char s_description[] =
+R"(  Remove sections of a WebAssembly binary file.
+
+examples:
+  # Remove all custom sections from test.wasm
+  $ wasm-strip test.wasm
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wasm-strip", s_description);
+
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) {
+                       s_filename = argument;
+                       ConvertBackslashToSlash(&s_filename);
+                     });
+  parser.Parse(argc, argv);
+}
+
+class BinaryReaderStrip : public BinaryReaderNop {
+ public:
+  explicit BinaryReaderStrip(Errors* errors)
+      : errors_(errors) {
+    stream_.WriteU32(WABT_BINARY_MAGIC, "WASM_BINARY_MAGIC");
+    stream_.WriteU32(WABT_BINARY_VERSION, "WASM_BINARY_VERSION");
+  }
+
+  bool OnError(const Error& error) override {
+    errors_->push_back(error);
+    return true;
+  }
+
+  Result BeginSection(Index section_index,
+                      BinarySection section_type,
+                      Offset size) override {
+    if (section_type == BinarySection::Custom) {
+      return Result::Ok;
+    }
+    stream_.WriteU8Enum(section_type, "section code");
+    WriteU32Leb128(&stream_, size, "section size");
+    stream_.WriteData(state->data + state->offset, size, "section data");
+    return Result::Ok;
+  }
+
+  Result WriteToFile(string_view filename) {
+    return stream_.WriteToFile(filename);
+  }
+
+ private:
+  MemoryStream stream_;
+  Errors* errors_;
+};
+
+int ProgramMain(int argc, char** argv) {
+  Result result;
+
+  InitStdio();
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  result = ReadFile(s_filename.c_str(), &file_data);
+  if (Succeeded(result)) {
+    Errors errors;
+    Features features;
+    const bool kReadDebugNames = false;
+    const bool kStopOnFirstError = true;
+    const bool kFailOnCustomSectionError = false;
+    ReadBinaryOptions options(features, nullptr, kReadDebugNames,
+                              kStopOnFirstError, kFailOnCustomSectionError);
+
+    BinaryReaderStrip reader(&errors);
+    result = ReadBinary(file_data.data(), file_data.size(), &reader, options);
+    FormatErrorsToFile(errors, Location::Type::Binary);
+
+    if (Succeeded(result)) {
+      result = reader.WriteToFile(s_filename);
+    }
+  }
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-validate.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm-validate.cc
new file mode 100644 (file)
index 0000000..a55c5ed
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * 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 <cassert>
+#include <cinttypes>
+#include <cstdio>
+#include <cstdlib>
+
+#include "src/binary-reader.h"
+#include "src/binary-reader-ir.h"
+#include "src/error-formatter.h"
+#include "src/ir.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-lexer.h"
+
+using namespace wabt;
+
+static int s_verbose;
+static std::string s_infile;
+static Features s_features;
+static bool s_read_debug_names = true;
+static bool s_fail_on_custom_section_error = true;
+static std::unique_ptr<FileStream> s_log_stream;
+
+static const char s_description[] =
+R"(  Read a file in the WebAssembly binary format, and validate it.
+
+examples:
+  # validate binary file test.wasm
+  $ wasm-validate test.wasm
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wasm-validate", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+  });
+  s_features.AddOptions(&parser);
+  parser.AddOption("no-debug-names", "Ignore debug names in the binary file",
+                   []() { s_read_debug_names = false; });
+  parser.AddOption("ignore-custom-section-errors",
+                   "Ignore errors in custom sections",
+                   []() { s_fail_on_custom_section_error = false; });
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) {
+                       s_infile = argument;
+                       ConvertBackslashToSlash(&s_infile);
+                     });
+  parser.Parse(argc, argv);
+}
+
+int ProgramMain(int argc, char** argv) {
+  Result result;
+
+  InitStdio();
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  result = ReadFile(s_infile.c_str(), &file_data);
+  if (Succeeded(result)) {
+    Errors errors;
+    Module module;
+    const bool kStopOnFirstError = true;
+    ReadBinaryOptions options(s_features, s_log_stream.get(),
+                              s_read_debug_names, kStopOnFirstError,
+                              s_fail_on_custom_section_error);
+    result = ReadBinaryIr(s_infile.c_str(), file_data.data(), file_data.size(),
+                          options, &errors, &module);
+    if (Succeeded(result)) {
+      ValidateOptions options(s_features);
+      result = ValidateModule(&module, &errors, options);
+    }
+    FormatErrorsToFile(errors, Location::Type::Binary);
+  }
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2c.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2c.cc
new file mode 100644 (file)
index 0000000..896841a
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * 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 <cassert>
+#include <cinttypes>
+#include <cstdio>
+#include <cstdlib>
+
+#include "src/apply-names.h"
+#include "src/binary-reader.h"
+#include "src/binary-reader-ir.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/generate-names.h"
+#include "src/ir.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-lexer.h"
+
+#include "src/c-writer.h"
+
+using namespace wabt;
+
+static int s_verbose;
+static std::string s_infile;
+static std::string s_outfile;
+static Features s_features;
+static WriteCOptions s_write_c_options;
+static bool s_read_debug_names = true;
+static std::unique_ptr<FileStream> s_log_stream;
+
+static const char s_description[] =
+R"(  Read a file in the WebAssembly binary format, and convert it to
+  a C source file and header.
+
+examples:
+  # parse binary file test.wasm and write test.c and test.h
+  $ wasm2c test.wasm -o test.c
+
+  # parse test.wasm, write test.c and test.h, but ignore the debug names, if any
+  $ wasm2c test.wasm --no-debug-names -o test.c
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wasm2c", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+  });
+  parser.AddOption(
+      'o', "output", "FILENAME",
+      "Output file for the generated C source file, by default use stdout",
+      [](const char* argument) {
+        s_outfile = argument;
+        ConvertBackslashToSlash(&s_outfile);
+      });
+  s_features.AddOptions(&parser);
+  parser.AddOption("no-debug-names", "Ignore debug names in the binary file",
+                   []() { s_read_debug_names = false; });
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) {
+                       s_infile = argument;
+                       ConvertBackslashToSlash(&s_infile);
+                     });
+  parser.Parse(argc, argv);
+
+  // TODO(binji): currently wasm2c doesn't support any non-default feature
+  // flags.
+  bool any_non_default_feature = false;
+#define WABT_FEATURE(variable, flag, default_, help) \
+  any_non_default_feature |= (s_features.variable##_enabled() != default_);
+#include "src/feature.def"
+#undef WABT_FEATURE
+
+  if (any_non_default_feature) {
+    fprintf(stderr, "wasm2c currently support only default feature flags.\n");
+    exit(1);
+  }
+}
+
+// TODO(binji): copied from binary-writer-spec.cc, probably should share.
+static string_view strip_extension(string_view s) {
+  string_view ext = s.substr(s.find_last_of('.'));
+  string_view result = s;
+
+  if (ext == ".c")
+    result.remove_suffix(ext.length());
+  return result;
+}
+
+int ProgramMain(int argc, char** argv) {
+  Result result;
+
+  InitStdio();
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  result = ReadFile(s_infile.c_str(), &file_data);
+  if (Succeeded(result)) {
+    Errors errors;
+    Module module;
+    const bool kStopOnFirstError = true;
+    const bool kFailOnCustomSectionError = true;
+    ReadBinaryOptions options(s_features, s_log_stream.get(),
+                              s_read_debug_names, kStopOnFirstError,
+                              kFailOnCustomSectionError);
+    result = ReadBinaryIr(s_infile.c_str(), file_data.data(), file_data.size(),
+                          options, &errors, &module);
+    if (Succeeded(result)) {
+      if (Succeeded(result)) {
+        ValidateOptions options(s_features);
+        result = ValidateModule(&module, &errors, options);
+        result |= GenerateNames(&module);
+      }
+
+      if (Succeeded(result)) {
+        /* TODO(binji): This shouldn't fail; if a name can't be applied
+         * (because the index is invalid, say) it should just be skipped. */
+        Result dummy_result = ApplyNames(&module);
+        WABT_USE(dummy_result);
+      }
+
+      if (Succeeded(result)) {
+        if (!s_outfile.empty()) {
+          std::string header_name =
+              strip_extension(s_outfile).to_string() + ".h";
+          FileStream c_stream(s_outfile.c_str());
+          FileStream h_stream(header_name);
+          result = WriteC(&c_stream, &h_stream, header_name.c_str(), &module,
+                          s_write_c_options);
+        } else {
+          FileStream stream(stdout);
+          result =
+              WriteC(&stream, &stream, "wasm.h", &module, s_write_c_options);
+        }
+      }
+    }
+    FormatErrorsToFile(errors, Location::Type::Binary);
+  }
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
+
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat-fuzz.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat-fuzz.cc
new file mode 100644 (file)
index 0000000..1318ef6
--- /dev/null
@@ -0,0 +1,30 @@
+// Copyright 2019 Google LLC
+//
+// 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 file is copied from the oss-fuzz project:
+//
+// https://github.com/google/oss-fuzz/blob/master/projects/wabt/wasm2wat_fuzzer.cc
+
+#include "src/binary-reader-ir.h"
+#include "src/binary-reader.h"
+#include "src/common.h"
+#include "src/ir.h"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  wabt::ReadBinaryOptions options;
+  wabt::Errors errors;
+  wabt::Module module;
+  wabt::ReadBinaryIr("dummy filename", data, size, options, &errors, &module);
+  return 0;
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wasm2wat.cc
new file mode 100644 (file)
index 0000000..58e8984
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * 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 <cassert>
+#include <cinttypes>
+#include <cstdio>
+#include <cstdlib>
+
+#include "src/apply-names.h"
+#include "src/binary-reader.h"
+#include "src/binary-reader-ir.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/generate-names.h"
+#include "src/ir.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-lexer.h"
+#include "src/wat-writer.h"
+
+using namespace wabt;
+
+static int s_verbose;
+static std::string s_infile;
+static std::string s_outfile;
+static Features s_features;
+static WriteWatOptions s_write_wat_options;
+static bool s_generate_names = false;
+static bool s_read_debug_names = true;
+static bool s_fail_on_custom_section_error = true;
+static std::unique_ptr<FileStream> s_log_stream;
+static bool s_validate = true;
+
+static const char s_description[] =
+R"(  Read a file in the WebAssembly binary format, and convert it to
+  the WebAssembly text format.
+
+examples:
+  # parse binary file test.wasm and write text file test.wast
+  $ wasm2wat test.wasm -o test.wat
+
+  # parse test.wasm, write test.wat, but ignore the debug names, if any
+  $ wasm2wat test.wasm --no-debug-names -o test.wat
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wasm2wat", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+  });
+  parser.AddOption(
+      'o', "output", "FILENAME",
+      "Output file for the generated wast file, by default use stdout",
+      [](const char* argument) {
+        s_outfile = argument;
+        ConvertBackslashToSlash(&s_outfile);
+      });
+  parser.AddOption('f', "fold-exprs", "Write folded expressions where possible",
+                   []() { s_write_wat_options.fold_exprs = true; });
+  s_features.AddOptions(&parser);
+  parser.AddOption("inline-exports", "Write all exports inline",
+                   []() { s_write_wat_options.inline_export = true; });
+  parser.AddOption("inline-imports", "Write all imports inline",
+                   []() { s_write_wat_options.inline_import = true; });
+  parser.AddOption("no-debug-names", "Ignore debug names in the binary file",
+                   []() { s_read_debug_names = false; });
+  parser.AddOption("ignore-custom-section-errors",
+                   "Ignore errors in custom sections",
+                   []() { s_fail_on_custom_section_error = false; });
+  parser.AddOption(
+      "generate-names",
+      "Give auto-generated names to non-named functions, types, etc.",
+      []() { s_generate_names = true; });
+  parser.AddOption("no-check", "Don't check for invalid modules",
+                   []() { s_validate = false; });
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) {
+                       s_infile = argument;
+                       ConvertBackslashToSlash(&s_infile);
+                     });
+  parser.Parse(argc, argv);
+}
+
+int ProgramMain(int argc, char** argv) {
+  Result result;
+
+  InitStdio();
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  result = ReadFile(s_infile.c_str(), &file_data);
+  if (Succeeded(result)) {
+    Errors errors;
+    Module module;
+    const bool kStopOnFirstError = true;
+    ReadBinaryOptions options(s_features, s_log_stream.get(),
+                              s_read_debug_names, kStopOnFirstError,
+                              s_fail_on_custom_section_error);
+    result = ReadBinaryIr(s_infile.c_str(), file_data.data(), file_data.size(),
+                          options, &errors, &module);
+    if (Succeeded(result)) {
+      if (Succeeded(result) && s_validate) {
+        ValidateOptions options(s_features);
+        result = ValidateModule(&module, &errors, options);
+      }
+
+      if (s_generate_names) {
+        result = GenerateNames(&module);
+      }
+
+      if (Succeeded(result)) {
+        /* TODO(binji): This shouldn't fail; if a name can't be applied
+         * (because the index is invalid, say) it should just be skipped. */
+        Result dummy_result = ApplyNames(&module);
+        WABT_USE(dummy_result);
+      }
+
+      if (Succeeded(result)) {
+        FileStream stream(!s_outfile.empty() ? FileStream(s_outfile)
+                                             : FileStream(stdout));
+        result = WriteWat(&stream, &module, s_write_wat_options);
+      }
+    }
+    FormatErrorsToFile(errors, Location::Type::Binary);
+  }
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wast2json.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wast2json.cc
new file mode 100644 (file)
index 0000000..a5c9a47
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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 <cassert>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+
+#include "config.h"
+
+#include "src/binary-writer.h"
+#include "src/binary-writer-spec.h"
+#include "src/common.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/filenames.h"
+#include "src/ir.h"
+#include "src/option-parser.h"
+#include "src/resolve-names.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-parser.h"
+
+using namespace wabt;
+
+static const char* s_infile;
+static std::string s_outfile;
+static int s_verbose;
+static WriteBinaryOptions s_write_binary_options;
+static bool s_validate = true;
+static bool s_debug_parsing;
+static Features s_features;
+
+static std::unique_ptr<FileStream> s_log_stream;
+
+static const char s_description[] =
+R"(  read a file in the wasm spec test format, check it for errors, and
+  convert it to a JSON file and associated wasm binary files.
+
+examples:
+  # parse spec-test.wast, and write files to spec-test.json. Modules are
+  # written to spec-test.0.wasm, spec-test.1.wasm, etc.
+  $ wast2json spec-test.wast -o spec-test.json
+)";
+
+static void ParseOptions(int argc, char* argv[]) {
+  OptionParser parser("wast2json", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+  });
+  parser.AddOption("debug-parser", "Turn on debugging the parser of wast files",
+                   []() { s_debug_parsing = true; });
+  s_features.AddOptions(&parser);
+  parser.AddOption('o', "output", "FILE", "output JSON file",
+                   [](const char* argument) { s_outfile = argument; });
+  parser.AddOption(
+      'r', "relocatable",
+      "Create a relocatable wasm binary (suitable for linking with e.g. lld)",
+      []() { s_write_binary_options.relocatable = true; });
+  parser.AddOption(
+      "no-canonicalize-leb128s",
+      "Write all LEB128 sizes as 5-bytes instead of their minimal size",
+      []() { s_write_binary_options.canonicalize_lebs = false; });
+  parser.AddOption("debug-names",
+                   "Write debug names to the generated binary file",
+                   []() { s_write_binary_options.write_debug_names = true; });
+  parser.AddOption("no-check", "Don't check for invalid modules",
+                   []() { s_validate = false; });
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) { s_infile = argument; });
+
+  parser.Parse(argc, argv);
+}
+
+static std::string DefaultOuputName(string_view input_name) {
+  // Strip existing extension and add .json
+  std::string result(StripExtension(GetBasename(input_name)));
+  result += ".json";
+
+  return result;
+}
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  Result result = ReadFile(s_infile, &file_data);
+  std::unique_ptr<WastLexer> lexer = WastLexer::CreateBufferLexer(
+      s_infile, file_data.data(), file_data.size());
+  if (Failed(result)) {
+    WABT_FATAL("unable to read file: %s\n", s_infile);
+  }
+
+  Errors errors;
+  std::unique_ptr<Script> script;
+  WastParseOptions parse_wast_options(s_features);
+  result = ParseWastScript(lexer.get(), &script, &errors, &parse_wast_options);
+
+  if (Succeeded(result) && s_validate) {
+    ValidateOptions options(s_features);
+    result = ValidateScript(script.get(), &errors, options);
+  }
+
+  if (Succeeded(result)) {
+    if (s_outfile.empty()) {
+      s_outfile = DefaultOuputName(s_infile);
+    }
+
+    std::vector<FilenameMemoryStreamPair> module_streams;
+    MemoryStream json_stream;
+
+    std::string output_basename = StripExtension(s_outfile).to_string();
+    s_write_binary_options.features = s_features;
+    result = WriteBinarySpecScript(&json_stream, script.get(), s_infile,
+                                   output_basename, s_write_binary_options,
+                                   &module_streams, s_log_stream.get());
+
+    if (Succeeded(result)) {
+      result = json_stream.WriteToFile(s_outfile);
+    }
+
+    if (Succeeded(result)) {
+      for (auto iter = module_streams.begin(); iter != module_streams.end();
+           ++iter) {
+        result = iter->stream->WriteToFile(iter->filename);
+        if (!Succeeded(result)) {
+          break;
+        }
+      }
+    }
+  }
+
+  auto line_finder = lexer->MakeLineFinder();
+  FormatErrorsToFile(errors, Location::Type::Text, line_finder.get());
+
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat-desugar.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat-desugar.cc
new file mode 100644 (file)
index 0000000..cc6a2cb
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * 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 <cassert>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdio>
+#include <cstdlib>
+
+#include "config.h"
+
+#include "src/apply-names.h"
+#include "src/common.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/generate-names.h"
+#include "src/ir.h"
+#include "src/option-parser.h"
+#include "src/stream.h"
+#include "src/wast-parser.h"
+#include "src/wat-writer.h"
+
+using namespace wabt;
+
+static const char* s_infile;
+static const char* s_outfile;
+static WriteWatOptions s_write_wat_options;
+static bool s_generate_names;
+static bool s_debug_parsing;
+static Features s_features;
+
+static const char s_description[] =
+R"(  read a file in the wasm s-expression format and format it.
+
+examples:
+  # write output to stdout
+  $ wat-desugar test.wat
+
+  # write output to test2.wat
+  $ wat-desugar test.wat -o test2.wat
+
+  # generate names for indexed variables
+  $ wat-desugar --generate-names test.wat
+)";
+
+static void ParseOptions(int argc, char** argv) {
+  OptionParser parser("wat-desugar", s_description);
+
+  parser.AddOption('o', "output", "FILE", "Output file for the formatted file",
+                   [](const char* argument) { s_outfile = argument; });
+  parser.AddOption("debug-parser", "Turn on debugging the parser of wat files",
+                   []() { s_debug_parsing = true; });
+  parser.AddOption('f', "fold-exprs", "Write folded expressions where possible",
+                   []() { s_write_wat_options.fold_exprs = true; });
+  parser.AddOption("inline-exports", "Write all exports inline",
+                   []() { s_write_wat_options.inline_export = true; });
+  parser.AddOption("inline-imports", "Write all imports inline",
+                   []() { s_write_wat_options.inline_import = true; });
+  s_features.AddOptions(&parser);
+  parser.AddOption(
+      "generate-names",
+      "Give auto-generated names to non-named functions, types, etc.",
+      []() { s_generate_names = true; });
+
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) { s_infile = argument; });
+  parser.Parse(argc, argv);
+}
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  Result result = ReadFile(s_infile, &file_data);
+  if (Failed(result)) {
+    WABT_FATAL("unable to read %s\n", s_infile);
+  }
+
+  std::unique_ptr<WastLexer> lexer(WastLexer::CreateBufferLexer(
+      s_infile, file_data.data(), file_data.size()));
+
+  Errors errors;
+  std::unique_ptr<Script> script;
+  WastParseOptions parse_wast_options(s_features);
+  result = ParseWastScript(lexer.get(), &script, &errors, &parse_wast_options);
+  auto line_finder = lexer->MakeLineFinder();
+  FormatErrorsToFile(errors, Location::Type::Text);
+
+  if (Succeeded(result)) {
+    Module* module = script->GetFirstModule();
+    if (!module) {
+      WABT_FATAL("no module in file.\n");
+    }
+
+    if (s_generate_names) {
+      result = GenerateNames(module);
+    }
+
+    if (Succeeded(result)) {
+      result = ApplyNames(module);
+    }
+
+    if (Succeeded(result)) {
+      FileStream stream(s_outfile ? FileStream(s_outfile) : FileStream(stdout));
+      result = WriteWat(&stream, module, s_write_wat_options);
+    }
+  }
+
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat2wasm.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tools/wat2wasm.cc
new file mode 100644 (file)
index 0000000..f77dad2
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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 <cassert>
+#include <cstdarg>
+#include <cstdint>
+#include <cstdlib>
+#include <cstdio>
+#include <string>
+
+#include "config.h"
+
+#include "src/binary-writer.h"
+#include "src/common.h"
+#include "src/error-formatter.h"
+#include "src/feature.h"
+#include "src/filenames.h"
+#include "src/ir.h"
+#include "src/option-parser.h"
+#include "src/resolve-names.h"
+#include "src/stream.h"
+#include "src/validator.h"
+#include "src/wast-parser.h"
+
+using namespace wabt;
+
+static const char* s_infile;
+static std::string s_outfile;
+static bool s_dump_module;
+static int s_verbose;
+static WriteBinaryOptions s_write_binary_options;
+static bool s_validate = true;
+static bool s_debug_parsing;
+static Features s_features;
+
+static std::unique_ptr<FileStream> s_log_stream;
+
+static const char s_description[] =
+R"(  read a file in the wasm text format, check it for errors, and
+  convert it to the wasm binary format.
+
+examples:
+  # parse and typecheck test.wat
+  $ wat2wasm test.wat
+
+  # parse test.wat and write to binary file test.wasm
+  $ wat2wasm test.wat -o test.wasm
+
+  # parse spec-test.wast, and write verbose output to stdout (including
+  # the meaning of every byte)
+  $ wat2wasm spec-test.wast -v
+)";
+
+static void ParseOptions(int argc, char* argv[]) {
+  OptionParser parser("wat2wasm", s_description);
+
+  parser.AddOption('v', "verbose", "Use multiple times for more info", []() {
+    s_verbose++;
+    s_log_stream = FileStream::CreateStderr();
+  });
+  parser.AddOption("debug-parser", "Turn on debugging the parser of wat files",
+                   []() { s_debug_parsing = true; });
+  parser.AddOption('d', "dump-module",
+                   "Print a hexdump of the module to stdout",
+                   []() { s_dump_module = true; });
+  s_features.AddOptions(&parser);
+  parser.AddOption('o', "output", "FILE", "output wasm binary file",
+                   [](const char* argument) { s_outfile = argument; });
+  parser.AddOption(
+      'r', "relocatable",
+      "Create a relocatable wasm binary (suitable for linking with e.g. lld)",
+      []() { s_write_binary_options.relocatable = true; });
+  parser.AddOption(
+      "no-canonicalize-leb128s",
+      "Write all LEB128 sizes as 5-bytes instead of their minimal size",
+      []() { s_write_binary_options.canonicalize_lebs = false; });
+  parser.AddOption("debug-names",
+                   "Write debug names to the generated binary file",
+                   []() { s_write_binary_options.write_debug_names = true; });
+  parser.AddOption("no-check", "Don't check for invalid modules",
+                   []() { s_validate = false; });
+  parser.AddArgument("filename", OptionParser::ArgumentCount::One,
+                     [](const char* argument) { s_infile = argument; });
+
+  parser.Parse(argc, argv);
+}
+
+static void WriteBufferToFile(string_view filename,
+                              const OutputBuffer& buffer) {
+  if (s_dump_module) {
+    std::unique_ptr<FileStream> stream = FileStream::CreateStdout();
+    if (s_verbose) {
+      stream->Writef(";; dump\n");
+    }
+    if (!buffer.data.empty()) {
+      stream->WriteMemoryDump(buffer.data.data(), buffer.data.size());
+    }
+  }
+
+  buffer.WriteToFile(filename);
+}
+
+static std::string DefaultOuputName(string_view input_name) {
+  // Strip existing extension and add .wasm
+  std::string result(StripExtension(GetBasename(input_name)));
+  result += kWasmExtension;
+
+  return result;
+}
+
+int ProgramMain(int argc, char** argv) {
+  InitStdio();
+
+  ParseOptions(argc, argv);
+
+  std::vector<uint8_t> file_data;
+  Result result = ReadFile(s_infile, &file_data);
+  std::unique_ptr<WastLexer> lexer = WastLexer::CreateBufferLexer(
+      s_infile, file_data.data(), file_data.size());
+  if (Failed(result)) {
+    WABT_FATAL("unable to read file: %s\n", s_infile);
+  }
+
+  Errors errors;
+  std::unique_ptr<Module> module;
+  WastParseOptions parse_wast_options(s_features);
+  result = ParseWatModule(lexer.get(), &module, &errors, &parse_wast_options);
+
+  if (Succeeded(result) && s_validate) {
+    ValidateOptions options(s_features);
+    result = ValidateModule(module.get(), &errors, options);
+  }
+
+  if (Succeeded(result)) {
+    MemoryStream stream(s_log_stream.get());
+    s_write_binary_options.features = s_features;
+    result = WriteBinaryModule(&stream, module.get(), s_write_binary_options);
+
+    if (Succeeded(result)) {
+      if (s_outfile.empty()) {
+        s_outfile = DefaultOuputName(s_infile);
+      }
+      WriteBufferToFile(s_outfile.c_str(), stream.output_buffer());
+    }
+  }
+
+  auto line_finder = lexer->MakeLineFinder();
+  FormatErrorsToFile(errors, Location::Type::Text, line_finder.get());
+
+  return result != Result::Ok;
+}
+
+int main(int argc, char** argv) {
+  WABT_TRY
+  return ProgramMain(argc, argv);
+  WABT_CATCH_BAD_ALLOC_AND_EXIT
+}
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.cc
new file mode 100644 (file)
index 0000000..3208acd
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+#define WABT_TRACING 1
+#include "src/tracing.h"
+
+namespace {
+
+size_t indent = 0;
+const char* indent_text = "  ";
+
+void Fill() {
+  for (size_t i = 0; i < indent; ++i)
+    fputs(indent_text, stderr);
+}
+
+void Indent() {
+  Fill();
+  ++indent;
+}
+
+void Dedent() {
+  if (indent) {
+    --indent;
+  }
+  Fill();
+}
+
+}  // end of anonymous namespace
+
+namespace wabt {
+
+// static
+
+TraceScope::TraceScope(const char* method) : method_(method) {
+  PrintEnter(method);
+  PrintNewline();
+}
+
+TraceScope::~TraceScope() {
+  Dedent();
+  fputs("<- ", stderr);
+  fputs(method_, stderr);
+  fputc('\n', stderr);
+}
+
+void TraceScope::PrintEnter(const char* method) {
+  Indent();
+  fputs("-> ", stderr);
+  fputs(method, stderr);
+  fputs("(", stderr);
+}
+
+void TraceScope::PrintNewline() {
+  fputs(")\n", stderr);
+}
+
+}  // end of namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/tracing.h
new file mode 100644 (file)
index 0000000..86daf63
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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_TRACING_H_
+#define WABT_TRACING_H_
+
+// Provides a simple tracing class that automatically generates enter/exit
+// messages using the scope of the instance.
+//
+// It also assumes that this file is only included in .cc files.
+// Immediately before the inclusion of this file, there is a define of
+// for WABT_TRACING, defining whether tracing should be compiled in for
+// that source file.
+
+#ifndef WABT_TRACING
+#define WABT_TRACING 0
+#endif
+
+#include "src/common.h"
+
+namespace wabt {
+
+#if WABT_TRACING
+
+// Scoped class that automatically prints enter("->") and exit("<-")
+// lines, indented by trace level.
+struct TraceScope {
+  WABT_DISALLOW_COPY_AND_ASSIGN(TraceScope);
+  TraceScope() = delete;
+  TraceScope(const char* method);
+  template <typename... Args>
+  TraceScope(const char* method, const char* format, Args&&... args)
+      : method_(method) {
+    PrintEnter(method);
+    fprintf(stderr, format, std::forward<Args>(args)...);
+    PrintNewline();
+  }
+  ~TraceScope();
+
+ private:
+  const char* method_;
+  void PrintEnter(const char* method);
+  void PrintNewline();
+};
+
+#define WABT_TRACE(method_name) TraceScope _func_(#method_name)
+
+#define WABT_TRACE_ARGS(method_name, format, ...) \
+  TraceScope _func_(#method_name, format, __VA_ARGS__)
+
+#else
+
+#define WABT_TRACE(method)
+#define WABT_TRACE_ARGS(method_name, format, ...)
+
+#endif
+
+}  // end namespace wabt
+
+#endif  // WABT_TRACING_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.cc
new file mode 100644 (file)
index 0000000..6d560f3
--- /dev/null
@@ -0,0 +1,915 @@
+/*
+ * 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/type-checker.h"
+
+#include <cinttypes>
+
+namespace wabt {
+
+namespace {
+
+std::string TypesToString(const TypeVector& types,
+                          const char* prefix = nullptr) {
+  std::string result = "[";
+  if (prefix) {
+    result += prefix;
+  }
+
+  for (size_t i = 0; i < types.size(); ++i) {
+    result += types[i].GetName();
+    if (i < types.size() - 1) {
+      result += ", ";
+    }
+  }
+  result += "]";
+  return result;
+}
+
+}  // end anonymous namespace
+
+TypeChecker::Label::Label(LabelType label_type,
+                          const TypeVector& param_types,
+                          const TypeVector& result_types,
+                          size_t limit)
+    : label_type(label_type),
+      param_types(param_types),
+      result_types(result_types),
+      type_stack_limit(limit),
+      unreachable(false) {}
+
+void TypeChecker::PrintError(const char* fmt, ...) {
+  if (error_callback_) {
+    WABT_SNPRINTF_ALLOCA(buffer, length, fmt);
+    error_callback_(buffer);
+  }
+}
+
+Result TypeChecker::GetLabel(Index depth, Label** out_label) {
+  if (depth >= label_stack_.size()) {
+    assert(label_stack_.size() > 0);
+    PrintError("invalid depth: %" PRIindex " (max %" PRIzd ")", depth,
+               label_stack_.size() - 1);
+    *out_label = nullptr;
+    return Result::Error;
+  }
+  *out_label = &label_stack_[label_stack_.size() - depth - 1];
+  return Result::Ok;
+}
+
+Result TypeChecker::GetRethrowLabel(Index depth, Label** out_label) {
+  if (Failed(GetLabel(depth, out_label))) {
+    return Result::Error;
+  }
+
+  if ((*out_label)->label_type == LabelType::Catch) {
+    return Result::Ok;
+  }
+
+  std::string candidates;
+  for (Index idx = 0; idx < label_stack_.size(); idx++) {
+    LabelType type = label_stack_[label_stack_.size() - idx - 1].label_type;
+    if (type == LabelType::Catch) {
+      if (!candidates.empty()) {
+        candidates.append(", ");
+      }
+      candidates.append(std::to_string(idx));
+    }
+  }
+
+  if (candidates.empty()) {
+    PrintError("rethrow not in try catch block");
+  } else {
+    PrintError("invalid rethrow depth: %" PRIindex " (catches: %s)", depth,
+               candidates.c_str());
+  }
+  *out_label = nullptr;
+  return Result::Error;
+}
+
+Result TypeChecker::TopLabel(Label** out_label) {
+  return GetLabel(0, out_label);
+}
+
+bool TypeChecker::IsUnreachable() {
+  Label* label;
+  if (Failed(TopLabel(&label))) {
+    return true;
+  }
+  return label->unreachable;
+}
+
+void TypeChecker::ResetTypeStackToLabel(Label* label) {
+  type_stack_.resize(label->type_stack_limit);
+}
+
+Result TypeChecker::SetUnreachable() {
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  label->unreachable = true;
+  ResetTypeStackToLabel(label);
+  return Result::Ok;
+}
+
+void TypeChecker::PushLabel(LabelType label_type,
+                            const TypeVector& param_types,
+                            const TypeVector& result_types) {
+  label_stack_.emplace_back(label_type, param_types, result_types,
+                            type_stack_.size());
+}
+
+Result TypeChecker::PopLabel() {
+  label_stack_.pop_back();
+  return Result::Ok;
+}
+
+Result TypeChecker::CheckLabelType(Label* label, LabelType label_type) {
+  return label->label_type == label_type ? Result::Ok : Result::Error;
+}
+
+Result TypeChecker::Check2LabelTypes(Label* label,
+                                     LabelType label_type1,
+                                     LabelType label_type2) {
+  return label->label_type == label_type1 ||
+         label->label_type == label_type2 ? Result::Ok : Result::Error;
+}
+
+Result TypeChecker::GetThisFunctionLabel(Label** label) {
+  return GetLabel(label_stack_.size() - 1, label);
+}
+
+Result TypeChecker::PeekType(Index depth, Type* out_type) {
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+
+  if (label->type_stack_limit + depth >= type_stack_.size()) {
+    *out_type = Type::Any;
+    return label->unreachable ? Result::Ok : Result::Error;
+  }
+  *out_type = type_stack_[type_stack_.size() - depth - 1];
+  return Result::Ok;
+}
+
+Result TypeChecker::PeekAndCheckType(Index depth, Type expected) {
+  Type actual = Type::Any;
+  Result result = PeekType(depth, &actual);
+  return result | CheckType(actual, expected);
+}
+
+Result TypeChecker::DropTypes(size_t drop_count) {
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  if (label->type_stack_limit + drop_count > type_stack_.size()) {
+    ResetTypeStackToLabel(label);
+    return label->unreachable ? Result::Ok : Result::Error;
+  }
+  type_stack_.erase(type_stack_.end() - drop_count, type_stack_.end());
+  return Result::Ok;
+}
+
+void TypeChecker::PushType(Type type) {
+  if (type != Type::Void) {
+    type_stack_.push_back(type);
+  }
+}
+
+void TypeChecker::PushTypes(const TypeVector& types) {
+  for (Type type : types) {
+    PushType(type);
+  }
+}
+
+Result TypeChecker::CheckTypeStackEnd(const char* desc) {
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  Result result = (type_stack_.size() == label->type_stack_limit)
+                      ? Result::Ok
+                      : Result::Error;
+  PrintStackIfFailed(result, desc);
+  return result;
+}
+
+Result TypeChecker::CheckType(Type actual, Type expected) {
+  if (expected == Type::Any || actual == Type::Any) {
+    return Result::Ok;
+  }
+  if (actual != expected) {
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
+Result TypeChecker::CheckTypes(const TypeVector& actual,
+                               const TypeVector& expected) {
+  if (actual.size() != expected.size()) {
+    return Result::Error;
+  } else {
+    Result result = Result::Ok;
+    for (size_t i = 0; i < actual.size(); i++)
+      result |= CheckType(actual[i], expected[i]);
+    return result;
+  }
+}
+
+Result TypeChecker::CheckSignature(const TypeVector& sig, const char* desc) {
+  Result result = Result::Ok;
+  for (size_t i = 0; i < sig.size(); ++i) {
+    result |= PeekAndCheckType(sig.size() - i - 1, sig[i]);
+  }
+  PrintStackIfFailed(result, desc, sig);
+  return result;
+}
+
+Result TypeChecker::CheckReturnSignature(const TypeVector& actual,
+                                         const TypeVector& expected,
+                                         const char* desc) {
+  Result result = CheckTypes(actual, expected);
+  if (Failed(result)) {
+    PrintError("return signatures have inconsistent types: expected %s, got %s",
+               TypesToString(expected).c_str(), TypesToString(actual).c_str());
+  }
+  return result;
+}
+
+Result TypeChecker::PopAndCheckSignature(const TypeVector& sig,
+                                         const char* desc) {
+  Result result = CheckSignature(sig, desc);
+  result |= DropTypes(sig.size());
+  return result;
+}
+
+Result TypeChecker::PopAndCheckCall(const TypeVector& param_types,
+                                    const TypeVector& result_types,
+                                    const char* desc) {
+  Result result = CheckSignature(param_types, desc);
+  result |= DropTypes(param_types.size());
+  PushTypes(result_types);
+  return result;
+}
+
+Result TypeChecker::PopAndCheck1Type(Type expected, const char* desc) {
+  Result result = Result::Ok;
+  result |= PeekAndCheckType(0, expected);
+  PrintStackIfFailed(result, desc, expected);
+  result |= DropTypes(1);
+  return result;
+}
+
+Result TypeChecker::PopAndCheck2Types(Type expected1,
+                                      Type expected2,
+                                      const char* desc) {
+  Result result = Result::Ok;
+  result |= PeekAndCheckType(0, expected2);
+  result |= PeekAndCheckType(1, expected1);
+  PrintStackIfFailed(result, desc, expected1, expected2);
+  result |= DropTypes(2);
+  return result;
+}
+
+Result TypeChecker::PopAndCheck3Types(Type expected1,
+                                      Type expected2,
+                                      Type expected3,
+                                      const char* desc) {
+  Result result = Result::Ok;
+  result |= PeekAndCheckType(0, expected3);
+  result |= PeekAndCheckType(1, expected2);
+  result |= PeekAndCheckType(2, expected1);
+  PrintStackIfFailed(result, desc, expected1, expected2, expected3);
+  result |= DropTypes(3);
+  return result;
+}
+
+Result TypeChecker::CheckOpcode1(Opcode opcode,
+                                 const Limits* limits,
+                                 bool has_address_operands) {
+  Result result =
+      PopAndCheck1Type(opcode.GetMemoryParam(
+                           opcode.GetParamType1(), limits,
+                           has_address_operands || opcode.GetMemorySize() != 0),
+                       opcode.GetName());
+  PushType(has_address_operands
+               ? opcode.GetMemoryParam(opcode.GetResultType(), limits, true)
+               : opcode.GetResultType());
+  return result;
+}
+
+Result TypeChecker::CheckOpcode2(Opcode opcode, const Limits* limits) {
+  Result result =
+      PopAndCheck2Types(opcode.GetMemoryParam(opcode.GetParamType1(), limits,
+                                              opcode.GetMemorySize() != 0),
+                        opcode.GetParamType2(), opcode.GetName());
+  PushType(opcode.GetResultType());
+  return result;
+}
+
+Result TypeChecker::CheckOpcode3(Opcode opcode,
+                                 const Limits* limits1,
+                                 const Limits* limits2,
+                                 const Limits* limits3) {
+  bool has_address_operands = limits1 || limits2 || limits3;
+  Result result =
+      PopAndCheck3Types(opcode.GetMemoryParam(opcode.GetParamType1(), limits1,
+                                              has_address_operands),
+                        opcode.GetMemoryParam(opcode.GetParamType2(), limits2,
+                                              has_address_operands),
+                        opcode.GetMemoryParam(opcode.GetParamType3(), limits3,
+                                              has_address_operands),
+                        opcode.GetName());
+  PushType(opcode.GetResultType());
+  return result;
+}
+
+void TypeChecker::PrintStackIfFailed(Result result,
+                                     const char* desc,
+                                     const TypeVector& expected) {
+  if (Succeeded(result)) {
+    return;
+  }
+
+  size_t limit = 0;
+  Label* label;
+  if (Succeeded(TopLabel(&label))) {
+    limit = label->type_stack_limit;
+  }
+
+  TypeVector actual;
+  size_t max_depth = type_stack_.size() - limit;
+
+  // In general we want to print as many values of the actual stack as were
+  // expected. However, if the stack was expected to be empty, we should
+  // print some amount of the actual stack.
+  size_t actual_size;
+  if (expected.size() == 0) {
+    // Don't print too many elements if the stack is really deep.
+    const size_t kMaxActualStackToPrint = 4;
+    actual_size = std::min(kMaxActualStackToPrint, max_depth);
+  } else {
+    actual_size = std::min(expected.size(), max_depth);
+  }
+
+  bool incomplete_actual_stack = actual_size != max_depth;
+
+  for (size_t i = 0; i < actual_size; ++i) {
+    Type type;
+    Result result = PeekType(actual_size - i - 1, &type);
+    WABT_USE(result);
+    assert(Succeeded(result));
+    actual.push_back(type);
+  }
+
+  std::string message = "type mismatch in ";
+  message += desc;
+  message += ", expected ";
+  message += TypesToString(expected);
+  message += " but got ";
+  message += TypesToString(actual, incomplete_actual_stack ? "... " : nullptr);
+
+  PrintError("%s", message.c_str());
+}
+
+Result TypeChecker::BeginFunction(const TypeVector& sig) {
+  type_stack_.clear();
+  label_stack_.clear();
+  PushLabel(LabelType::Func, TypeVector(), sig);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnAtomicLoad(Opcode opcode, const Limits& limits) {
+  return CheckOpcode1(opcode, &limits);
+}
+
+Result TypeChecker::OnAtomicStore(Opcode opcode, const Limits& limits) {
+  return CheckOpcode2(opcode, &limits);
+}
+
+Result TypeChecker::OnAtomicRmw(Opcode opcode, const Limits& limits) {
+  return CheckOpcode2(opcode, &limits);
+}
+
+Result TypeChecker::OnAtomicRmwCmpxchg(Opcode opcode, const Limits& limits) {
+  return CheckOpcode3(opcode, &limits);
+}
+
+Result TypeChecker::OnAtomicWait(Opcode opcode, const Limits& limits) {
+  return CheckOpcode3(opcode, &limits);
+}
+
+Result TypeChecker::OnAtomicFence(uint32_t consistency_model) {
+  return Result::Ok;
+}
+
+Result TypeChecker::OnAtomicNotify(Opcode opcode, const Limits& limits) {
+  return CheckOpcode2(opcode, &limits);
+}
+
+Result TypeChecker::OnBinary(Opcode opcode) {
+  return CheckOpcode2(opcode);
+}
+
+Result TypeChecker::OnBlock(const TypeVector& param_types,
+                            const TypeVector& result_types) {
+  Result result = PopAndCheckSignature(param_types, "block");
+  PushLabel(LabelType::Block, param_types, result_types);
+  PushTypes(param_types);
+  return result;
+}
+
+Result TypeChecker::OnBr(Index depth) {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(GetLabel(depth, &label));
+  result |= CheckSignature(label->br_types(), "br");
+  CHECK_RESULT(SetUnreachable());
+  return result;
+}
+
+Result TypeChecker::OnBrIf(Index depth) {
+  Result result = PopAndCheck1Type(Type::I32, "br_if");
+  Label* label;
+  CHECK_RESULT(GetLabel(depth, &label));
+  result |= PopAndCheckSignature(label->br_types(), "br_if");
+  PushTypes(label->br_types());
+  return result;
+}
+
+Result TypeChecker::BeginBrTable() {
+  br_table_sig_ = nullptr;
+  return PopAndCheck1Type(Type::I32, "br_table");
+}
+
+Result TypeChecker::OnBrTableTarget(Index depth) {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(GetLabel(depth, &label));
+  TypeVector& label_sig = label->br_types();
+  result |= CheckSignature(label_sig, "br_table");
+
+  // Make sure this label's signature is consistent with the previous labels'
+  // signatures.
+  if (br_table_sig_ == nullptr) {
+    br_table_sig_ = &label_sig;
+  } else {
+    if (*br_table_sig_ != label_sig) {
+      result |= Result::Error;
+      PrintError("br_table labels have inconsistent types: expected %s, got %s",
+                 TypesToString(*br_table_sig_).c_str(),
+                 TypesToString(label_sig).c_str());
+    }
+  }
+
+  return result;
+}
+
+Result TypeChecker::EndBrTable() {
+  return SetUnreachable();
+}
+
+Result TypeChecker::OnCall(const TypeVector& param_types,
+                           const TypeVector& result_types) {
+  return PopAndCheckCall(param_types, result_types, "call");
+}
+
+Result TypeChecker::OnCallIndirect(const TypeVector& param_types,
+                                   const TypeVector& result_types) {
+  Result result = PopAndCheck1Type(Type::I32, "call_indirect");
+  result |= PopAndCheckCall(param_types, result_types, "call_indirect");
+  return result;
+}
+
+Result TypeChecker::OnReturnCall(const TypeVector& param_types,
+                                 const TypeVector& result_types) {
+  Result result = PopAndCheckSignature(param_types, "return_call");
+  Label* func_label;
+  CHECK_RESULT(GetThisFunctionLabel(&func_label));
+  result |= CheckReturnSignature(result_types, func_label->result_types,
+                                 "return_call");
+
+  CHECK_RESULT(SetUnreachable());
+  return result;
+}
+
+Result TypeChecker::OnReturnCallIndirect(const TypeVector& param_types,
+                                         const TypeVector& result_types) {
+  Result result = PopAndCheck1Type(Type::I32, "return_call_indirect");
+
+  result |= PopAndCheckSignature(param_types, "return_call_indirect");
+  Label* func_label;
+  CHECK_RESULT(GetThisFunctionLabel(&func_label));
+  result |= CheckReturnSignature(result_types, func_label->result_types,
+                                 "return_call_indirect");
+
+  CHECK_RESULT(SetUnreachable());
+  return result;
+}
+
+Result TypeChecker::OnCompare(Opcode opcode) {
+  return CheckOpcode2(opcode);
+}
+
+Result TypeChecker::OnCatch(const TypeVector& sig) {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  result |= Check2LabelTypes(label, LabelType::Try, LabelType::Catch);
+  result |= PopAndCheckSignature(label->result_types, "try block");
+  result |= CheckTypeStackEnd("try block");
+  ResetTypeStackToLabel(label);
+  label->label_type = LabelType::Catch;
+  label->unreachable = false;
+  PushTypes(sig);
+  return result;
+}
+
+Result TypeChecker::OnConst(Type type) {
+  PushType(type);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnConvert(Opcode opcode) {
+  return CheckOpcode1(opcode);
+}
+
+Result TypeChecker::OnDelegate(Index depth) {
+  Result result = Result::Ok;
+  Label* label;
+  // Delegate starts counting after the current try, as the delegate
+  // instruction is not actually in the try block.
+  CHECK_RESULT(GetLabel(depth + 1, &label));
+  if (Failed(Check2LabelTypes(label, LabelType::Try, LabelType::Func))) {
+    PrintError("try-delegate must target a try block or function label");
+    result = Result::Error;
+  }
+
+  Label* try_label;
+  CHECK_RESULT(TopLabel(&try_label));
+  result |= CheckLabelType(try_label, LabelType::Try);
+  result |= PopAndCheckSignature(try_label->result_types, "try block");
+  result |= CheckTypeStackEnd("try block");
+  ResetTypeStackToLabel(try_label);
+
+  // Since an end instruction does not follow a delegate, we push
+  // the block results here and pop the label.
+  PushTypes(try_label->result_types);
+  PopLabel();
+  return result;
+}
+
+Result TypeChecker::OnDrop() {
+  Result result = Result::Ok;
+  result |= DropTypes(1);
+  PrintStackIfFailed(result, "drop", Type::Any);
+  return result;
+}
+
+Result TypeChecker::OnElse() {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  result |= CheckLabelType(label, LabelType::If);
+  result |= PopAndCheckSignature(label->result_types, "if true branch");
+  result |= CheckTypeStackEnd("if true branch");
+  ResetTypeStackToLabel(label);
+  PushTypes(label->param_types);
+  label->label_type = LabelType::Else;
+  label->unreachable = false;
+  return result;
+}
+
+Result TypeChecker::OnEnd(Label* label,
+                          TypeVector& check_type,
+                          const char* sig_desc,
+                          const char* end_desc) {
+  Result result = Result::Ok;
+  result |= PopAndCheckSignature(check_type, sig_desc);
+  result |= CheckTypeStackEnd(end_desc);
+  ResetTypeStackToLabel(label);
+  PushTypes(label->result_types);
+  PopLabel();
+  return result;
+}
+
+Result TypeChecker::OnEnd() {
+  Result result = Result::Ok;
+  static const char* s_label_type_name[] = {
+      "function", "block", "loop", "if", "if false branch", "try",
+      "try catch", "try unwind"};
+  WABT_STATIC_ASSERT(WABT_ARRAY_SIZE(s_label_type_name) == kLabelTypeCount);
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  assert(static_cast<int>(label->label_type) < kLabelTypeCount);
+  if (label->label_type == LabelType::If) {
+    // An if without an else will just pass the params through, so the result
+    // types must be the same as the param types. It has the same behavior as
+    // an empty else block.
+    CHECK_RESULT(OnElse());
+  }
+
+  const char* desc = s_label_type_name[static_cast<int>(label->label_type)];
+  if (label->label_type == LabelType::Unwind) {
+    // Unwind is unusual in that it always unwinds the control stack at the end,
+    // and therefore the return type of the unwind expressions are not the same
+    // as the block return type.
+    TypeVector empty;
+    result |= OnEnd(label, empty, desc, desc);
+  } else {
+    result |= OnEnd(label, label->result_types, desc, desc);
+  }
+  return result;
+}
+
+Result TypeChecker::OnIf(const TypeVector& param_types,
+                         const TypeVector& result_types) {
+  Result result = PopAndCheck1Type(Type::I32, "if");
+  result |= PopAndCheckSignature(param_types, "if");
+  PushLabel(LabelType::If, param_types, result_types);
+  PushTypes(param_types);
+  return result;
+}
+
+Result TypeChecker::OnGlobalGet(Type type) {
+  PushType(type);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnGlobalSet(Type type) {
+  return PopAndCheck1Type(type, "global.set");
+}
+
+Result TypeChecker::OnLoad(Opcode opcode, const Limits& limits) {
+  return CheckOpcode1(opcode, &limits);
+}
+
+Result TypeChecker::OnLocalGet(Type type) {
+  PushType(type);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnLocalSet(Type type) {
+  return PopAndCheck1Type(type, "local.set");
+}
+
+Result TypeChecker::OnLocalTee(Type type) {
+  Result result = Result::Ok;
+  result |= PopAndCheck1Type(type, "local.tee");
+  PushType(type);
+  return result;
+}
+
+Result TypeChecker::OnLoop(const TypeVector& param_types,
+                           const TypeVector& result_types) {
+  Result result = PopAndCheckSignature(param_types, "loop");
+  PushLabel(LabelType::Loop, param_types, result_types);
+  PushTypes(param_types);
+  return result;
+}
+
+Result TypeChecker::OnMemoryCopy(const Limits& limits) {
+  return CheckOpcode3(Opcode::MemoryCopy, &limits, &limits, &limits);
+}
+
+Result TypeChecker::OnDataDrop(uint32_t segment) {
+  return Result::Ok;
+}
+
+Result TypeChecker::OnMemoryFill(const Limits& limits) {
+  return CheckOpcode3(Opcode::MemoryFill, &limits, nullptr, &limits);
+}
+
+Result TypeChecker::OnMemoryGrow(const Limits& limits) {
+  return CheckOpcode1(Opcode::MemoryGrow, &limits, true);
+}
+
+Result TypeChecker::OnMemoryInit(uint32_t segment, const Limits& limits) {
+  return CheckOpcode3(Opcode::MemoryInit, &limits);
+}
+
+Result TypeChecker::OnMemorySize(const Limits& limits) {
+  PushType(limits.is_64 ? Type::I64 : Type::I32);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnTableCopy() {
+  return CheckOpcode3(Opcode::TableCopy);
+}
+
+Result TypeChecker::OnElemDrop(uint32_t segment) {
+  return Result::Ok;
+}
+
+Result TypeChecker::OnTableInit(uint32_t table, uint32_t segment) {
+  return CheckOpcode3(Opcode::TableInit);
+}
+
+Result TypeChecker::OnTableGet(Type elem_type) {
+  Result result = PopAndCheck1Type(Type::I32, "table.get");
+  PushType(elem_type);
+  return result;
+}
+
+Result TypeChecker::OnTableSet(Type elem_type) {
+  return PopAndCheck2Types(Type::I32, elem_type, "table.set");
+}
+
+Result TypeChecker::OnTableGrow(Type elem_type) {
+  Result result = PopAndCheck2Types(elem_type, Type::I32, "table.grow");
+  PushType(Type::I32);
+  return result;
+}
+
+Result TypeChecker::OnTableSize() {
+  PushType(Type::I32);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnTableFill(Type elem_type) {
+  return PopAndCheck3Types(Type::I32, elem_type, Type::I32, "table.fill");
+}
+
+Result TypeChecker::OnRefFuncExpr(Index) {
+  PushType(Type::FuncRef);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnRefNullExpr(Type type) {
+  PushType(type);
+  return Result::Ok;
+}
+
+Result TypeChecker::OnRefIsNullExpr() {
+  Type type;
+  Result result = PeekType(0, &type);
+  if (!type.IsRef()) {
+    TypeVector actual;
+    if (Succeeded(result)) {
+      actual.push_back(type);
+    }
+    std::string message =
+        "type mismatch in ref.is_null, expected reference but got " +
+        TypesToString(actual);
+    PrintError("%s", message.c_str());
+    result = Result::Error;
+  }
+  result |= DropTypes(1);
+  PushType(Type::I32);
+  return result;
+}
+
+Result TypeChecker::OnRethrow(Index depth) {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(GetRethrowLabel(depth, &label));
+  CHECK_RESULT(SetUnreachable());
+  return result;
+}
+
+Result TypeChecker::OnThrow(const TypeVector& sig) {
+  Result result = Result::Ok;
+  result |= PopAndCheckSignature(sig, "throw");
+  CHECK_RESULT(SetUnreachable());
+  return result;
+}
+
+Result TypeChecker::OnReturn() {
+  Result result = Result::Ok;
+  Label* func_label;
+  CHECK_RESULT(GetThisFunctionLabel(&func_label));
+  result |= PopAndCheckSignature(func_label->result_types, "return");
+  CHECK_RESULT(SetUnreachable());
+  return result;
+}
+
+Result TypeChecker::OnSelect(const TypeVector& expected) {
+  Result result = Result::Ok;
+  Type type1 = Type::Any;
+  Type type2 = Type::Any;
+  Type result_type = Type::Any;
+  result |= PeekAndCheckType(0, Type::I32);
+  result |= PeekType(1, &type1);
+  result |= PeekType(2, &type2);
+  if (expected.empty()) {
+    if (type1.IsRef() || type2.IsRef()) {
+      result = Result::Error;
+    } else {
+      result |= CheckType(type1, type2);
+      result_type = type1;
+    }
+  } else {
+    assert(expected.size() == 1);
+    result |= CheckType(type1, expected[0]);
+    result |= CheckType(type2, expected[0]);
+  }
+  PrintStackIfFailed(result, "select", result_type, result_type, Type::I32);
+  result |= DropTypes(3);
+  PushType(result_type);
+  return result;
+}
+
+Result TypeChecker::OnStore(Opcode opcode, const Limits& limits) {
+  return CheckOpcode2(opcode, &limits);
+}
+
+Result TypeChecker::OnTry(const TypeVector& param_types,
+                          const TypeVector& result_types) {
+  Result result = PopAndCheckSignature(param_types, "try");
+  PushLabel(LabelType::Try, param_types, result_types);
+  PushTypes(param_types);
+  return result;
+}
+
+Result TypeChecker::OnUnary(Opcode opcode) {
+  return CheckOpcode1(opcode);
+}
+
+Result TypeChecker::OnTernary(Opcode opcode) {
+  return CheckOpcode3(opcode);
+}
+
+Result TypeChecker::OnSimdLaneOp(Opcode opcode, uint64_t lane_idx) {
+  Result result = Result::Ok;
+  uint32_t lane_count = opcode.GetSimdLaneCount();
+  if (lane_idx >= lane_count) {
+    PrintError("lane index must be less than %d (got %" PRIu64 ")", lane_count,
+               lane_idx);
+    result = Result::Error;
+  }
+
+  switch (opcode) {
+    case Opcode::I8X16ExtractLaneS:
+    case Opcode::I8X16ExtractLaneU:
+    case Opcode::I16X8ExtractLaneS:
+    case Opcode::I16X8ExtractLaneU:
+    case Opcode::I32X4ExtractLane:
+    case Opcode::F32X4ExtractLane:
+    case Opcode::I64X2ExtractLane:
+    case Opcode::F64X2ExtractLane:
+      result |= CheckOpcode1(opcode);
+      break;
+    case Opcode::I8X16ReplaceLane:
+    case Opcode::I16X8ReplaceLane:
+    case Opcode::I32X4ReplaceLane:
+    case Opcode::F32X4ReplaceLane:
+    case Opcode::I64X2ReplaceLane:
+    case Opcode::F64X2ReplaceLane:
+      result |= CheckOpcode2(opcode);
+      break;
+    default:
+      WABT_UNREACHABLE;
+  }
+  return result;
+}
+
+Result TypeChecker::OnSimdShuffleOp(Opcode opcode, v128 lane_idx) {
+  Result result = Result::Ok;
+  uint8_t simd_data[16];
+  memcpy(simd_data, &lane_idx, 16);
+  for (int i = 0; i < 16; i++) {
+    if (simd_data[i] >= 32) {
+      PrintError("lane index must be less than 32 (got %d)", simd_data[i]);
+      result = Result::Error;
+    }
+  }
+
+  result |= CheckOpcode2(opcode);
+  return result;
+}
+
+Result TypeChecker::OnUnreachable() {
+  return SetUnreachable();
+}
+
+Result TypeChecker::OnUnwind() {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  result |= CheckLabelType(label, LabelType::Try);
+  result |= PopAndCheckSignature(label->result_types, "try block");
+  result |= CheckTypeStackEnd("try block");
+  ResetTypeStackToLabel(label);
+  label->label_type = LabelType::Unwind;
+  label->unreachable = false;
+  return result;
+}
+
+Result TypeChecker::EndFunction() {
+  Result result = Result::Ok;
+  Label* label;
+  CHECK_RESULT(TopLabel(&label));
+  result |= CheckLabelType(label, LabelType::Func);
+  result |= OnEnd(label, label->result_types, "implicit return", "function");
+  return result;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type-checker.h
new file mode 100644 (file)
index 0000000..4673067
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ * 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_TYPE_CHECKER_H_
+#define WABT_TYPE_CHECKER_H_
+
+#include <functional>
+#include <vector>
+
+#include "src/common.h"
+#include "src/feature.h"
+#include "src/opcode.h"
+
+namespace wabt {
+
+class TypeChecker {
+ public:
+  typedef std::function<void(const char* msg)> ErrorCallback;
+
+  struct Label {
+    Label(LabelType,
+          const TypeVector& param_types,
+          const TypeVector& result_types,
+          size_t limit);
+
+    TypeVector& br_types() {
+      return label_type == LabelType::Loop ? param_types : result_types;
+    }
+
+    LabelType label_type;
+    TypeVector param_types;
+    TypeVector result_types;
+    size_t type_stack_limit;
+    bool unreachable;
+  };
+
+  explicit TypeChecker(const Features& features) : features_(features) {}
+
+  void set_error_callback(const ErrorCallback& error_callback) {
+    error_callback_ = error_callback;
+  }
+
+  size_t type_stack_size() const { return type_stack_.size(); }
+
+  bool IsUnreachable();
+  Result GetLabel(Index depth, Label** out_label);
+  Result GetRethrowLabel(Index depth, Label** out_label);
+
+  Result BeginFunction(const TypeVector& sig);
+  Result OnAtomicFence(uint32_t consistency_model);
+  Result OnAtomicLoad(Opcode, const Limits& limits);
+  Result OnAtomicNotify(Opcode, const Limits& limits);
+  Result OnAtomicStore(Opcode, const Limits& limits);
+  Result OnAtomicRmw(Opcode, const Limits& limits);
+  Result OnAtomicRmwCmpxchg(Opcode, const Limits& limits);
+  Result OnAtomicWait(Opcode, const Limits& limits);
+  Result OnBinary(Opcode);
+  Result OnBlock(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnBr(Index depth);
+  Result OnBrIf(Index depth);
+  Result BeginBrTable();
+  Result OnBrTableTarget(Index depth);
+  Result EndBrTable();
+  Result OnCall(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnCallIndirect(const TypeVector& param_types,
+                        const TypeVector& result_types);
+  Result OnReturnCall(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnReturnCallIndirect(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnCatch(const TypeVector& sig);
+  Result OnCompare(Opcode);
+  Result OnConst(Type);
+  Result OnConvert(Opcode);
+  Result OnDelegate(Index depth);
+  Result OnDrop();
+  Result OnElse();
+  Result OnEnd();
+  Result OnGlobalGet(Type);
+  Result OnGlobalSet(Type);
+  Result OnIf(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnLoad(Opcode, const Limits& limits);
+  Result OnLocalGet(Type);
+  Result OnLocalSet(Type);
+  Result OnLocalTee(Type);
+  Result OnLoop(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnMemoryCopy(const Limits& limits);
+  Result OnDataDrop(Index);
+  Result OnMemoryFill(const Limits& limits);
+  Result OnMemoryGrow(const Limits& limits);
+  Result OnMemoryInit(Index, const Limits& limits);
+  Result OnMemorySize(const Limits& limits);
+  Result OnTableCopy();
+  Result OnElemDrop(Index);
+  Result OnTableInit(Index, Index);
+  Result OnTableGet(Type elem_type);
+  Result OnTableSet(Type elem_type);
+  Result OnTableGrow(Type elem_type);
+  Result OnTableSize();
+  Result OnTableFill(Type elem_type);
+  Result OnRefFuncExpr(Index func_index);
+  Result OnRefNullExpr(Type type);
+  Result OnRefIsNullExpr();
+  Result OnRethrow(Index depth);
+  Result OnReturn();
+  Result OnSelect(const TypeVector& result_types);
+  Result OnSimdLaneOp(Opcode, uint64_t);
+  Result OnSimdShuffleOp(Opcode, v128);
+  Result OnStore(Opcode, const Limits& limits);
+  Result OnTernary(Opcode);
+  Result OnThrow(const TypeVector& sig);
+  Result OnTry(const TypeVector& param_types, const TypeVector& result_types);
+  Result OnUnary(Opcode);
+  Result OnUnreachable();
+  Result OnUnwind();
+  Result EndFunction();
+
+  static Result CheckType(Type actual, Type expected);
+
+ private:
+  void WABT_PRINTF_FORMAT(2, 3) PrintError(const char* fmt, ...);
+  Result TopLabel(Label** out_label);
+  void ResetTypeStackToLabel(Label* label);
+  Result SetUnreachable();
+  void PushLabel(LabelType label_type,
+                 const TypeVector& param_types,
+                 const TypeVector& result_types);
+  Result PopLabel();
+  Result CheckLabelType(Label* label, LabelType label_type);
+  Result Check2LabelTypes(Label* label, LabelType label_type1, LabelType label_type2);
+  Result GetThisFunctionLabel(Label **label);
+  Result PeekType(Index depth, Type* out_type);
+  Result PeekAndCheckType(Index depth, Type expected);
+  Result DropTypes(size_t drop_count);
+  void PushType(Type type);
+  void PushTypes(const TypeVector& types);
+  Result CheckTypeStackEnd(const char* desc);
+  Result CheckTypes(const TypeVector &actual, const TypeVector &expected);
+  Result CheckSignature(const TypeVector& sig, const char* desc);
+  Result CheckReturnSignature(const TypeVector& sig, const TypeVector &expected,const char *desc);
+  Result PopAndCheckSignature(const TypeVector& sig, const char* desc);
+  Result PopAndCheckCall(const TypeVector& param_types,
+                         const TypeVector& result_types,
+                         const char* desc);
+  Result PopAndCheck1Type(Type expected, const char* desc);
+  Result PopAndCheck2Types(Type expected1, Type expected2, const char* desc);
+  Result PopAndCheck3Types(Type expected1,
+                           Type expected2,
+                           Type expected3,
+                           const char* desc);
+  Result CheckOpcode1(Opcode opcode,
+                      const Limits* limits = nullptr,
+                      bool has_address_operands = false);
+  Result CheckOpcode2(Opcode opcode, const Limits* limits = nullptr);
+  Result CheckOpcode3(Opcode opcode,
+                      const Limits* limits1 = nullptr,
+                      const Limits* limits2 = nullptr,
+                      const Limits* limits3 = nullptr);
+  Result OnEnd(Label* label, TypeVector& check_type, const char* sig_desc, const char* end_desc);
+
+  template <typename... Args>
+  void PrintStackIfFailed(Result result, const char* desc, Args... args) {
+    // Minor optimization, check result before constructing the vector to pass
+    // to the other overload of PrintStackIfFailed.
+    if (Failed(result)) {
+      PrintStackIfFailed(result, desc, {args...});
+    }
+  }
+
+  void PrintStackIfFailed(Result, const char* desc, const TypeVector&);
+
+  ErrorCallback error_callback_;
+  TypeVector type_stack_;
+  std::vector<Label> label_stack_;
+  // Cache the expected br_table signature. It will be initialized to `nullptr`
+  // to represent "any".
+  TypeVector* br_table_sig_ = nullptr;
+  Features features_;
+};
+
+}  // namespace wabt
+
+#endif /* WABT_TYPE_CHECKER_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/type.h
new file mode 100644 (file)
index 0000000..cd383a1
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * 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_TYPE_H_
+#define WABT_TYPE_H_
+
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+#include "config.h"
+
+namespace wabt {
+
+class Type;
+
+using Index = uint32_t;
+using TypeVector = std::vector<Type>;
+
+class Type {
+ public:
+  // Matches binary format, do not change.
+  enum Enum : int32_t {
+    I32 = -0x01,        // 0x7f
+    I64 = -0x02,        // 0x7e
+    F32 = -0x03,        // 0x7d
+    F64 = -0x04,        // 0x7c
+    V128 = -0x05,       // 0x7b
+    I8 = -0x06,         // 0x7a  : packed-type only, used in gc and as v128 lane
+    I16 = -0x07,        // 0x79  : packed-type only, used in gc and as v128 lane
+    FuncRef = -0x10,    // 0x70
+    ExternRef = -0x11,  // 0x6f
+    Func = -0x20,       // 0x60
+    Struct = -0x21,     // 0x5f
+    Array = -0x22,      // 0x5e
+    Void = -0x40,       // 0x40
+    ___ = Void,         // Convenient for the opcode table in opcode.h
+
+    Any = 0,          // Not actually specified, but useful for type-checking
+    I8U = 4,   // Not actually specified, but used internally with load/store
+    I16U = 6,  // Not actually specified, but used internally with load/store
+    I32U = 7,  // Not actually specified, but used internally with load/store
+  };
+
+  Type() = default;  // Provided so Type can be member of a union.
+  Type(int32_t code) : enum_(static_cast<Enum>(code)) {}
+  Type(Enum e) : enum_(e) {}
+  operator Enum() const { return enum_; }
+
+  bool IsRef() const {
+    return enum_ == Type::ExternRef || enum_ == Type::FuncRef;
+  }
+
+  bool IsNullableRef() const {
+    // Currently all reftypes are nullable
+    return IsRef();
+  }
+
+  const char* GetName() const {
+    switch (enum_) {
+      case Type::I32:       return "i32";
+      case Type::I64:       return "i64";
+      case Type::F32:       return "f32";
+      case Type::F64:       return "f64";
+      case Type::V128:      return "v128";
+      case Type::I8:        return "i8";
+      case Type::I16:       return "i16";
+      case Type::FuncRef:   return "funcref";
+      case Type::Func:      return "func";
+      case Type::Void:      return "void";
+      case Type::Any:       return "any";
+      case Type::ExternRef: return "externref";
+      default:              return "<type_index>";
+    }
+  }
+
+  const char* GetRefKindName() const {
+    switch (enum_) {
+      case Type::FuncRef:   return "func";
+      case Type::ExternRef: return "extern";
+      case Type::Struct:    return "struct";
+      case Type::Array:     return "array";
+      default:              return "<invalid>";
+    }
+  }
+
+  // Functions for handling types that are an index into the type section.
+  // These are always positive integers. They occur in the binary format in
+  // block signatures, e.g.
+  //
+  //   (block (result i32 i64) ...)
+  //
+  // is encoded as
+  //
+  //   (type $T (func (result i32 i64)))
+  //   ...
+  //   (block (type $T) ...)
+  // 
+  bool IsIndex() const { return static_cast<int32_t>(enum_) >= 0; }
+
+  Index GetIndex() const {
+    assert(IsIndex());
+    return static_cast<Index>(enum_);
+  }
+
+  TypeVector GetInlineVector() const {
+    assert(!IsIndex());
+    switch (enum_) {
+      case Type::Void:
+        return TypeVector();
+
+      case Type::I32:
+      case Type::I64:
+      case Type::F32:
+      case Type::F64:
+      case Type::V128:
+      case Type::FuncRef:
+      case Type::ExternRef:
+        return TypeVector(this, this + 1);
+
+      default:
+        WABT_UNREACHABLE;
+    }
+  }
+
+ private:
+  Enum enum_;
+};
+
+}  // namespace wabt
+
+#endif  // WABT_TYPE_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.cc
new file mode 100644 (file)
index 0000000..37a8df0
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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/utf8.h"
+
+#include <cstdint>
+
+namespace wabt {
+
+namespace {
+
+const int s_utf8_length[256] = {
+ // 0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x00
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x10
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x20
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x30
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x40
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x50
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x60
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  // 0x70
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0x80
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0x90
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xa0
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xb0
+    0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,  // 0xc0
+    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,  // 0xd0
+    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  // 0xe0
+    4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  // 0xf0
+};
+
+// Returns true if this is a valid continuation byte.
+bool IsCont(uint8_t c) {
+  return (c & 0xc0) == 0x80;
+}
+
+}  // end anonymous namespace
+
+bool IsValidUtf8(const char* s, size_t s_length) {
+  const uint8_t* p = reinterpret_cast<const uint8_t*>(s);
+  const uint8_t* end = p + s_length;
+  while (p < end) {
+    uint8_t cu0 = *p;
+    int length = s_utf8_length[cu0];
+    if (p + length > end) {
+      return false;
+    }
+
+    switch (length) {
+      case 0:
+        return false;
+
+      case 1:
+        p++;
+        break;
+
+      case 2:
+        p++;
+        if (!IsCont(*p++)) {
+          return false;
+        }
+        break;
+
+      case 3: {
+        p++;
+        uint8_t cu1 = *p++;
+        uint8_t cu2 = *p++;
+        if (!(IsCont(cu1) && IsCont(cu2)) ||
+            (cu0 == 0xe0 && cu1 < 0xa0) ||  // Overlong encoding.
+            (cu0 == 0xed && cu1 >= 0xa0))   // UTF-16 surrogate halves.
+          return false;
+        break;
+      }
+
+      case 4: {
+        p++;
+        uint8_t cu1 = *p++;
+        uint8_t cu2 = *p++;
+        uint8_t cu3 = *p++;
+        if (!(IsCont(cu1) && IsCont(cu2) && IsCont(cu3)) ||
+            (cu0 == 0xf0 && cu1 < 0x90) ||  // Overlong encoding.
+            (cu0 == 0xf4 && cu1 >= 0x90))   // Code point >= 0x11000.
+          return false;
+        break;
+      }
+    }
+  }
+  return true;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/utf8.h
new file mode 100644 (file)
index 0000000..c378035
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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_UTF8_H_
+#define WABT_UTF8_H_
+
+#include <stdlib.h>
+
+namespace wabt {
+
+bool IsValidUtf8(const char* s, size_t length);
+
+}  // namespace wabt
+
+#endif  // WABT_UTF8_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.cc
new file mode 100644 (file)
index 0000000..4733954
--- /dev/null
@@ -0,0 +1,1043 @@
+/*
+ * 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/validator.h"
+
+#include <cassert>
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdio>
+
+#include "config.h"
+
+#include "src/binary-reader.h"
+#include "src/cast.h"
+#include "src/expr-visitor.h"
+#include "src/ir.h"
+#include "src/shared-validator.h"
+
+namespace wabt {
+
+namespace {
+
+class ScriptValidator {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(ScriptValidator);
+  ScriptValidator(Errors*, const Script*, const ValidateOptions& options);
+
+  Result CheckScript();
+
+ private:
+  struct ActionResult {
+    enum class Kind {
+      Error,
+      Types,
+      Type,
+    } kind;
+
+    union {
+      const TypeVector* types;
+      Type type;
+    };
+  };
+
+  void WABT_PRINTF_FORMAT(3, 4)
+      PrintError(const Location* loc, const char* fmt, ...);
+  void CheckTypeIndex(const Location* loc,
+                      Type actual,
+                      Type expected,
+                      const char* desc,
+                      Index index,
+                      const char* index_kind);
+  void CheckResultTypes(const Location* loc,
+                        const TypeVector& actual,
+                        const TypeVector& expected,
+                        const char* desc);
+
+  const TypeVector* CheckInvoke(const InvokeAction* action);
+  Result CheckGet(const GetAction* action, Type* out_type);
+  ActionResult CheckAction(const Action* action);
+  void CheckCommand(const Command* command);
+
+  const ValidateOptions& options_;
+  Errors* errors_ = nullptr;
+  const Script* script_ = nullptr;
+
+  Result result_ = Result::Ok;
+};
+
+class Validator : public ExprVisitor::Delegate {
+ public:
+  Validator(Errors*, const Module* module, const ValidateOptions& options);
+
+  Result CheckModule();
+
+  Result OnBinaryExpr(BinaryExpr*) override;
+  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 OnCallIndirectExpr(CallIndirectExpr*) override;
+  Result OnCompareExpr(CompareExpr*) override;
+  Result OnConstExpr(ConstExpr*) override;
+  Result OnConvertExpr(ConvertExpr*) override;
+  Result OnDropExpr(DropExpr*) override;
+  Result OnGlobalGetExpr(GlobalGetExpr*) override;
+  Result OnGlobalSetExpr(GlobalSetExpr*) override;
+  Result BeginIfExpr(IfExpr*) override;
+  Result AfterIfTrueExpr(IfExpr*) override;
+  Result EndIfExpr(IfExpr*) override;
+  Result OnLoadExpr(LoadExpr*) override;
+  Result OnLocalGetExpr(LocalGetExpr*) override;
+  Result OnLocalSetExpr(LocalSetExpr*) override;
+  Result OnLocalTeeExpr(LocalTeeExpr*) override;
+  Result BeginLoopExpr(LoopExpr*) override;
+  Result EndLoopExpr(LoopExpr*) override;
+  Result OnMemoryCopyExpr(MemoryCopyExpr*) override;
+  Result OnDataDropExpr(DataDropExpr*) override;
+  Result OnMemoryFillExpr(MemoryFillExpr*) override;
+  Result OnMemoryGrowExpr(MemoryGrowExpr*) override;
+  Result OnMemoryInitExpr(MemoryInitExpr*) override;
+  Result OnMemorySizeExpr(MemorySizeExpr*) override;
+  Result OnTableCopyExpr(TableCopyExpr*) override;
+  Result OnElemDropExpr(ElemDropExpr*) 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 OnRefFuncExpr(RefFuncExpr*) override;
+  Result OnRefNullExpr(RefNullExpr*) override;
+  Result OnRefIsNullExpr(RefIsNullExpr*) override;
+  Result OnNopExpr(NopExpr*) override;
+  Result OnReturnExpr(ReturnExpr*) override;
+  Result OnReturnCallExpr(ReturnCallExpr*) override;
+  Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override;
+  Result OnSelectExpr(SelectExpr*) override;
+  Result OnStoreExpr(StoreExpr*) override;
+  Result OnUnaryExpr(UnaryExpr*) override;
+  Result OnUnreachableExpr(UnreachableExpr*) override;
+  Result BeginTryExpr(TryExpr*) override;
+  Result OnCatchExpr(TryExpr*, Catch*) override;
+  Result OnUnwindExpr(TryExpr*) override;
+  Result OnDelegateExpr(TryExpr*) override;
+  Result EndTryExpr(TryExpr*) override;
+  Result OnThrowExpr(ThrowExpr*) override;
+  Result OnRethrowExpr(RethrowExpr*) override;
+  Result OnAtomicWaitExpr(AtomicWaitExpr*) override;
+  Result OnAtomicFenceExpr(AtomicFenceExpr*) override;
+  Result OnAtomicNotifyExpr(AtomicNotifyExpr*) override;
+  Result OnAtomicLoadExpr(AtomicLoadExpr*) override;
+  Result OnAtomicStoreExpr(AtomicStoreExpr*) override;
+  Result OnAtomicRmwExpr(AtomicRmwExpr*) override;
+  Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) override;
+  Result OnTernaryExpr(TernaryExpr*) override;
+  Result OnSimdLaneOpExpr(SimdLaneOpExpr*) override;
+  Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) override;
+  Result OnLoadSplatExpr(LoadSplatExpr*) override;
+
+ private:
+  Type GetDeclarationType(const FuncDeclaration&);
+  Var GetFuncTypeIndex(const Location&, const FuncDeclaration&);
+
+  const ValidateOptions& options_;
+  Errors* errors_ = nullptr;
+  SharedValidator validator_;
+  const Module* current_module_ = nullptr;
+  Result result_ = Result::Ok;
+};
+
+ScriptValidator::ScriptValidator(Errors* errors,
+                                 const Script* script,
+                                 const ValidateOptions& options)
+    : options_(options), errors_(errors), script_(script) {}
+
+void ScriptValidator::PrintError(const Location* loc, const char* format, ...) {
+  result_ = Result::Error;
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  errors_->emplace_back(ErrorLevel::Error, *loc, buffer);
+}
+
+void ScriptValidator::CheckTypeIndex(const Location* loc,
+                                     Type actual,
+                                     Type expected,
+                                     const char* desc,
+                                     Index index,
+                                     const char* index_kind) {
+  if (Failed(TypeChecker::CheckType(actual, expected))) {
+    PrintError(loc,
+               "type mismatch for %s %" PRIindex " of %s. got %s, expected %s",
+               index_kind, index, desc, actual.GetName(), expected.GetName());
+  }
+}
+
+void ScriptValidator::CheckResultTypes(const Location* loc,
+                                       const TypeVector& actual,
+                                       const TypeVector& expected,
+                                       const char* desc) {
+  if (actual.size() == expected.size()) {
+    for (size_t i = 0; i < actual.size(); ++i) {
+      CheckTypeIndex(loc, actual[i], expected[i], desc, i, "result");
+    }
+  } else {
+    PrintError(loc, "expected %" PRIzd " results, got %" PRIzd, expected.size(),
+               actual.size());
+  }
+}
+
+Type Validator::GetDeclarationType(const FuncDeclaration& decl) {
+  if (decl.has_func_type) {
+    return Type(decl.type_var.index());
+  }
+  if (decl.sig.param_types.empty()) {
+    if (decl.sig.result_types.empty()) {
+      return Type::Void;
+    }
+    if (decl.sig.result_types.size() == 1) {
+      return decl.sig.result_types[0];
+    }
+  }
+  return Type(current_module_->GetFuncTypeIndex(decl));
+}
+
+Var Validator::GetFuncTypeIndex(const Location& default_loc,
+                                const FuncDeclaration& decl) {
+  if (decl.has_func_type) {
+    return decl.type_var;
+  }
+  return Var(current_module_->GetFuncTypeIndex(decl), default_loc);
+}
+
+Result Validator::OnBinaryExpr(BinaryExpr* expr) {
+  result_ |= validator_.OnBinary(expr->loc, expr->opcode);
+  return Result::Ok;
+}
+
+Result Validator::BeginBlockExpr(BlockExpr* expr) {
+  result_ |=
+      validator_.OnBlock(expr->loc, GetDeclarationType(expr->block.decl));
+  return Result::Ok;
+}
+
+Result Validator::EndBlockExpr(BlockExpr* expr) {
+  result_ |= validator_.OnEnd(expr->block.end_loc);
+  return Result::Ok;
+}
+
+Result Validator::OnBrExpr(BrExpr* expr) {
+  result_ |= validator_.OnBr(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnBrIfExpr(BrIfExpr* expr) {
+  result_ |= validator_.OnBrIf(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnBrTableExpr(BrTableExpr* expr) {
+  result_ |= validator_.BeginBrTable(expr->loc);
+  for (const Var& var : expr->targets) {
+    result_ |= validator_.OnBrTableTarget(expr->loc, var);
+  }
+  result_ |= validator_.OnBrTableTarget(expr->loc, expr->default_target);
+  result_ |= validator_.EndBrTable(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnCallExpr(CallExpr* expr) {
+  result_ |= validator_.OnCall(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnCallIndirectExpr(CallIndirectExpr* expr) {
+  result_ |= validator_.OnCallIndirect(
+      expr->loc, GetFuncTypeIndex(expr->loc, expr->decl), expr->table);
+  return Result::Ok;
+}
+
+Result Validator::OnCompareExpr(CompareExpr* expr) {
+  result_ |= validator_.OnCompare(expr->loc, expr->opcode);
+  return Result::Ok;
+}
+
+Result Validator::OnConstExpr(ConstExpr* expr) {
+  result_ |= validator_.OnConst(expr->loc, expr->const_.type());
+  return Result::Ok;
+}
+
+Result Validator::OnConvertExpr(ConvertExpr* expr) {
+  result_ |= validator_.OnConvert(expr->loc, expr->opcode);
+  return Result::Ok;
+}
+
+Result Validator::OnDropExpr(DropExpr* expr) {
+  result_ |= validator_.OnDrop(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnGlobalGetExpr(GlobalGetExpr* expr) {
+  result_ |= validator_.OnGlobalGet(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnGlobalSetExpr(GlobalSetExpr* expr) {
+  result_ |= validator_.OnGlobalSet(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::BeginIfExpr(IfExpr* expr) {
+  result_ |= validator_.OnIf(expr->loc, GetDeclarationType(expr->true_.decl));
+  return Result::Ok;
+}
+
+Result Validator::AfterIfTrueExpr(IfExpr* expr) {
+  if (!expr->false_.empty()) {
+    result_ |= validator_.OnElse(expr->true_.end_loc);
+  }
+  return Result::Ok;
+}
+
+Result Validator::EndIfExpr(IfExpr* expr) {
+  result_ |= validator_.OnEnd(expr->false_.empty() ? expr->true_.end_loc
+                                                   : expr->false_end_loc);
+  return Result::Ok;
+}
+
+Result Validator::OnLoadExpr(LoadExpr* expr) {
+  result_ |= validator_.OnLoad(expr->loc, expr->opcode,
+                               expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnLocalGetExpr(LocalGetExpr* expr) {
+  result_ |= validator_.OnLocalGet(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnLocalSetExpr(LocalSetExpr* expr) {
+  result_ |= validator_.OnLocalSet(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnLocalTeeExpr(LocalTeeExpr* expr) {
+  result_ |= validator_.OnLocalTee(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::BeginLoopExpr(LoopExpr* expr) {
+  result_ |= validator_.OnLoop(expr->loc, GetDeclarationType(expr->block.decl));
+  return Result::Ok;
+}
+
+Result Validator::EndLoopExpr(LoopExpr* expr) {
+  result_ |= validator_.OnEnd(expr->block.end_loc);
+  return Result::Ok;
+}
+
+Result Validator::OnMemoryCopyExpr(MemoryCopyExpr* expr) {
+  result_ |= validator_.OnMemoryCopy(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnDataDropExpr(DataDropExpr* expr) {
+  result_ |= validator_.OnDataDrop(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnMemoryFillExpr(MemoryFillExpr* expr) {
+  result_ |= validator_.OnMemoryFill(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnMemoryGrowExpr(MemoryGrowExpr* expr) {
+  result_ |= validator_.OnMemoryGrow(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnMemoryInitExpr(MemoryInitExpr* expr) {
+  result_ |= validator_.OnMemoryInit(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnMemorySizeExpr(MemorySizeExpr* expr) {
+  result_ |= validator_.OnMemorySize(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnTableCopyExpr(TableCopyExpr* expr) {
+  result_ |=
+      validator_.OnTableCopy(expr->loc, expr->dst_table, expr->src_table);
+  return Result::Ok;
+}
+
+Result Validator::OnElemDropExpr(ElemDropExpr* expr) {
+  result_ |= validator_.OnElemDrop(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnTableInitExpr(TableInitExpr* expr) {
+  result_ |=
+      validator_.OnTableInit(expr->loc, expr->segment_index, expr->table_index);
+  return Result::Ok;
+}
+
+Result Validator::OnTableGetExpr(TableGetExpr* expr) {
+  result_ |= validator_.OnTableGet(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnTableSetExpr(TableSetExpr* expr) {
+  result_ |= validator_.OnTableSet(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnTableGrowExpr(TableGrowExpr* expr) {
+  result_ |= validator_.OnTableGrow(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnTableSizeExpr(TableSizeExpr* expr) {
+  result_ |= validator_.OnTableSize(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnTableFillExpr(TableFillExpr* expr) {
+  result_ |= validator_.OnTableFill(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnRefFuncExpr(RefFuncExpr* expr) {
+  result_ |= validator_.OnRefFunc(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnRefNullExpr(RefNullExpr* expr) {
+  result_ |= validator_.OnRefNull(expr->loc, expr->type);
+  return Result::Ok;
+}
+
+Result Validator::OnRefIsNullExpr(RefIsNullExpr* expr) {
+  result_ |= validator_.OnRefIsNull(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnNopExpr(NopExpr* expr) {
+  result_ |= validator_.OnNop(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnReturnExpr(ReturnExpr* expr) {
+  result_ |= validator_.OnReturn(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnReturnCallExpr(ReturnCallExpr* expr) {
+  result_ |= validator_.OnReturnCall(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) {
+  result_ |= validator_.OnReturnCallIndirect(
+      expr->loc, GetFuncTypeIndex(expr->loc, expr->decl), expr->table);
+  return Result::Ok;
+}
+
+Result Validator::OnSelectExpr(SelectExpr* expr) {
+  result_ |= validator_.OnSelect(expr->loc, expr->result_type.size(),
+                                 expr->result_type.data());
+  // TODO: Existing behavior fails when select fails.
+#if 0
+  return Result::Ok;
+#else
+  return result_;
+#endif
+}
+
+Result Validator::OnStoreExpr(StoreExpr* expr) {
+  result_ |= validator_.OnStore(expr->loc, expr->opcode,
+                                expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnUnaryExpr(UnaryExpr* expr) {
+  result_ |= validator_.OnUnary(expr->loc, expr->opcode);
+  return Result::Ok;
+}
+
+Result Validator::OnUnreachableExpr(UnreachableExpr* expr) {
+  result_ |= validator_.OnUnreachable(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::BeginTryExpr(TryExpr* expr) {
+  result_ |= validator_.OnTry(expr->loc, GetDeclarationType(expr->block.decl));
+  return Result::Ok;
+}
+
+Result Validator::OnCatchExpr(TryExpr*, Catch* catch_) {
+  result_ |= validator_.OnCatch(catch_->loc, catch_->var,
+                                catch_->IsCatchAll());
+  return Result::Ok;
+}
+
+Result Validator::OnUnwindExpr(TryExpr* expr) {
+  result_ |= validator_.OnUnwind(expr->loc);
+  return Result::Ok;
+}
+
+Result Validator::OnDelegateExpr(TryExpr* expr) {
+  result_ |= validator_.OnDelegate(expr->loc, expr->delegate_target);
+  return Result::Ok;
+}
+
+Result Validator::EndTryExpr(TryExpr* expr) {
+  result_ |= validator_.OnEnd(expr->block.end_loc);
+  return Result::Ok;
+}
+
+Result Validator::OnThrowExpr(ThrowExpr* expr) {
+  result_ |= validator_.OnThrow(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnRethrowExpr(RethrowExpr* expr) {
+  result_ |= validator_.OnRethrow(expr->loc, expr->var);
+  return Result::Ok;
+}
+
+Result Validator::OnAtomicWaitExpr(AtomicWaitExpr* expr) {
+  result_ |= validator_.OnAtomicWait(expr->loc, expr->opcode,
+                                     expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnAtomicFenceExpr(AtomicFenceExpr* expr) {
+  result_ |= validator_.OnAtomicFence(expr->loc, expr->consistency_model);
+  return Result::Ok;
+}
+
+Result Validator::OnAtomicNotifyExpr(AtomicNotifyExpr* expr) {
+  result_ |= validator_.OnAtomicNotify(expr->loc, expr->opcode,
+                                       expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnAtomicLoadExpr(AtomicLoadExpr* expr) {
+  result_ |= validator_.OnAtomicLoad(expr->loc, expr->opcode,
+                                     expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnAtomicStoreExpr(AtomicStoreExpr* expr) {
+  result_ |= validator_.OnAtomicStore(expr->loc, expr->opcode,
+                                      expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnAtomicRmwExpr(AtomicRmwExpr* expr) {
+  result_ |= validator_.OnAtomicRmw(expr->loc, expr->opcode,
+                                    expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr* expr) {
+  result_ |= validator_.OnAtomicRmwCmpxchg(
+      expr->loc, expr->opcode, expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Result Validator::OnTernaryExpr(TernaryExpr* expr) {
+  result_ |= validator_.OnTernary(expr->loc, expr->opcode);
+  return Result::Ok;
+}
+
+Result Validator::OnSimdLaneOpExpr(SimdLaneOpExpr* expr) {
+  result_ |= validator_.OnSimdLaneOp(expr->loc, expr->opcode, expr->val);
+  return Result::Ok;
+}
+
+Result Validator::OnSimdShuffleOpExpr(SimdShuffleOpExpr* expr) {
+  result_ |= validator_.OnSimdShuffleOp(expr->loc, expr->opcode, expr->val);
+  return Result::Ok;
+}
+
+Result Validator::OnLoadSplatExpr(LoadSplatExpr* expr) {
+  result_ |= validator_.OnLoadSplat(expr->loc, expr->opcode,
+                                    expr->opcode.GetAlignment(expr->align));
+  return Result::Ok;
+}
+
+Validator::Validator(Errors* errors,
+                     const Module* module,
+                     const ValidateOptions& options)
+    : options_(options),
+      errors_(errors),
+      validator_(errors_, options_),
+      current_module_(module) {}
+
+Result Validator::CheckModule() {
+  const Module* module = current_module_;
+
+  // Type section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<TypeModuleField>(&field)) {
+      switch (f->type->kind()) {
+        case TypeEntryKind::Func: {
+          FuncType* func_type = cast<FuncType>(f->type.get());
+          result_ |= validator_.OnFuncType(field.loc,
+                                           func_type->sig.param_types.size(),
+                                           func_type->sig.param_types.data(),
+                                           func_type->sig.result_types.size(),
+                                           func_type->sig.result_types.data());
+          break;
+        }
+
+        case TypeEntryKind::Struct: {
+          StructType* struct_type = cast<StructType>(f->type.get());
+          TypeMutVector type_muts;
+          for (auto&& field : struct_type->fields) {
+            type_muts.push_back(TypeMut{field.type, field.mutable_});
+          }
+          result_ |= validator_.OnStructType(field.loc, type_muts.size(),
+                                             type_muts.data());
+          break;
+        }
+
+        case TypeEntryKind::Array: {
+          ArrayType* array_type = cast<ArrayType>(f->type.get());
+          result_ |= validator_.OnArrayType(
+              field.loc,
+              TypeMut{array_type->field.type, array_type->field.mutable_});
+          break;
+        }
+      }
+    }
+  }
+
+  // Import section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<ImportModuleField>(&field)) {
+      switch (f->import->kind()) {
+        case ExternalKind::Func: {
+          auto&& func = cast<FuncImport>(f->import.get())->func;
+          result_ |= validator_.OnFunction(
+              field.loc, GetFuncTypeIndex(field.loc, func.decl));
+          break;
+        }
+
+        case ExternalKind::Table: {
+          auto&& table = cast<TableImport>(f->import.get())->table;
+          result_ |=
+              validator_.OnTable(field.loc, table.elem_type, table.elem_limits);
+          break;
+        }
+
+        case ExternalKind::Memory: {
+          auto&& memory = cast<MemoryImport>(f->import.get())->memory;
+          result_ |= validator_.OnMemory(field.loc, memory.page_limits);
+          break;
+        }
+
+        case ExternalKind::Global: {
+          auto&& global = cast<GlobalImport>(f->import.get())->global;
+          result_ |= validator_.OnGlobalImport(field.loc, global.type,
+                                               global.mutable_);
+          break;
+        }
+
+        case ExternalKind::Event: {
+          auto&& event = cast<EventImport>(f->import.get())->event;
+          result_ |= validator_.OnEvent(
+              field.loc, GetFuncTypeIndex(field.loc, event.decl));
+          break;
+        }
+      }
+    }
+  }
+
+  // Func section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<FuncModuleField>(&field)) {
+      result_ |= validator_.OnFunction(
+          field.loc, GetFuncTypeIndex(field.loc, f->func.decl));
+    }
+  }
+
+  // Table section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<TableModuleField>(&field)) {
+      result_ |= validator_.OnTable(field.loc, f->table.elem_type,
+                                    f->table.elem_limits);
+    }
+  }
+
+  // Memory section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<MemoryModuleField>(&field)) {
+      result_ |= validator_.OnMemory(field.loc, f->memory.page_limits);
+    }
+  }
+
+  // Global section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<GlobalModuleField>(&field)) {
+      result_ |=
+          validator_.OnGlobal(field.loc, f->global.type, f->global.mutable_);
+
+      if (f->global.init_expr.size() == 1) {
+        const Expr* expr = &f->global.init_expr.front();
+
+        switch (expr->type()) {
+          case ExprType::Const:
+            result_ |= validator_.OnGlobalInitExpr_Const(
+                expr->loc, cast<ConstExpr>(expr)->const_.type());
+            break;
+
+          case ExprType::GlobalGet: {
+            Var var = cast<GlobalGetExpr>(expr)->var;
+            result_ |= validator_.OnGlobalInitExpr_GlobalGet(expr->loc, var);
+            break;
+          }
+
+          case ExprType::RefFunc:
+            result_ |= validator_.OnGlobalInitExpr_RefFunc(
+                expr->loc, cast<RefFuncExpr>(expr)->var);
+            break;
+
+          case ExprType::RefNull:
+            result_ |= validator_.OnGlobalInitExpr_RefNull(
+                expr->loc, cast<RefNullExpr>(expr)->type);
+            break;
+
+          default:
+            result_ |= validator_.OnGlobalInitExpr_Other(field.loc);
+            break;
+        }
+      } else {
+        result_ |= validator_.OnGlobalInitExpr_Other(field.loc);
+      }
+    }
+  }
+
+  // Event section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<EventModuleField>(&field)) {
+      result_ |= validator_.OnEvent(field.loc,
+                                    GetFuncTypeIndex(field.loc, f->event.decl));
+    }
+  }
+
+  // Export section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<ExportModuleField>(&field)) {
+      result_ |= validator_.OnExport(field.loc, f->export_.kind, f->export_.var,
+                                     f->export_.name);
+    }
+  }
+
+  // Start section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<StartModuleField>(&field)) {
+      result_ |= validator_.OnStart(field.loc, f->start);
+    }
+  }
+
+  // Elem segment section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<ElemSegmentModuleField>(&field)) {
+      result_ |= validator_.OnElemSegment(field.loc, f->elem_segment.table_var,
+                                          f->elem_segment.kind);
+
+      validator_.OnElemSegmentElemType(f->elem_segment.elem_type);
+
+      // Init expr.
+      if (f->elem_segment.offset.size() == 1) {
+        const Expr* expr = &f->elem_segment.offset.front();
+
+        switch (expr->type()) {
+          case ExprType::Const:
+            result_ |= validator_.OnElemSegmentInitExpr_Const(
+                expr->loc, cast<ConstExpr>(expr)->const_.type());
+            break;
+
+          case ExprType::GlobalGet: {
+            Var var = cast<GlobalGetExpr>(expr)->var;
+            result_ |=
+                validator_.OnElemSegmentInitExpr_GlobalGet(expr->loc, var);
+            break;
+          }
+
+          default:
+            result_ |= validator_.OnElemSegmentInitExpr_Other(field.loc);
+            break;
+        }
+      } else if (f->elem_segment.offset.size() > 1) {
+        result_ |= validator_.OnElemSegmentInitExpr_Other(field.loc);
+      }
+
+      // Element expr.
+      for (auto&& elem_expr : f->elem_segment.elem_exprs) {
+        switch (elem_expr.kind) {
+          case ElemExprKind::RefNull:
+            // TODO: better location?
+            result_ |= validator_.OnElemSegmentElemExpr_RefNull(field.loc,
+                                                                elem_expr.type);
+            break;
+
+          case ElemExprKind::RefFunc:
+            result_ |= validator_.OnElemSegmentElemExpr_RefFunc(
+                elem_expr.var.loc, elem_expr.var);
+            break;
+        }
+      }
+    }
+  }
+
+  // DataCount section.
+  validator_.OnDataCount(module->data_segments.size());
+
+  // Code section.
+  Index func_index = module->num_func_imports;
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<FuncModuleField>(&field)) {
+      result_ |= validator_.BeginFunctionBody(field.loc, func_index++);
+
+      for (auto&& decl : f->func.local_types.decls()) {
+        // TODO: Better location?
+        result_ |= validator_.OnLocalDecl(field.loc, decl.second, decl.first);
+      }
+
+      ExprVisitor visitor(this);
+      result_ |= visitor.VisitExprList(const_cast<ExprList&>(f->func.exprs));
+      result_ |= validator_.EndFunctionBody(field.loc);
+    }
+  }
+
+  // Data segment section.
+  for (const ModuleField& field : module->fields) {
+    if (auto* f = dyn_cast<DataSegmentModuleField>(&field)) {
+      result_ |= validator_.OnDataSegment(
+          field.loc, f->data_segment.memory_var, f->data_segment.kind);
+
+      // Init expr.
+      if (f->data_segment.offset.size() == 1) {
+        const Expr* expr = &f->data_segment.offset.front();
+
+        switch (expr->type()) {
+          case ExprType::Const:
+            result_ |= validator_.OnDataSegmentInitExpr_Const(
+                expr->loc, cast<ConstExpr>(expr)->const_.type());
+            break;
+
+          case ExprType::GlobalGet: {
+            Var var = cast<GlobalGetExpr>(expr)->var;
+            result_ |=
+                validator_.OnDataSegmentInitExpr_GlobalGet(expr->loc, var);
+            break;
+          }
+
+          default:
+            result_ |= validator_.OnDataSegmentInitExpr_Other(field.loc);
+            break;
+        }
+      } else if (f->data_segment.offset.size() > 1) {
+        result_ |= validator_.OnDataSegmentInitExpr_Other(field.loc);
+      }
+    }
+  }
+
+  result_ |= validator_.EndModule();
+
+  return result_;
+}
+
+// Returns the result type of the invoked function, checked by the caller;
+// returning nullptr means that another error occured first, so the result type
+// should be ignored.
+const TypeVector* ScriptValidator::CheckInvoke(const InvokeAction* action) {
+  const Module* module = script_->GetModule(action->module_var);
+  if (!module) {
+    PrintError(&action->loc, "unknown module");
+    return nullptr;
+  }
+
+  const Export* export_ = module->GetExport(action->name);
+  if (!export_) {
+    PrintError(&action->loc, "unknown function export \"%s\"",
+               action->name.c_str());
+    return nullptr;
+  }
+
+  const Func* func = module->GetFunc(export_->var);
+  if (!func) {
+    // This error will have already been reported, just skip it.
+    return nullptr;
+  }
+
+  size_t actual_args = action->args.size();
+  size_t expected_args = func->GetNumParams();
+  if (expected_args != actual_args) {
+    PrintError(&action->loc,
+               "too %s parameters to function. got %" PRIzd
+               ", expected %" PRIzd,
+               actual_args > expected_args ? "many" : "few", actual_args,
+               expected_args);
+    return nullptr;
+  }
+  for (size_t i = 0; i < actual_args; ++i) {
+    const Const* const_ = &action->args[i];
+    CheckTypeIndex(&const_->loc, const_->type(), func->GetParamType(i),
+                   "invoke", i, "argument");
+  }
+
+  return &func->decl.sig.result_types;
+}
+
+Result ScriptValidator::CheckGet(const GetAction* action, Type* out_type) {
+  const Module* module = script_->GetModule(action->module_var);
+  if (!module) {
+    PrintError(&action->loc, "unknown module");
+    return Result::Error;
+  }
+
+  const Export* export_ = module->GetExport(action->name);
+  if (!export_) {
+    PrintError(&action->loc, "unknown global export \"%s\"",
+               action->name.c_str());
+    return Result::Error;
+  }
+
+  const Global* global = module->GetGlobal(export_->var);
+  if (!global) {
+    // This error will have already been reported, just skip it.
+    return Result::Error;
+  }
+
+  *out_type = global->type;
+  return Result::Ok;
+}
+
+ScriptValidator::ActionResult ScriptValidator::CheckAction(
+    const Action* action) {
+  ActionResult result;
+  ZeroMemory(result);
+
+  switch (action->type()) {
+    case ActionType::Invoke:
+      result.types = CheckInvoke(cast<InvokeAction>(action));
+      result.kind =
+          result.types ? ActionResult::Kind::Types : ActionResult::Kind::Error;
+      break;
+
+    case ActionType::Get:
+      if (Succeeded(CheckGet(cast<GetAction>(action), &result.type))) {
+        result.kind = ActionResult::Kind::Type;
+      } else {
+        result.kind = ActionResult::Kind::Error;
+      }
+      break;
+  }
+
+  return result;
+}
+
+void ScriptValidator::CheckCommand(const Command* command) {
+  switch (command->type) {
+    case CommandType::Module: {
+      Validator module_validator(errors_, &cast<ModuleCommand>(command)->module,
+                                 options_);
+      module_validator.CheckModule();
+      break;
+    }
+
+    case CommandType::Action:
+      // Ignore result type.
+      CheckAction(cast<ActionCommand>(command)->action.get());
+      break;
+
+    case CommandType::Register:
+    case CommandType::AssertMalformed:
+    case CommandType::AssertInvalid:
+    case CommandType::AssertUnlinkable:
+    case CommandType::AssertUninstantiable:
+      // Ignore.
+      break;
+
+    case CommandType::AssertReturn: {
+      auto* assert_return_command = cast<AssertReturnCommand>(command);
+      const Action* action = assert_return_command->action.get();
+      ActionResult result = CheckAction(action);
+      // Here we take the concrete expected output types verify those actains
+      // the types that are the result of the action.
+      TypeVector actual_types;
+      for (auto ex : assert_return_command->expected) {
+        actual_types.push_back(ex.type());
+      }
+      switch (result.kind) {
+        case ActionResult::Kind::Types:
+          CheckResultTypes(&action->loc, actual_types, *result.types, "action");
+          break;
+
+        case ActionResult::Kind::Type:
+          CheckResultTypes(&action->loc, actual_types, {result.type}, "action");
+          break;
+
+        case ActionResult::Kind::Error:
+          // Error occurred, don't do any further checks.
+          break;
+      }
+      break;
+    }
+
+    case CommandType::AssertTrap:
+      // ignore result type.
+      CheckAction(cast<AssertTrapCommand>(command)->action.get());
+      break;
+    case CommandType::AssertExhaustion:
+      // ignore result type.
+      CheckAction(cast<AssertExhaustionCommand>(command)->action.get());
+      break;
+  }
+}
+
+Result ScriptValidator::CheckScript() {
+  for (const std::unique_ptr<Command>& command : script_->commands)
+    CheckCommand(command.get());
+  return result_;
+}
+
+}  // end anonymous namespace
+
+Result ValidateScript(const Script* script,
+                      Errors* errors,
+                      const ValidateOptions& options) {
+  ScriptValidator validator(errors, script, options);
+
+  return validator.CheckScript();
+}
+
+Result ValidateModule(const Module* module,
+                      Errors* errors,
+                      const ValidateOptions& options) {
+  Validator validator(errors, module, options);
+
+  return validator.CheckModule();
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/validator.h
new file mode 100644 (file)
index 0000000..b84acbc
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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_VALIDATOR_H_
+#define WABT_VALIDATOR_H_
+
+#include "src/error.h"
+#include "src/feature.h"
+#include "src/shared-validator.h"
+
+namespace wabt {
+
+struct Module;
+struct Script;
+
+// Perform all checks on the script. It is valid if and only if this function
+// succeeds.
+Result ValidateScript(const Script*, Errors*, const ValidateOptions&);
+Result ValidateModule(const Module*, Errors*, const ValidateOptions&);
+
+}  // namespace wabt
+
+#endif // WABT_VALIDATOR_H_
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.c.tmpl b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.c.tmpl
new file mode 100644 (file)
index 0000000..8e0fb17
--- /dev/null
@@ -0,0 +1,184 @@
+%%includes
+/* Automically generated by wasm2c */
+#include <math.h>
+#include <string.h>
+%%declarations
+#define UNLIKELY(x) __builtin_expect(!!(x), 0)
+#define LIKELY(x) __builtin_expect(!!(x), 1)
+
+#define TRAP(x) (wasm_rt_trap(WASM_RT_TRAP_##x), 0)
+
+#define FUNC_PROLOGUE                                            \
+  if (++wasm_rt_call_stack_depth > WASM_RT_MAX_CALL_STACK_DEPTH) \
+    TRAP(EXHAUSTION)
+
+#define FUNC_EPILOGUE --wasm_rt_call_stack_depth
+
+#define UNREACHABLE TRAP(UNREACHABLE)
+
+#define CALL_INDIRECT(table, t, ft, x, ...)          \
+  (LIKELY((x) < table.size && table.data[x].func &&  \
+          table.data[x].func_type == func_types[ft]) \
+       ? ((t)table.data[x].func)(__VA_ARGS__)        \
+       : TRAP(CALL_INDIRECT))
+
+#if WASM_RT_MEMCHECK_SIGNAL_HANDLER
+#define MEMCHECK(mem, a, t)
+#else
+#define MEMCHECK(mem, a, t)  \
+  if (UNLIKELY((a) + sizeof(t) > mem->size)) TRAP(OOB)
+#endif
+
+#if WABT_BIG_ENDIAN
+static inline void load_data(void *dest, const void *src, size_t n) {
+  size_t i = 0;
+  u8 *dest_chars = dest;
+  memcpy(dest, src, n);
+  for (i = 0; i < (n>>1); i++) {
+    u8 cursor = dest_chars[i];
+    dest_chars[i] = dest_chars[n - i - 1];
+    dest_chars[n - i - 1] = cursor;
+  }
+}
+#define LOAD_DATA(m, o, i, s) load_data(&(m.data[m.size - o - s]), i, s)
+#define DEFINE_LOAD(name, t1, t2, t3)                                                 \
+  static inline t3 name(wasm_rt_memory_t* mem, u64 addr) {                            \
+    MEMCHECK(mem, addr, t1);                                                          \
+    t1 result;                                                                        \
+    __builtin_memcpy(&result, &mem->data[mem->size - addr - sizeof(t1)], sizeof(t1)); \
+    return (t3)(t2)result;                                                            \
+  }
+
+#define DEFINE_STORE(name, t1, t2)                                                     \
+  static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) {                 \
+    MEMCHECK(mem, addr, t1);                                                           \
+    t1 wrapped = (t1)value;                                                            \
+    __builtin_memcpy(&mem->data[mem->size - addr - sizeof(t1)], &wrapped, sizeof(t1)); \
+  }
+#else
+static inline void load_data(void *dest, const void *src, size_t n) {
+  memcpy(dest, src, n);
+}
+#define LOAD_DATA(m, o, i, s) load_data(&(m.data[o]), i, s)
+#define DEFINE_LOAD(name, t1, t2, t3)                        \
+  static inline t3 name(wasm_rt_memory_t* mem, u64 addr) {   \
+    MEMCHECK(mem, addr, t1);                                 \
+    t1 result;                                               \
+    __builtin_memcpy(&result, &mem->data[addr], sizeof(t1)); \
+    return (t3)(t2)result;                                   \
+  }
+
+#define DEFINE_STORE(name, t1, t2)                                     \
+  static inline void name(wasm_rt_memory_t* mem, u64 addr, t2 value) { \
+    MEMCHECK(mem, addr, t1);                                           \
+    t1 wrapped = (t1)value;                                            \
+    __builtin_memcpy(&mem->data[addr], &wrapped, sizeof(t1));          \
+  }
+#endif
+
+DEFINE_LOAD(i32_load, u32, u32, u32);
+DEFINE_LOAD(i64_load, u64, u64, u64);
+DEFINE_LOAD(f32_load, f32, f32, f32);
+DEFINE_LOAD(f64_load, f64, f64, f64);
+DEFINE_LOAD(i32_load8_s, s8, s32, u32);
+DEFINE_LOAD(i64_load8_s, s8, s64, u64);
+DEFINE_LOAD(i32_load8_u, u8, u32, u32);
+DEFINE_LOAD(i64_load8_u, u8, u64, u64);
+DEFINE_LOAD(i32_load16_s, s16, s32, u32);
+DEFINE_LOAD(i64_load16_s, s16, s64, u64);
+DEFINE_LOAD(i32_load16_u, u16, u32, u32);
+DEFINE_LOAD(i64_load16_u, u16, u64, u64);
+DEFINE_LOAD(i64_load32_s, s32, s64, u64);
+DEFINE_LOAD(i64_load32_u, u32, u64, u64);
+DEFINE_STORE(i32_store, u32, u32);
+DEFINE_STORE(i64_store, u64, u64);
+DEFINE_STORE(f32_store, f32, f32);
+DEFINE_STORE(f64_store, f64, f64);
+DEFINE_STORE(i32_store8, u8, u32);
+DEFINE_STORE(i32_store16, u16, u32);
+DEFINE_STORE(i64_store8, u8, u64);
+DEFINE_STORE(i64_store16, u16, u64);
+DEFINE_STORE(i64_store32, u32, u64);
+
+#define I32_CLZ(x) ((x) ? __builtin_clz(x) : 32)
+#define I64_CLZ(x) ((x) ? __builtin_clzll(x) : 64)
+#define I32_CTZ(x) ((x) ? __builtin_ctz(x) : 32)
+#define I64_CTZ(x) ((x) ? __builtin_ctzll(x) : 64)
+#define I32_POPCNT(x) (__builtin_popcount(x))
+#define I64_POPCNT(x) (__builtin_popcountll(x))
+
+#define DIV_S(ut, min, x, y)                                 \
+   ((UNLIKELY((y) == 0)) ?                TRAP(DIV_BY_ZERO)  \
+  : (UNLIKELY((x) == min && (y) == -1)) ? TRAP(INT_OVERFLOW) \
+  : (ut)((x) / (y)))
+
+#define REM_S(ut, min, x, y)                                \
+   ((UNLIKELY((y) == 0)) ?                TRAP(DIV_BY_ZERO) \
+  : (UNLIKELY((x) == min && (y) == -1)) ? 0                 \
+  : (ut)((x) % (y)))
+
+#define I32_DIV_S(x, y) DIV_S(u32, INT32_MIN, (s32)x, (s32)y)
+#define I64_DIV_S(x, y) DIV_S(u64, INT64_MIN, (s64)x, (s64)y)
+#define I32_REM_S(x, y) REM_S(u32, INT32_MIN, (s32)x, (s32)y)
+#define I64_REM_S(x, y) REM_S(u64, INT64_MIN, (s64)x, (s64)y)
+
+#define DIVREM_U(op, x, y) \
+  ((UNLIKELY((y) == 0)) ? TRAP(DIV_BY_ZERO) : ((x) op (y)))
+
+#define DIV_U(x, y) DIVREM_U(/, x, y)
+#define REM_U(x, y) DIVREM_U(%, x, y)
+
+#define ROTL(x, y, mask) \
+  (((x) << ((y) & (mask))) | ((x) >> (((mask) - (y) + 1) & (mask))))
+#define ROTR(x, y, mask) \
+  (((x) >> ((y) & (mask))) | ((x) << (((mask) - (y) + 1) & (mask))))
+
+#define I32_ROTL(x, y) ROTL(x, y, 31)
+#define I64_ROTL(x, y) ROTL(x, y, 63)
+#define I32_ROTR(x, y) ROTR(x, y, 31)
+#define I64_ROTR(x, y) ROTR(x, y, 63)
+
+#define FMIN(x, y)                                          \
+   ((UNLIKELY((x) != (x))) ? NAN                            \
+  : (UNLIKELY((y) != (y))) ? NAN                            \
+  : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? x : y) \
+  : (x < y) ? x : y)
+
+#define FMAX(x, y)                                          \
+   ((UNLIKELY((x) != (x))) ? NAN                            \
+  : (UNLIKELY((y) != (y))) ? NAN                            \
+  : (UNLIKELY((x) == 0 && (y) == 0)) ? (signbit(x) ? y : x) \
+  : (x > y) ? x : y)
+
+#define TRUNC_S(ut, st, ft, min, minop, max, x)                             \
+  ((UNLIKELY((x) != (x)))                        ? TRAP(INVALID_CONVERSION) \
+   : (UNLIKELY(!((x)minop(min) && (x) < (max)))) ? TRAP(INT_OVERFLOW)       \
+                                                 : (ut)(st)(x))
+
+#define I32_TRUNC_S_F32(x) TRUNC_S(u32, s32, f32, (f32)INT32_MIN, >=, 2147483648.f, x)
+#define I64_TRUNC_S_F32(x) TRUNC_S(u64, s64, f32, (f32)INT64_MIN, >=, (f32)INT64_MAX, x)
+#define I32_TRUNC_S_F64(x) TRUNC_S(u32, s32, f64, -2147483649., >, 2147483648., x)
+#define I64_TRUNC_S_F64(x) TRUNC_S(u64, s64, f64, (f64)INT64_MIN, >=, (f64)INT64_MAX, x)
+
+#define TRUNC_U(ut, ft, max, x)                                            \
+  ((UNLIKELY((x) != (x)))                       ? TRAP(INVALID_CONVERSION) \
+   : (UNLIKELY(!((x) > (ft)-1 && (x) < (max)))) ? TRAP(INT_OVERFLOW)       \
+                                                : (ut)(x))
+
+#define I32_TRUNC_U_F32(x) TRUNC_U(u32, f32, 4294967296.f, x)
+#define I64_TRUNC_U_F32(x) TRUNC_U(u64, f32, (f32)UINT64_MAX, x)
+#define I32_TRUNC_U_F64(x) TRUNC_U(u32, f64, 4294967296.,  x)
+#define I64_TRUNC_U_F64(x) TRUNC_U(u64, f64, (f64)UINT64_MAX, x)
+
+#define DEFINE_REINTERPRET(name, t1, t2)  \
+  static inline t2 name(t1 x) {           \
+    t2 result;                            \
+    memcpy(&result, &x, sizeof(result));  \
+    return result;                        \
+  }
+
+DEFINE_REINTERPRET(f32_reinterpret_i32, u32, f32)
+DEFINE_REINTERPRET(i32_reinterpret_f32, f32, u32)
+DEFINE_REINTERPRET(f64_reinterpret_i64, u64, f64)
+DEFINE_REINTERPRET(i64_reinterpret_f64, f64, u64)
+
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.h.tmpl b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c.h.tmpl
new file mode 100644 (file)
index 0000000..8478d81
--- /dev/null
@@ -0,0 +1,35 @@
+%%top
+/* Automically generated by wasm2c */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include "wasm-rt.h"
+
+#ifndef WASM_RT_MODULE_PREFIX
+#define WASM_RT_MODULE_PREFIX
+#endif
+
+#define WASM_RT_PASTE_(x, y) x ## y
+#define WASM_RT_PASTE(x, y) WASM_RT_PASTE_(x, y)
+#define WASM_RT_ADD_PREFIX(x) WASM_RT_PASTE(WASM_RT_MODULE_PREFIX, x)
+
+/* TODO(binji): only use stdint.h types in header */
+typedef uint8_t u8;
+typedef int8_t s8;
+typedef uint16_t u16;
+typedef int16_t s16;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef float f32;
+typedef double f64;
+
+extern void WASM_RT_ADD_PREFIX(init)(void);
+%%bottom
+#ifdef __cplusplus
+}
+#endif
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c_tmpl.py b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wasm2c_tmpl.py
new file mode 100755 (executable)
index 0000000..0da117a
--- /dev/null
@@ -0,0 +1,77 @@
+#!/usr/bin/env python3
+#
+# Copyright 2018 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.
+#
+
+import argparse
+import io
+import os
+import sys
+
+
+def EscapeCString(s):
+    out = ''
+    for b in bytearray(s.encode('utf-8')):
+        if b in (34, 92):
+            # " or \
+            out += '\\' + chr(b)
+        elif b == 10:
+            # newline
+            out += '\\n'
+        elif 32 <= b <= 127:
+            # printable char
+            out += chr(b)
+        else:
+            # non-printable; write as \xab
+            out += '\\x%02x' % b
+
+    return out
+
+
+def main(args):
+    arg_parser = argparse.ArgumentParser()
+    arg_parser.add_argument('-o', '--output', metavar='PATH',
+                            help='output file.')
+    arg_parser.add_argument('file', help='input file.')
+    options = arg_parser.parse_args(args)
+
+    section_name = None
+    output = io.StringIO()
+
+    output.write('/* Generated from \'%s\' by wasm2c_tmpl.py, do not edit! */\n' %
+                 os.path.basename(options.file))
+
+    with open(options.file) as f:
+        for line in f.readlines():
+            if line.startswith('%%'):
+                if section_name is not None:
+                    output.write(';\n\n')
+                section_name = line[2:-1]
+                output.write('const char SECTION_NAME(%s)[] =\n' % section_name)
+            else:
+                output.write('"%s"\n' % EscapeCString(line))
+
+    output.write(';\n')
+    if options.output:
+        with open(options.output, 'w') as outf:
+            outf.write(output.getvalue())
+    else:
+        sys.stdout.write(output.getvalue())
+
+    return 0
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv[1:]))
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.cc
new file mode 100644 (file)
index 0000000..05ac736
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * 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/wast-lexer.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include "config.h"
+
+#include "src/lexer-source.h"
+#include "src/wast-parser.h"
+
+#define ERROR(...) parser->Error(GetLocation(), __VA_ARGS__)
+
+namespace wabt {
+
+namespace {
+
+#include "src/prebuilt/lexer-keywords.cc"
+
+}  // namespace
+
+WastLexer::WastLexer(std::unique_ptr<LexerSource> source, string_view filename)
+    : source_(std::move(source)),
+      filename_(filename),
+      line_(1),
+      buffer_(static_cast<const char*>(source_->data())),
+      buffer_end_(buffer_ + source_->size()),
+      line_start_(buffer_),
+      token_start_(buffer_),
+      cursor_(buffer_) {}
+
+// static
+std::unique_ptr<WastLexer> WastLexer::CreateBufferLexer(string_view filename,
+                                                        const void* data,
+                                                        size_t size) {
+  return MakeUnique<WastLexer>(MakeUnique<LexerSource>(data, size), filename);
+}
+
+Token WastLexer::GetToken(WastParser* parser) {
+  while (true) {
+    token_start_ = cursor_;
+    switch (PeekChar()) {
+      case kEof:
+        return BareToken(TokenType::Eof);
+
+      case '(':
+        if (MatchString("(;")) {
+          if (ReadBlockComment(parser)) {
+            continue;
+          }
+          return BareToken(TokenType::Eof);
+        } else if (MatchString("(@")) {
+          ReadReservedChars();
+          // offset=2 to skip the "(@" prefix
+          return TextToken(TokenType::LparAnn, 2);
+        } else {
+          ReadChar();
+          return BareToken(TokenType::Lpar);
+        }
+        break;
+
+      case ')':
+        ReadChar();
+        return BareToken(TokenType::Rpar);
+
+      case ';':
+        if (MatchString(";;")) {
+          if (ReadLineComment()) {
+            continue;
+          }
+          return BareToken(TokenType::Eof);
+        } else {
+          ReadChar();
+          ERROR("unexpected char");
+          continue;
+        }
+        break;
+
+      case ' ':
+      case '\t':
+      case '\r':
+      case '\n':
+        ReadWhitespace();
+        continue;
+
+      case '"':
+        return GetStringToken(parser);
+
+      case '+':
+      case '-':
+        ReadChar();
+        switch (PeekChar()) {
+          case 'i':
+            return GetInfToken();
+
+          case 'n':
+            return GetNanToken();
+
+          case '0':
+            return MatchString("0x") ? GetHexNumberToken(TokenType::Int)
+                                     : GetNumberToken(TokenType::Int);
+          case '1':
+          case '2':
+          case '3':
+          case '4':
+          case '5':
+          case '6':
+          case '7':
+          case '8':
+          case '9':
+            return GetNumberToken(TokenType::Int);
+
+          default:
+            return GetReservedToken();
+        }
+        break;
+
+      case '0':
+        return MatchString("0x") ? GetHexNumberToken(TokenType::Nat)
+                                 : GetNumberToken(TokenType::Nat);
+
+      case '1':
+      case '2':
+      case '3':
+      case '4':
+      case '5':
+      case '6':
+      case '7':
+      case '8':
+      case '9':
+        return GetNumberToken(TokenType::Nat);
+
+      case '$':
+        return GetIdToken();
+
+      case 'a':
+        return GetNameEqNumToken("align=", TokenType::AlignEqNat);
+
+      case 'i':
+        return GetInfToken();
+
+      case 'n':
+        return GetNanToken();
+
+      case 'o':
+        return GetNameEqNumToken("offset=", TokenType::OffsetEqNat);
+
+      default:
+        if (IsKeyword(PeekChar())) {
+          return GetKeywordToken();
+        } else if (IsReserved(PeekChar())) {
+          return GetReservedToken();
+        } else {
+          ReadChar();
+          ERROR("unexpected char");
+          continue;
+        }
+    }
+  }
+}
+
+Location WastLexer::GetLocation() {
+  auto column = [=](const char* p) {
+    return std::max(1, static_cast<int>(p - line_start_ + 1));
+  };
+  return Location(filename_, line_, column(token_start_), column(cursor_));
+}
+
+string_view WastLexer::GetText(size_t offset) {
+  return string_view(token_start_ + offset, (cursor_ - token_start_) - offset);
+}
+
+Token WastLexer::BareToken(TokenType token_type) {
+  return Token(GetLocation(), token_type);
+}
+
+Token WastLexer::LiteralToken(TokenType token_type, LiteralType literal_type) {
+  return Token(GetLocation(), token_type, Literal(literal_type, GetText()));
+}
+
+Token WastLexer::TextToken(TokenType token_type, size_t offset) {
+  return Token(GetLocation(), token_type, GetText(offset));
+}
+
+int WastLexer::PeekChar() {
+  return cursor_ < buffer_end_ ? static_cast<uint8_t>(*cursor_) : kEof;
+}
+
+int WastLexer::ReadChar() {
+  return cursor_ < buffer_end_ ? static_cast<uint8_t>(*cursor_++) : kEof;
+}
+
+bool WastLexer::MatchChar(char c) {
+  if (PeekChar() == c) {
+    ReadChar();
+    return true;
+  }
+  return false;
+}
+
+bool WastLexer::MatchString(string_view s) {
+  const char* saved_cursor = cursor_;
+  for (char c : s) {
+    if (ReadChar() != c) {
+      cursor_ = saved_cursor;
+      return false;
+    }
+  }
+  return true;
+}
+
+void WastLexer::Newline() {
+  line_++;
+  line_start_ = cursor_;
+}
+
+bool WastLexer::ReadBlockComment(WastParser* parser) {
+  int nesting = 1;
+  while (true) {
+    switch (ReadChar()) {
+      case kEof:
+        ERROR("EOF in block comment");
+        return false;
+
+      case ';':
+        if (MatchChar(')') && --nesting == 0) {
+          return true;
+        }
+        break;
+
+      case '(':
+        if (MatchChar(';')) {
+          nesting++;
+        }
+        break;
+
+      case '\n':
+        Newline();
+        break;
+    }
+  }
+}
+
+bool WastLexer::ReadLineComment() {
+  while (true) {
+    switch (ReadChar()) {
+      case kEof:
+        return false;
+
+      case '\n':
+        Newline();
+        return true;
+    }
+  }
+}
+
+void WastLexer::ReadWhitespace() {
+  while (true) {
+    switch (PeekChar()) {
+      case ' ':
+      case '\t':
+      case '\r':
+        ReadChar();
+        break;
+
+      case '\n':
+        ReadChar();
+        Newline();
+        break;
+
+      default:
+        return;
+    }
+  }
+}
+
+Token WastLexer::GetStringToken(WastParser* parser) {
+  const char* saved_token_start = token_start_;
+  bool has_error = false;
+  bool in_string = true;
+  ReadChar();
+  while (in_string) {
+    switch (ReadChar()) {
+      case kEof:
+        return BareToken(TokenType::Eof);
+
+      case '\n':
+        token_start_ = cursor_ - 1;
+        ERROR("newline in string");
+        has_error = true;
+        Newline();
+        continue;
+
+      case '"':
+        in_string = false;
+        break;
+
+      case '\\': {
+        switch (ReadChar()) {
+          case 't':
+          case 'n':
+          case 'r':
+          case '"':
+          case '\'':
+          case '\\':
+            // Valid escape.
+            break;
+
+          case '0':
+          case '1':
+          case '2':
+          case '3':
+          case '4':
+          case '5':
+          case '6':
+          case '7':
+          case '8':
+          case '9':
+          case 'a':
+          case 'b':
+          case 'c':
+          case 'd':
+          case 'e':
+          case 'f':
+          case 'A':
+          case 'B':
+          case 'C':
+          case 'D':
+          case 'E':
+          case 'F':  // Hex byte escape.
+            if (IsHexDigit(PeekChar())) {
+              ReadChar();
+            } else {
+              token_start_ = cursor_ - 2;
+              goto error;
+            }
+            break;
+
+          default:
+            token_start_ = cursor_ - 2;
+            goto error;
+
+          error:
+            ERROR("bad escape \"%.*s\"",
+                  static_cast<int>(cursor_ - token_start_), token_start_);
+            has_error = true;
+            break;
+        }
+        break;
+      }
+    }
+  }
+  token_start_ = saved_token_start;
+  if (has_error) {
+    return Token(GetLocation(), TokenType::Invalid);
+  }
+
+  return TextToken(TokenType::Text);
+}
+
+// static
+bool WastLexer::IsCharClass(int c, CharClass bit) {
+  // Generated by the following python script:
+  //
+  //   def Range(c, lo, hi): return lo <= c <= hi
+  //   def IsDigit(c): return Range(c, '0', '9')
+  //   def IsHexDigit(c): return IsDigit(c) or Range(c.lower(), 'a', 'f')
+  //   def IsKeyword(c): return Range(c, 'a', 'z')
+  //   def IsReserved(c): return Range(c, '!', '~') and c not in '"(),;[]{}'
+  //
+  //   print ([0] + [
+  //       (8 if IsDigit(c) else 0) |
+  //       (4 if IsHexDigit(c) else 0) |
+  //       (2 if IsKeyword(c) else 0) |
+  //       (1 if IsReserved(c) else 0)
+  //       for c in map(chr, range(0, 127))
+  //   ])
+  static const char kCharClasses[257] = {
+      0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,
+      0,  0,  0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  1,  0,  1,  1,
+      1,  1,  1, 0, 0, 1, 1, 0, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13,
+      13, 13, 1, 0, 1, 1, 1, 1, 1, 5, 5, 5,  5,  5,  5,  1,  1,  1,  1,
+      1,  1,  1, 1, 1, 1, 1, 1, 1, 1, 1, 1,  1,  1,  1,  1,  0,  1,  0,
+      1,  1,  1, 7, 7, 7, 7, 7, 7, 3, 3, 3,  3,  3,  3,  3,  3,  3,  3,
+      3,  3,  3, 3, 3, 3, 3, 3, 3, 3, 0, 1,  0,  1,
+  };
+
+  assert(c >= -1 && c < 256);
+  return (kCharClasses[c + 1] & static_cast<int>(bit)) != 0;
+}
+
+bool WastLexer::ReadNum() {
+  if (IsDigit(PeekChar())) {
+    ReadChar();
+    return MatchChar('_') || IsDigit(PeekChar()) ? ReadNum() : true;
+  }
+  return false;
+}
+
+bool WastLexer::ReadHexNum() {
+  if (IsHexDigit(PeekChar())) {
+    ReadChar();
+    return MatchChar('_') || IsHexDigit(PeekChar()) ? ReadHexNum() : true;
+  }
+  return false;
+}
+
+int WastLexer::ReadReservedChars() {
+  int count = 0;
+  while (IsReserved(PeekChar())) {
+    ReadChar();
+    ++count;
+  }
+  return count;
+}
+
+void WastLexer::ReadSign() {
+  if (PeekChar() == '+' || PeekChar() == '-') {
+    ReadChar();
+  }
+}
+
+Token WastLexer::GetNumberToken(TokenType token_type) {
+  if (ReadNum()) {
+    if (MatchChar('.')) {
+      token_type = TokenType::Float;
+      if (IsDigit(PeekChar()) && !ReadNum()) {
+        return GetReservedToken();
+      }
+    }
+    if (MatchChar('e') || MatchChar('E')) {
+      token_type = TokenType::Float;
+      ReadSign();
+      if (!ReadNum()) {
+        return GetReservedToken();
+      }
+    }
+    if (NoTrailingReservedChars()) {
+      if (token_type == TokenType::Float) {
+        return LiteralToken(token_type, LiteralType::Float);
+      } else {
+        return LiteralToken(token_type, LiteralType::Int);
+      }
+    }
+  }
+  return GetReservedToken();
+}
+
+Token WastLexer::GetHexNumberToken(TokenType token_type) {
+  if (ReadHexNum()) {
+    if (MatchChar('.')) {
+      token_type = TokenType::Float;
+      if (IsHexDigit(PeekChar()) && !ReadHexNum()) {
+        return GetReservedToken();
+      }
+    }
+    if (MatchChar('p') || MatchChar('P')) {
+      token_type = TokenType::Float;
+      ReadSign();
+      if (!ReadNum()) {
+        return GetReservedToken();
+      }
+    }
+    if (NoTrailingReservedChars()) {
+      if (token_type == TokenType::Float) {
+        return LiteralToken(token_type, LiteralType::Hexfloat);
+      } else {
+        return LiteralToken(token_type, LiteralType::Int);
+      }
+    }
+  }
+  return GetReservedToken();
+}
+
+Token WastLexer::GetInfToken() {
+  if (MatchString("inf")) {
+    if (NoTrailingReservedChars()) {
+      return LiteralToken(TokenType::Float, LiteralType::Infinity);
+    }
+    return GetReservedToken();
+  }
+  return GetKeywordToken();
+}
+
+Token WastLexer::GetNanToken() {
+  if (MatchString("nan")) {
+    if (MatchChar(':')) {
+      if (MatchString("0x") && ReadHexNum() && NoTrailingReservedChars()) {
+        return LiteralToken(TokenType::Float, LiteralType::Nan);
+      }
+    } else if (NoTrailingReservedChars()) {
+      return LiteralToken(TokenType::Float, LiteralType::Nan);
+    }
+  }
+  return GetKeywordToken();
+}
+
+Token WastLexer::GetNameEqNumToken(string_view name, TokenType token_type) {
+  if (MatchString(name)) {
+    if (MatchString("0x")) {
+      if (ReadHexNum() && NoTrailingReservedChars()) {
+        return TextToken(token_type, name.size());
+      }
+    } else if (ReadNum() && NoTrailingReservedChars()) {
+      return TextToken(token_type, name.size());
+    }
+  }
+  return GetKeywordToken();
+}
+
+Token WastLexer::GetIdToken() {
+  ReadChar();
+  if (NoTrailingReservedChars()) {
+    return TextToken(TokenType::Reserved);
+  }
+  return TextToken(TokenType::Var);
+}
+
+Token WastLexer::GetKeywordToken() {
+  ReadReservedChars();
+  TokenInfo* info =
+      Perfect_Hash::InWordSet(token_start_, cursor_ - token_start_);
+  if (!info) {
+    return TextToken(TokenType::Reserved);
+  }
+  if (IsTokenTypeBare(info->token_type)) {
+    return BareToken(info->token_type);
+  } else if (IsTokenTypeType(info->token_type) ||
+             IsTokenTypeRefKind(info->token_type)) {
+    return Token(GetLocation(), info->token_type, info->value_type);
+  } else {
+    assert(IsTokenTypeOpcode(info->token_type));
+    return Token(GetLocation(), info->token_type, info->opcode);
+  }
+}
+
+Token WastLexer::GetReservedToken() {
+  ReadReservedChars();
+  return TextToken(TokenType::Reserved);
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-lexer.h
new file mode 100644 (file)
index 0000000..985fb8b
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * 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_WAST_LEXER_H_
+#define WABT_WAST_LEXER_H_
+
+#include <cstddef>
+#include <cstdio>
+#include <memory>
+
+#include "src/common.h"
+#include "src/lexer-source-line-finder.h"
+#include "src/literal.h"
+#include "src/make-unique.h"
+#include "src/opcode.h"
+#include "src/token.h"
+
+namespace wabt {
+
+class ErrorHandler;
+class LexerSource;
+class WastParser;
+
+class WastLexer {
+ public:
+  WABT_DISALLOW_COPY_AND_ASSIGN(WastLexer);
+
+  WastLexer(std::unique_ptr<LexerSource> source, string_view filename);
+
+  // Convenience functions.
+  static std::unique_ptr<WastLexer> CreateBufferLexer(string_view filename,
+                                                      const void* data,
+                                                      size_t size);
+
+  Token GetToken(WastParser* parser);
+
+  // TODO(binji): Move this out of the lexer.
+  std::unique_ptr<LexerSourceLineFinder> MakeLineFinder() {
+    return MakeUnique<LexerSourceLineFinder>(source_->Clone());
+  }
+
+ private:
+  static const int kEof = -1;
+  enum class CharClass { Reserved = 1, Keyword = 2, HexDigit = 4, Digit = 8 };
+
+  Location GetLocation();
+  string_view GetText(size_t offset = 0);
+
+  Token BareToken(TokenType);
+  Token LiteralToken(TokenType, LiteralType);
+  Token TextToken(TokenType, size_t offset = 0);
+
+  int PeekChar();
+  int ReadChar();
+  bool MatchChar(char);
+  bool MatchString(string_view);
+  void Newline();
+  bool ReadBlockComment(WastParser*);  // Returns false if EOF.
+  bool ReadLineComment();              // Returns false if EOF.
+  void ReadWhitespace();
+
+  static bool IsCharClass(int c, CharClass);
+  static bool IsDigit(int c) { return IsCharClass(c, CharClass::Digit); }
+  static bool IsHexDigit(int c) { return IsCharClass(c, CharClass::HexDigit); }
+  static bool IsKeyword(int c) { return IsCharClass(c, CharClass::Keyword); }
+  static bool IsReserved(int c) { return IsCharClass(c, CharClass::Reserved); }
+
+  bool ReadNum();
+  bool ReadHexNum();
+  int ReadReservedChars();
+  bool NoTrailingReservedChars() { return ReadReservedChars() == 0; }
+  void ReadSign();
+  Token GetStringToken(WastParser*);
+  Token GetNumberToken(TokenType);
+  Token GetHexNumberToken(TokenType);
+  Token GetInfToken();
+  Token GetNanToken();
+  Token GetNameEqNumToken(string_view name, TokenType);
+  Token GetIdToken();
+  Token GetKeywordToken();
+  Token GetReservedToken();
+
+  std::unique_ptr<LexerSource> source_;
+  std::string filename_;
+  int line_;
+  const char* buffer_;
+  const char* buffer_end_;
+  const char* line_start_;
+  const char* token_start_;
+  const char* cursor_;
+};
+
+}  // namespace wabt
+
+#endif /* WABT_WAST_LEXER_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.cc
new file mode 100644 (file)
index 0000000..6ae2d24
--- /dev/null
@@ -0,0 +1,3250 @@
+/*
+ * 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/wast-parser.h"
+
+#include "src/binary-reader-ir.h"
+#include "src/binary-reader.h"
+#include "src/cast.h"
+#include "src/expr-visitor.h"
+#include "src/make-unique.h"
+#include "src/resolve-names.h"
+#include "src/stream.h"
+#include "src/utf8.h"
+#include "src/validator.h"
+
+#define WABT_TRACING 0
+#include "src/tracing.h"
+
+#define EXPECT(token_type) CHECK_RESULT(Expect(TokenType::token_type))
+
+namespace wabt {
+
+namespace {
+
+static const size_t kMaxErrorTokenLength = 80;
+
+bool IsPowerOfTwo(uint32_t x) {
+  return x && ((x & (x - 1)) == 0);
+}
+
+template <typename OutputIter>
+void RemoveEscapes(string_view text, OutputIter dest) {
+  // Remove surrounding quotes; if any. This may be empty if the string was
+  // invalid (e.g. if it contained a bad escape sequence).
+  if (text.size() <= 2) {
+    return;
+  }
+
+  text = text.substr(1, text.size() - 2);
+
+  const char* src = text.data();
+  const char* end = text.data() + text.size();
+
+  while (src < end) {
+    if (*src == '\\') {
+      src++;
+      switch (*src) {
+        case 'n':
+          *dest++ = '\n';
+          break;
+        case 'r':
+          *dest++ = '\r';
+          break;
+        case 't':
+          *dest++ = '\t';
+          break;
+        case '\\':
+          *dest++ = '\\';
+          break;
+        case '\'':
+          *dest++ = '\'';
+          break;
+        case '\"':
+          *dest++ = '\"';
+          break;
+        default: {
+          // The string should be validated already, so we know this is a hex
+          // sequence.
+          uint32_t hi;
+          uint32_t lo;
+          if (Succeeded(ParseHexdigit(src[0], &hi)) &&
+              Succeeded(ParseHexdigit(src[1], &lo))) {
+            *dest++ = (hi << 4) | lo;
+          } else {
+            assert(0);
+          }
+          src++;
+          break;
+        }
+      }
+      src++;
+    } else {
+      *dest++ = *src++;
+    }
+  }
+}
+
+typedef std::vector<string_view> TextVector;
+
+template <typename OutputIter>
+void RemoveEscapes(const TextVector& texts, OutputIter out) {
+  for (string_view text : texts)
+    RemoveEscapes(text, out);
+}
+
+bool IsPlainInstr(TokenType token_type) {
+  switch (token_type) {
+    case TokenType::Unreachable:
+    case TokenType::Nop:
+    case TokenType::Drop:
+    case TokenType::Select:
+    case TokenType::Br:
+    case TokenType::BrIf:
+    case TokenType::BrTable:
+    case TokenType::Return:
+    case TokenType::ReturnCall:
+    case TokenType::ReturnCallIndirect:
+    case TokenType::Call:
+    case TokenType::CallIndirect:
+    case TokenType::LocalGet:
+    case TokenType::LocalSet:
+    case TokenType::LocalTee:
+    case TokenType::GlobalGet:
+    case TokenType::GlobalSet:
+    case TokenType::Load:
+    case TokenType::Store:
+    case TokenType::Const:
+    case TokenType::Unary:
+    case TokenType::Binary:
+    case TokenType::Compare:
+    case TokenType::Convert:
+    case TokenType::MemoryCopy:
+    case TokenType::DataDrop:
+    case TokenType::MemoryFill:
+    case TokenType::MemoryGrow:
+    case TokenType::MemoryInit:
+    case TokenType::MemorySize:
+    case TokenType::TableCopy:
+    case TokenType::ElemDrop:
+    case TokenType::TableInit:
+    case TokenType::TableGet:
+    case TokenType::TableSet:
+    case TokenType::TableGrow:
+    case TokenType::TableSize:
+    case TokenType::TableFill:
+    case TokenType::Throw:
+    case TokenType::Rethrow:
+    case TokenType::RefFunc:
+    case TokenType::RefNull:
+    case TokenType::RefIsNull:
+    case TokenType::AtomicLoad:
+    case TokenType::AtomicStore:
+    case TokenType::AtomicRmw:
+    case TokenType::AtomicRmwCmpxchg:
+    case TokenType::AtomicNotify:
+    case TokenType::AtomicFence:
+    case TokenType::AtomicWait:
+    case TokenType::Ternary:
+    case TokenType::SimdLaneOp:
+    case TokenType::SimdShuffleOp:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool IsBlockInstr(TokenType token_type) {
+  switch (token_type) {
+    case TokenType::Block:
+    case TokenType::Loop:
+    case TokenType::If:
+    case TokenType::Try:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool IsPlainOrBlockInstr(TokenType token_type) {
+  return IsPlainInstr(token_type) || IsBlockInstr(token_type);
+}
+
+bool IsExpr(TokenTypePair pair) {
+  return pair[0] == TokenType::Lpar && IsPlainOrBlockInstr(pair[1]);
+}
+
+bool IsInstr(TokenTypePair pair) {
+  return IsPlainOrBlockInstr(pair[0]) || IsExpr(pair);
+}
+
+bool IsCatch(TokenType token_type) {
+  return token_type == TokenType::Catch || token_type == TokenType::CatchAll;
+}
+
+bool IsModuleField(TokenTypePair pair) {
+  if (pair[0] != TokenType::Lpar) {
+    return false;
+  }
+
+  switch (pair[1]) {
+    case TokenType::Data:
+    case TokenType::Elem:
+    case TokenType::Event:
+    case TokenType::Export:
+    case TokenType::Func:
+    case TokenType::Type:
+    case TokenType::Global:
+    case TokenType::Import:
+    case TokenType::Memory:
+    case TokenType::Start:
+    case TokenType::Table:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool IsCommand(TokenTypePair pair) {
+  if (pair[0] != TokenType::Lpar) {
+    return false;
+  }
+
+  switch (pair[1]) {
+    case TokenType::AssertExhaustion:
+    case TokenType::AssertInvalid:
+    case TokenType::AssertMalformed:
+    case TokenType::AssertReturn:
+    case TokenType::AssertTrap:
+    case TokenType::AssertUnlinkable:
+    case TokenType::Get:
+    case TokenType::Invoke:
+    case TokenType::Input:
+    case TokenType::Module:
+    case TokenType::Output:
+    case TokenType::Register:
+      return true;
+    default:
+      return false;
+  }
+}
+
+bool IsEmptySignature(const FuncSignature& sig) {
+  return sig.result_types.empty() && sig.param_types.empty();
+}
+
+bool ResolveFuncTypeWithEmptySignature(const Module& module,
+                                       FuncDeclaration* decl) {
+  // Resolve func type variables where the signature was not specified
+  // explicitly, e.g.: (func (type 1) ...)
+  if (decl->has_func_type && IsEmptySignature(decl->sig)) {
+    const FuncType* func_type = module.GetFuncType(decl->type_var);
+    if (func_type) {
+      decl->sig = func_type->sig;
+      return true;
+    }
+  }
+  return false;
+}
+
+void ResolveImplicitlyDefinedFunctionType(const Location& loc,
+                                          Module* module,
+                                          const FuncDeclaration& decl) {
+  // Resolve implicitly defined function types, e.g.: (func (param i32) ...)
+  if (!decl.has_func_type) {
+    Index func_type_index = module->GetFuncTypeIndex(decl.sig);
+    if (func_type_index == kInvalidIndex) {
+      auto func_type_field = MakeUnique<TypeModuleField>(loc);
+      auto func_type = MakeUnique<FuncType>();
+      func_type->sig = decl.sig;
+      func_type_field->type = std::move(func_type);
+      module->AppendField(std::move(func_type_field));
+    }
+  }
+}
+
+Result CheckTypeIndex(const Location& loc,
+                      Type actual,
+                      Type expected,
+                      const char* desc,
+                      Index index,
+                      const char* index_kind,
+                      Errors* errors) {
+  // Types must match exactly; no subtyping should be allowed.
+  if (actual != expected) {
+    errors->emplace_back(ErrorLevel::Error, loc,
+                         StringPrintf("type mismatch for %s %" PRIindex
+                                      " of %s. got %s, expected %s",
+                                      index_kind, index, desc, actual.GetName(),
+                                      expected.GetName()));
+    return Result::Error;
+  }
+  return Result::Ok;
+}
+
+Result CheckTypes(const Location& loc,
+                  const TypeVector& actual,
+                  const TypeVector& expected,
+                  const char* desc,
+                  const char* index_kind,
+                  Errors* errors) {
+  Result result = Result::Ok;
+  if (actual.size() == expected.size()) {
+    for (size_t i = 0; i < actual.size(); ++i) {
+      result |= CheckTypeIndex(loc, actual[i], expected[i], desc, i, index_kind,
+                               errors);
+    }
+  } else {
+    errors->emplace_back(
+        ErrorLevel::Error, loc,
+        StringPrintf("expected %" PRIzd " %ss, got %" PRIzd, expected.size(),
+                     index_kind, actual.size()));
+    result = Result::Error;
+  }
+  return result;
+}
+
+Result CheckFuncTypeVarMatchesExplicit(const Location& loc,
+                                       const Module& module,
+                                       const FuncDeclaration& decl,
+                                       Errors* errors) {
+  Result result = Result::Ok;
+  if (decl.has_func_type) {
+    const FuncType* func_type = module.GetFuncType(decl.type_var);
+    if (func_type) {
+      result |=
+          CheckTypes(loc, decl.sig.result_types, func_type->sig.result_types,
+                     "function", "result", errors);
+      result |=
+          CheckTypes(loc, decl.sig.param_types, func_type->sig.param_types,
+                     "function", "argument", errors);
+    } else if (!(decl.sig.param_types.empty() &&
+                 decl.sig.result_types.empty())) {
+      // We want to check whether the function type at the explicit index
+      // matches the given param and result types. If they were omitted then
+      // they'll be resolved automatically (see
+      // ResolveFuncTypeWithEmptySignature), but if they are provided then we
+      // have to check. If we get here then the type var is invalid, so we
+      // can't check whether they match.
+      errors->emplace_back(ErrorLevel::Error, loc,
+                           StringPrintf("invalid func type index %" PRIindex,
+                                        decl.type_var.index()));
+      result = Result::Error;
+    }
+  }
+  return result;
+}
+
+bool IsInlinableFuncSignature(const FuncSignature& sig) {
+  return sig.GetNumParams() == 0 && sig.GetNumResults() <= 1;
+}
+
+class ResolveFuncTypesExprVisitorDelegate : public ExprVisitor::DelegateNop {
+ public:
+  explicit ResolveFuncTypesExprVisitorDelegate(Module* module, Errors* errors)
+      : module_(module), errors_(errors) {}
+
+  void ResolveBlockDeclaration(const Location& loc, BlockDeclaration* decl) {
+    ResolveFuncTypeWithEmptySignature(*module_, decl);
+    if (!IsInlinableFuncSignature(decl->sig)) {
+      ResolveImplicitlyDefinedFunctionType(loc, module_, *decl);
+    }
+  }
+
+  Result BeginBlockExpr(BlockExpr* expr) override {
+    ResolveBlockDeclaration(expr->loc, &expr->block.decl);
+    return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_,
+                                           expr->block.decl, errors_);
+  }
+
+  Result BeginIfExpr(IfExpr* expr) override {
+    ResolveBlockDeclaration(expr->loc, &expr->true_.decl);
+    return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_,
+                                           expr->true_.decl, errors_);
+  }
+
+  Result BeginLoopExpr(LoopExpr* expr) override {
+    ResolveBlockDeclaration(expr->loc, &expr->block.decl);
+    return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_,
+                                           expr->block.decl, errors_);
+  }
+
+  Result BeginTryExpr(TryExpr* expr) override {
+    ResolveBlockDeclaration(expr->loc, &expr->block.decl);
+    return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_,
+                                           expr->block.decl, errors_);
+  }
+
+  Result OnCallIndirectExpr(CallIndirectExpr* expr) override {
+    ResolveFuncTypeWithEmptySignature(*module_, &expr->decl);
+    ResolveImplicitlyDefinedFunctionType(expr->loc, module_, expr->decl);
+    return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, expr->decl,
+                                           errors_);
+  }
+
+  Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr* expr) override {
+    ResolveFuncTypeWithEmptySignature(*module_, &expr->decl);
+    ResolveImplicitlyDefinedFunctionType(expr->loc, module_, expr->decl);
+    return CheckFuncTypeVarMatchesExplicit(expr->loc, *module_, expr->decl,
+                                           errors_);
+  }
+
+ private:
+  Module* module_;
+  Errors* errors_;
+};
+
+Result ResolveFuncTypes(Module* module, Errors* errors) {
+  Result result = Result::Ok;
+  for (ModuleField& field : module->fields) {
+    Func* func = nullptr;
+    FuncDeclaration* decl = nullptr;
+    if (auto* func_field = dyn_cast<FuncModuleField>(&field)) {
+      func = &func_field->func;
+      decl = &func->decl;
+    } else if (auto* event_field = dyn_cast<EventModuleField>(&field)) {
+      decl = &event_field->event.decl;
+    } else if (auto* import_field = dyn_cast<ImportModuleField>(&field)) {
+      if (auto* func_import =
+              dyn_cast<FuncImport>(import_field->import.get())) {
+        // Only check the declaration, not the function itself, since it is an
+        // import.
+        decl = &func_import->func.decl;
+      } else if (auto* event_import =
+                     dyn_cast<EventImport>(import_field->import.get())) {
+        decl = &event_import->event.decl;
+      } else {
+        continue;
+      }
+    } else {
+      continue;
+    }
+
+    bool has_func_type_and_empty_signature = false;
+
+    if (decl) {
+      has_func_type_and_empty_signature =
+          ResolveFuncTypeWithEmptySignature(*module, decl);
+      ResolveImplicitlyDefinedFunctionType(field.loc, module, *decl);
+      result |=
+          CheckFuncTypeVarMatchesExplicit(field.loc, *module, *decl, errors);
+    }
+
+    if (func) {
+      if (has_func_type_and_empty_signature) {
+        // The call to ResolveFuncTypeWithEmptySignature may have updated the
+        // function signature so there are parameters. Since parameters and
+        // local variables share the same index space, we need to increment the
+        // local indexes bound to a given name by the number of parameters in
+        // the function.
+        for (auto& pair: func->bindings) {
+          pair.second.index += func->GetNumParams();
+        }
+      }
+
+      ResolveFuncTypesExprVisitorDelegate delegate(module, errors);
+      ExprVisitor visitor(&delegate);
+      result |= visitor.VisitFunc(func);
+    }
+  }
+  return result;
+}
+
+void AppendInlineExportFields(Module* module,
+                              ModuleFieldList* fields,
+                              Index index) {
+  Location last_field_loc = module->fields.back().loc;
+
+  for (ModuleField& field : *fields) {
+    auto* export_field = cast<ExportModuleField>(&field);
+    export_field->export_.var = Var(index, last_field_loc);
+  }
+
+  module->AppendFields(fields);
+}
+
+}  // End of anonymous namespace
+
+WastParser::WastParser(WastLexer* lexer,
+                       Errors* errors,
+                       WastParseOptions* options)
+    : lexer_(lexer), errors_(errors), options_(options) {}
+
+void WastParser::Error(Location loc, const char* format, ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  errors_->emplace_back(ErrorLevel::Error, loc, buffer);
+}
+
+Token WastParser::GetToken() {
+  if (tokens_.empty()) {
+    tokens_.push_back(lexer_->GetToken(this));
+  }
+  return tokens_.front();
+}
+
+Location WastParser::GetLocation() {
+  return GetToken().loc;
+}
+
+TokenType WastParser::Peek(size_t n) {
+  while (tokens_.size() <= n) {
+    Token cur = lexer_->GetToken(this);
+    if (cur.token_type() != TokenType::LparAnn) {
+      tokens_.push_back(cur);
+    } else {
+      // Custom annotation. For now, discard until matching Rpar.
+      if (!options_->features.annotations_enabled()) {
+        Error(cur.loc, "annotations not enabled: %s", cur.to_string().c_str());
+        tokens_.push_back(Token(cur.loc, TokenType::Invalid));
+        continue;
+      }
+      int indent = 1;
+      while (indent > 0) {
+        cur = lexer_->GetToken(this);
+        switch (cur.token_type()) {
+          case TokenType::Lpar:
+          case TokenType::LparAnn:
+            indent++;
+            break;
+
+          case TokenType::Rpar:
+            indent--;
+            break;
+
+          default:
+            break;
+        }
+      }
+    }
+  }
+  return tokens_.at(n).token_type();
+}
+
+TokenTypePair WastParser::PeekPair() {
+  return TokenTypePair{{Peek(), Peek(1)}};
+}
+
+bool WastParser::PeekMatch(TokenType type) {
+  return Peek() == type;
+}
+
+bool WastParser::PeekMatchLpar(TokenType type) {
+  return Peek() == TokenType::Lpar && Peek(1) == type;
+}
+
+bool WastParser::PeekMatchExpr() {
+  return IsExpr(PeekPair());
+}
+
+bool WastParser::Match(TokenType type) {
+  if (PeekMatch(type)) {
+    Consume();
+    return true;
+  }
+  return false;
+}
+
+bool WastParser::MatchLpar(TokenType type) {
+  if (PeekMatchLpar(type)) {
+    Consume();
+    Consume();
+    return true;
+  }
+  return false;
+}
+
+Result WastParser::Expect(TokenType type) {
+  if (!Match(type)) {
+    Token token = Consume();
+    Error(token.loc, "unexpected token %s, expected %s.",
+          token.to_string_clamp(kMaxErrorTokenLength).c_str(),
+          GetTokenTypeName(type));
+    return Result::Error;
+  }
+
+  return Result::Ok;
+}
+
+Token WastParser::Consume() {
+  assert(!tokens_.empty());
+  Token token = tokens_.front();
+  tokens_.pop_front();
+  return token;
+}
+
+Result WastParser::Synchronize(SynchronizeFunc func) {
+  static const int kMaxConsumed = 10;
+  for (int i = 0; i < kMaxConsumed; ++i) {
+    if (func(PeekPair())) {
+      return Result::Ok;
+    }
+
+    Token token = Consume();
+    if (token.token_type() == TokenType::Reserved) {
+      Error(token.loc, "unexpected token %s.",
+            token.to_string_clamp(kMaxErrorTokenLength).c_str());
+    }
+  }
+
+  return Result::Error;
+}
+
+void WastParser::ErrorUnlessOpcodeEnabled(const Token& token) {
+  Opcode opcode = token.opcode();
+  if (!opcode.IsEnabled(options_->features)) {
+    Error(token.loc, "opcode not allowed: %s", opcode.GetName());
+  }
+}
+
+Result WastParser::ErrorExpected(const std::vector<std::string>& expected,
+                                 const char* example) {
+  Token token = Consume();
+  std::string expected_str;
+  if (!expected.empty()) {
+    expected_str = ", expected ";
+    for (size_t i = 0; i < expected.size(); ++i) {
+      if (i != 0) {
+        if (i == expected.size() - 1) {
+          expected_str += " or ";
+        } else {
+          expected_str += ", ";
+        }
+      }
+
+      expected_str += expected[i];
+    }
+
+    if (example) {
+      expected_str += " (e.g. ";
+      expected_str += example;
+      expected_str += ")";
+    }
+  }
+
+  Error(token.loc, "unexpected token \"%s\"%s.",
+        token.to_string_clamp(kMaxErrorTokenLength).c_str(),
+        expected_str.c_str());
+  return Result::Error;
+}
+
+Result WastParser::ErrorIfLpar(const std::vector<std::string>& expected,
+                               const char* example) {
+  if (Match(TokenType::Lpar)) {
+    GetToken();
+    return ErrorExpected(expected, example);
+  }
+  return Result::Ok;
+}
+
+bool WastParser::ParseBindVarOpt(std::string* name) {
+  WABT_TRACE(ParseBindVarOpt);
+  if (!PeekMatch(TokenType::Var)) {
+    return false;
+  }
+  Token token = Consume();
+  *name = token.text().to_string();
+  return true;
+}
+
+Result WastParser::ParseVar(Var* out_var) {
+  WABT_TRACE(ParseVar);
+  if (PeekMatch(TokenType::Nat)) {
+    Token token = Consume();
+    string_view sv = token.literal().text;
+    uint64_t index = kInvalidIndex;
+    if (Failed(ParseUint64(sv.begin(), sv.end(), &index))) {
+      // Print an error, but don't fail parsing.
+      Error(token.loc, "invalid int \"" PRIstringview "\"",
+            WABT_PRINTF_STRING_VIEW_ARG(sv));
+    }
+
+    *out_var = Var(index, token.loc);
+    return Result::Ok;
+  } else if (PeekMatch(TokenType::Var)) {
+    Token token = Consume();
+    *out_var = Var(token.text(), token.loc);
+    return Result::Ok;
+  } else {
+    return ErrorExpected({"a numeric index", "a name"}, "12 or $foo");
+  }
+}
+
+bool WastParser::ParseVarOpt(Var* out_var, Var default_var) {
+  WABT_TRACE(ParseVarOpt);
+  if (PeekMatch(TokenType::Nat) || PeekMatch(TokenType::Var)) {
+    Result result = ParseVar(out_var);
+    // Should always succeed, the only way it could fail is if the token
+    // doesn't match.
+    assert(Succeeded(result));
+    WABT_USE(result);
+    return true;
+  } else {
+    *out_var = default_var;
+    return false;
+  }
+}
+
+Result WastParser::ParseOffsetExpr(ExprList* out_expr_list) {
+  WABT_TRACE(ParseOffsetExpr);
+  if (!ParseOffsetExprOpt(out_expr_list)) {
+    return ErrorExpected({"an offset expr"}, "(i32.const 123)");
+  }
+  return Result::Ok;
+}
+
+bool WastParser::ParseOffsetExprOpt(ExprList* out_expr_list) {
+  WABT_TRACE(ParseOffsetExprOpt);
+  if (MatchLpar(TokenType::Offset)) {
+    CHECK_RESULT(ParseTerminatingInstrList(out_expr_list));
+    EXPECT(Rpar);
+    return true;
+  } else if (PeekMatchExpr()) {
+    CHECK_RESULT(ParseExpr(out_expr_list));
+    return true;
+  } else {
+    return false;
+  }
+}
+
+Result WastParser::ParseTextList(std::vector<uint8_t>* out_data) {
+  WABT_TRACE(ParseTextList);
+  if (!ParseTextListOpt(out_data)) {
+    // TODO(binji): Add error message here.
+    return Result::Error;
+  }
+
+  return Result::Ok;
+}
+
+bool WastParser::ParseTextListOpt(std::vector<uint8_t>* out_data) {
+  WABT_TRACE(ParseTextListOpt);
+  TextVector texts;
+  while (PeekMatch(TokenType::Text))
+    texts.push_back(Consume().text());
+
+  RemoveEscapes(texts, std::back_inserter(*out_data));
+  return !texts.empty();
+}
+
+Result WastParser::ParseVarList(VarVector* out_var_list) {
+  WABT_TRACE(ParseVarList);
+  Var var;
+  while (ParseVarOpt(&var)) {
+    out_var_list->emplace_back(var);
+  }
+  if (out_var_list->empty()) {
+    return ErrorExpected({"a var"}, "12 or $foo");
+  } else {
+    return Result::Ok;
+  }
+}
+
+bool WastParser::ParseElemExprOpt(ElemExpr* out_elem_expr) {
+  Location loc = GetLocation();
+  bool item = MatchLpar(TokenType::Item);
+  bool lpar = Match(TokenType::Lpar);
+  if (Match(TokenType::RefNull)) {
+    if (!(options_->features.bulk_memory_enabled() ||
+          options_->features.reference_types_enabled())) {
+      Error(loc, "ref.null not allowed");
+    }
+    Type type;
+    CHECK_RESULT(ParseRefKind(&type));
+    *out_elem_expr = ElemExpr(type);
+  } else if (Match(TokenType::RefFunc)) {
+    Var var;
+    CHECK_RESULT(ParseVar(&var));
+    *out_elem_expr = ElemExpr(var);
+  } else {
+    return false;
+  }
+  if (lpar) {
+    EXPECT(Rpar);
+  }
+  if (item) {
+    EXPECT(Rpar);
+  }
+  return true;
+}
+
+bool WastParser::ParseElemExprListOpt(ElemExprVector* out_list) {
+  ElemExpr elem_expr;
+  while (ParseElemExprOpt(&elem_expr)) {
+    out_list->push_back(elem_expr);
+  }
+  return !out_list->empty();
+}
+
+bool WastParser::ParseElemExprVarListOpt(ElemExprVector* out_list) {
+  WABT_TRACE(ParseElemExprVarListOpt);
+  Var var;
+  while (ParseVarOpt(&var)) {
+    out_list->emplace_back(var);
+  }
+  return !out_list->empty();
+}
+
+Result WastParser::ParseValueType(Type* out_type) {
+  WABT_TRACE(ParseValueType);
+  if (!PeekMatch(TokenType::ValueType)) {
+    return ErrorExpected({"i32", "i64", "f32", "f64", "v128", "externref"});
+  }
+
+  Token token = Consume();
+  Type type = token.type();
+  bool is_enabled;
+  switch (type) {
+    case Type::V128:
+      is_enabled = options_->features.simd_enabled();
+      break;
+    case Type::FuncRef:
+    case Type::ExternRef:
+      is_enabled = options_->features.reference_types_enabled();
+      break;
+    default:
+      is_enabled = true;
+      break;
+  }
+
+  if (!is_enabled) {
+    Error(token.loc, "value type not allowed: %s", type.GetName());
+    return Result::Error;
+  }
+
+  *out_type = type;
+  return Result::Ok;
+}
+
+Result WastParser::ParseValueTypeList(TypeVector* out_type_list) {
+  WABT_TRACE(ParseValueTypeList);
+  while (PeekMatch(TokenType::ValueType))
+    out_type_list->push_back(Consume().type());
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseRefKind(Type* out_type) {
+  WABT_TRACE(ParseRefKind);
+  if (!IsTokenTypeRefKind(Peek())) {
+    return ErrorExpected({"func", "extern", "exn"});
+  }
+
+  Token token = Consume();
+  Type type = token.type();
+
+  if ((type == Type::ExternRef &&
+       !options_->features.reference_types_enabled()) ||
+      ((type == Type::Struct || type == Type::Array) &&
+       !options_->features.gc_enabled())) {
+    Error(token.loc, "value type not allowed: %s", type.GetName());
+    return Result::Error;
+  }
+
+  *out_type = type;
+  return Result::Ok;
+}
+
+Result WastParser::ParseRefType(Type* out_type) {
+  WABT_TRACE(ParseRefType);
+  if (!PeekMatch(TokenType::ValueType)) {
+    return ErrorExpected({"funcref", "externref"});
+  }
+
+  Token token = Consume();
+  Type type = token.type();
+  if (type == Type::ExternRef &&
+      !options_->features.reference_types_enabled()) {
+    Error(token.loc, "value type not allowed: %s", type.GetName());
+    return Result::Error;
+  }
+
+  *out_type = type;
+  return Result::Ok;
+}
+
+bool WastParser::ParseRefTypeOpt(Type* out_type) {
+  WABT_TRACE(ParseRefTypeOpt);
+  if (!PeekMatch(TokenType::ValueType)) {
+    return false;
+  }
+
+  Token token = Consume();
+  Type type = token.type();
+  if (type == Type::ExternRef &&
+      !options_->features.reference_types_enabled()) {
+    return false;
+  }
+
+  *out_type = type;
+  return true;
+}
+
+Result WastParser::ParseQuotedText(std::string* text) {
+  WABT_TRACE(ParseQuotedText);
+  if (!PeekMatch(TokenType::Text)) {
+    return ErrorExpected({"a quoted string"}, "\"foo\"");
+  }
+
+  Token token = Consume();
+  RemoveEscapes(token.text(), std::back_inserter(*text));
+  if (!IsValidUtf8(text->data(), text->length())) {
+    Error(token.loc, "quoted string has an invalid utf-8 encoding");
+  }
+  return Result::Ok;
+}
+
+bool WastParser::ParseOffsetOpt(Address* out_offset) {
+  WABT_TRACE(ParseOffsetOpt);
+  if (PeekMatch(TokenType::OffsetEqNat)) {
+    Token token = Consume();
+    uint64_t offset64;
+    string_view sv = token.text();
+    if (Failed(ParseInt64(sv.begin(), sv.end(), &offset64,
+                          ParseIntType::SignedAndUnsigned))) {
+      Error(token.loc, "invalid offset \"" PRIstringview "\"",
+            WABT_PRINTF_STRING_VIEW_ARG(sv));
+    }
+    // FIXME: make this depend on the current memory.
+    if (offset64 > UINT32_MAX) {
+      Error(token.loc, "offset must be less than or equal to 0xffffffff");
+    }
+    *out_offset = offset64;
+    return true;
+  } else {
+    *out_offset = 0;
+    return false;
+  }
+}
+
+bool WastParser::ParseAlignOpt(Address* out_align) {
+  WABT_TRACE(ParseAlignOpt);
+  if (PeekMatch(TokenType::AlignEqNat)) {
+    Token token = Consume();
+    string_view sv = token.text();
+    if (Failed(ParseInt64(sv.begin(), sv.end(), out_align,
+                          ParseIntType::UnsignedOnly))) {
+      Error(token.loc, "invalid alignment \"" PRIstringview "\"",
+            WABT_PRINTF_STRING_VIEW_ARG(sv));
+    }
+
+    if (!IsPowerOfTwo(*out_align)) {
+      Error(token.loc, "alignment must be power-of-two");
+    }
+
+    return true;
+  } else {
+    *out_align = WABT_USE_NATURAL_ALIGNMENT;
+    return false;
+  }
+}
+
+Result WastParser::ParseLimitsIndex(Limits* out_limits) {
+  WABT_TRACE(ParseLimitsIndex);
+
+  if (PeekMatch(TokenType::ValueType)) {
+    if (GetToken().type() == Type::I64) {
+      Consume();
+      out_limits->is_64 = true;
+    } else if (GetToken().type() == Type::I32) {
+      Consume();
+      out_limits->is_64 = false;
+    }
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseLimits(Limits* out_limits) {
+  WABT_TRACE(ParseLimits);
+
+  CHECK_RESULT(ParseNat(&out_limits->initial));
+  if (PeekMatch(TokenType::Nat)) {
+    CHECK_RESULT(ParseNat(&out_limits->max));
+    out_limits->has_max = true;
+  } else {
+    out_limits->has_max = false;
+  }
+
+  if (Match(TokenType::Shared)) {
+    out_limits->is_shared = true;
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseNat(uint64_t* out_nat) {
+  WABT_TRACE(ParseNat);
+  if (!PeekMatch(TokenType::Nat)) {
+    return ErrorExpected({"a natural number"}, "123");
+  }
+
+  Token token = Consume();
+  string_view sv = token.literal().text;
+  if (Failed(ParseUint64(sv.begin(), sv.end(), out_nat)) ||
+      *out_nat > 0xffffffffu) {
+    Error(token.loc, "invalid int \"" PRIstringview "\"",
+          WABT_PRINTF_STRING_VIEW_ARG(sv));
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseModule(std::unique_ptr<Module>* out_module) {
+  WABT_TRACE(ParseModule);
+  auto module = MakeUnique<Module>();
+
+  if (PeekMatchLpar(TokenType::Module)) {
+    // Starts with "(module". Allow text and binary modules, but no quoted
+    // modules.
+    CommandPtr command;
+    CHECK_RESULT(ParseModuleCommand(nullptr, &command));
+    auto module_command = cast<ModuleCommand>(std::move(command));
+    *module = std::move(module_command->module);
+  } else if (IsModuleField(PeekPair())) {
+    // Parse an inline module (i.e. one with no surrounding (module)).
+    CHECK_RESULT(ParseModuleFieldList(module.get()));
+  } else {
+    ConsumeIfLpar();
+    ErrorExpected({"a module field", "a module"});
+  }
+
+  EXPECT(Eof);
+  if (errors_->size() == 0) {
+    *out_module = std::move(module);
+    return Result::Ok;
+  } else {
+    return Result::Error;
+  }
+}
+
+Result WastParser::ParseScript(std::unique_ptr<Script>* out_script) {
+  WABT_TRACE(ParseScript);
+  auto script = MakeUnique<Script>();
+
+  // Don't consume the Lpar yet, even though it is required. This way the
+  // sub-parser functions (e.g. ParseFuncModuleField) can consume it and keep
+  // the parsing structure more regular.
+  if (IsModuleField(PeekPair())) {
+    // Parse an inline module (i.e. one with no surrounding (module)).
+    auto command = MakeUnique<ModuleCommand>();
+    command->module.loc = GetLocation();
+    CHECK_RESULT(ParseModuleFieldList(&command->module));
+    script->commands.emplace_back(std::move(command));
+  } else if (IsCommand(PeekPair())) {
+    CHECK_RESULT(ParseCommandList(script.get(), &script->commands));
+  } else {
+    ConsumeIfLpar();
+    ErrorExpected({"a module field", "a command"});
+  }
+
+  EXPECT(Eof);
+  if (errors_->size() == 0) {
+    *out_script = std::move(script);
+    return Result::Ok;
+  } else {
+    return Result::Error;
+  }
+}
+
+Result WastParser::ParseModuleFieldList(Module* module) {
+  WABT_TRACE(ParseModuleFieldList);
+  while (IsModuleField(PeekPair())) {
+    if (Failed(ParseModuleField(module))) {
+      CHECK_RESULT(Synchronize(IsModuleField));
+    }
+  }
+  CHECK_RESULT(ResolveFuncTypes(module, errors_));
+  CHECK_RESULT(ResolveNamesModule(module, errors_));
+  return Result::Ok;
+}
+
+Result WastParser::ParseModuleField(Module* module) {
+  WABT_TRACE(ParseModuleField);
+  switch (Peek(1)) {
+    case TokenType::Data:   return ParseDataModuleField(module);
+    case TokenType::Elem:   return ParseElemModuleField(module);
+    case TokenType::Event:  return ParseEventModuleField(module);
+    case TokenType::Export: return ParseExportModuleField(module);
+    case TokenType::Func:   return ParseFuncModuleField(module);
+    case TokenType::Type:   return ParseTypeModuleField(module);
+    case TokenType::Global: return ParseGlobalModuleField(module);
+    case TokenType::Import: return ParseImportModuleField(module);
+    case TokenType::Memory: return ParseMemoryModuleField(module);
+    case TokenType::Start:  return ParseStartModuleField(module);
+    case TokenType::Table:  return ParseTableModuleField(module);
+    default:
+      assert(
+          !"ParseModuleField should only be called if IsModuleField() is true");
+      return Result::Error;
+  }
+}
+
+Result WastParser::ParseDataModuleField(Module* module) {
+  WABT_TRACE(ParseDataModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Data);
+  std::string name;
+  ParseBindVarOpt(&name);
+  auto field = MakeUnique<DataSegmentModuleField>(loc, name);
+
+  if (PeekMatchLpar(TokenType::Memory)) {
+    EXPECT(Lpar);
+    EXPECT(Memory);
+    CHECK_RESULT(ParseVar(&field->data_segment.memory_var));
+    EXPECT(Rpar);
+    CHECK_RESULT(ParseOffsetExpr(&field->data_segment.offset));
+  } else if (ParseVarOpt(&field->data_segment.memory_var, Var(0, loc))) {
+    CHECK_RESULT(ParseOffsetExpr(&field->data_segment.offset));
+  } else if (!ParseOffsetExprOpt(&field->data_segment.offset)) {
+    if (!options_->features.bulk_memory_enabled()) {
+      Error(loc, "passive data segments are not allowed");
+      return Result::Error;
+    }
+
+    field->data_segment.kind = SegmentKind::Passive;
+  }
+
+  ParseTextListOpt(&field->data_segment.data);
+  EXPECT(Rpar);
+  module->AppendField(std::move(field));
+  return Result::Ok;
+}
+
+Result WastParser::ParseElemModuleField(Module* module) {
+  WABT_TRACE(ParseElemModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Elem);
+
+  // With MVP text format the name here was intended to refer to the table
+  // that the elem segment was part of, but we never did anything with this name
+  // since there was only one table anyway.
+  // With bulk-memory enabled this introduces a new name for the particular
+  // elem segment.
+  std::string initial_name;
+  bool has_name = ParseBindVarOpt(&initial_name);
+
+  std::string segment_name = initial_name;
+  if (!options_->features.bulk_memory_enabled()) {
+    segment_name = "";
+  }
+  auto field = MakeUnique<ElemSegmentModuleField>(loc, segment_name);
+  if (options_->features.reference_types_enabled() &&
+      Match(TokenType::Declare)) {
+    field->elem_segment.kind = SegmentKind::Declared;
+  }
+
+  // Optional table specifier
+  if (options_->features.bulk_memory_enabled()) {
+    if (PeekMatchLpar(TokenType::Table)) {
+      EXPECT(Lpar);
+      EXPECT(Table);
+      CHECK_RESULT(ParseVar(&field->elem_segment.table_var));
+      EXPECT(Rpar);
+    } else {
+      ParseVarOpt(&field->elem_segment.table_var, Var(0, loc));
+    }
+  } else {
+    if (has_name) {
+      field->elem_segment.table_var = Var(initial_name, loc);
+    } else {
+      ParseVarOpt(&field->elem_segment.table_var, Var(0, loc));
+    }
+  }
+
+  // Parse offset expression, if not declared/passive segment.
+  if (options_->features.bulk_memory_enabled()) {
+    if (field->elem_segment.kind != SegmentKind::Declared &&
+        !ParseOffsetExprOpt(&field->elem_segment.offset)) {
+      field->elem_segment.kind = SegmentKind::Passive;
+    }
+  } else {
+    CHECK_RESULT(ParseOffsetExpr(&field->elem_segment.offset));
+  }
+
+  if (ParseRefTypeOpt(&field->elem_segment.elem_type)) {
+    ParseElemExprListOpt(&field->elem_segment.elem_exprs);
+  } else {
+    field->elem_segment.elem_type = Type::FuncRef;
+    if (PeekMatch(TokenType::Func)) {
+      EXPECT(Func);
+    }
+    ParseElemExprVarListOpt(&field->elem_segment.elem_exprs);
+  }
+  EXPECT(Rpar);
+  module->AppendField(std::move(field));
+  return Result::Ok;
+}
+
+Result WastParser::ParseEventModuleField(Module* module) {
+  WABT_TRACE(ParseEventModuleField);
+  EXPECT(Lpar);
+  auto field = MakeUnique<EventModuleField>(GetLocation());
+  EXPECT(Event);
+  ParseBindVarOpt(&field->event.name);
+  CHECK_RESULT(ParseTypeUseOpt(&field->event.decl));
+  CHECK_RESULT(ParseUnboundFuncSignature(&field->event.decl.sig));
+  EXPECT(Rpar);
+  module->AppendField(std::move(field));
+  return Result::Ok;
+}
+
+Result WastParser::ParseExportModuleField(Module* module) {
+  WABT_TRACE(ParseExportModuleField);
+  EXPECT(Lpar);
+  auto field = MakeUnique<ExportModuleField>(GetLocation());
+  EXPECT(Export);
+  CHECK_RESULT(ParseQuotedText(&field->export_.name));
+  CHECK_RESULT(ParseExportDesc(&field->export_));
+  EXPECT(Rpar);
+  module->AppendField(std::move(field));
+  return Result::Ok;
+}
+
+Result WastParser::ParseFuncModuleField(Module* module) {
+  WABT_TRACE(ParseFuncModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Func);
+  std::string name;
+  ParseBindVarOpt(&name);
+
+  ModuleFieldList export_fields;
+  CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Func));
+
+  if (PeekMatchLpar(TokenType::Import)) {
+    CheckImportOrdering(module);
+    auto import = MakeUnique<FuncImport>(name);
+    Func& func = import->func;
+    CHECK_RESULT(ParseInlineImport(import.get()));
+    CHECK_RESULT(ParseTypeUseOpt(&func.decl));
+    CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings));
+    CHECK_RESULT(ErrorIfLpar({"type", "param", "result"}));
+    auto field =
+        MakeUnique<ImportModuleField>(std::move(import), GetLocation());
+    module->AppendField(std::move(field));
+  } else {
+    auto field = MakeUnique<FuncModuleField>(loc, name);
+    Func& func = field->func;
+    CHECK_RESULT(ParseTypeUseOpt(&func.decl));
+    CHECK_RESULT(ParseFuncSignature(&func.decl.sig, &func.bindings));
+    TypeVector local_types;
+    CHECK_RESULT(ParseBoundValueTypeList(TokenType::Local, &local_types,
+                                         &func.bindings, func.GetNumParams()));
+    func.local_types.Set(local_types);
+    CHECK_RESULT(ParseTerminatingInstrList(&func.exprs));
+    module->AppendField(std::move(field));
+  }
+
+  AppendInlineExportFields(module, &export_fields, module->funcs.size() - 1);
+
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseTypeModuleField(Module* module) {
+  WABT_TRACE(ParseTypeModuleField);
+  EXPECT(Lpar);
+  auto field = MakeUnique<TypeModuleField>(GetLocation());
+  EXPECT(Type);
+
+  std::string name;
+  ParseBindVarOpt(&name);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+
+  if (Match(TokenType::Func)) {
+    auto func_type = MakeUnique<FuncType>(name);
+    BindingHash bindings;
+    CHECK_RESULT(ParseFuncSignature(&func_type->sig, &bindings));
+    CHECK_RESULT(ErrorIfLpar({"param", "result"}));
+    field->type = std::move(func_type);
+  } else if (Match(TokenType::Struct)) {
+    if (!options_->features.gc_enabled()) {
+      Error(loc, "struct not allowed");
+      return Result::Error;
+    }
+    auto struct_type = MakeUnique<StructType>(name);
+    CHECK_RESULT(ParseFieldList(&struct_type->fields));
+    field->type = std::move(struct_type);
+  } else if (Match(TokenType::Array)) {
+    if (!options_->features.gc_enabled()) {
+      Error(loc, "array type not allowed");
+    }
+    auto array_type = MakeUnique<ArrayType>(name);
+    CHECK_RESULT(ParseField(&array_type->field));
+    field->type = std::move(array_type);
+  } else {
+    return ErrorExpected({"func", "struct", "array"});
+  }
+
+  EXPECT(Rpar);
+  EXPECT(Rpar);
+  module->AppendField(std::move(field));
+  return Result::Ok;
+}
+
+Result WastParser::ParseField(Field* field) {
+  WABT_TRACE(ParseField);
+  auto parse_mut_valuetype = [&]() -> Result {
+    // TODO: Share with ParseGlobalType?
+    if (MatchLpar(TokenType::Mut)) {
+      field->mutable_ = true;
+      CHECK_RESULT(ParseValueType(&field->type));
+      EXPECT(Rpar);
+    } else {
+      field->mutable_ = false;
+      CHECK_RESULT(ParseValueType(&field->type));
+    }
+    return Result::Ok;
+  };
+
+  if (MatchLpar(TokenType::Field)) {
+    ParseBindVarOpt(&field->name);
+    CHECK_RESULT(parse_mut_valuetype());
+    EXPECT(Rpar);
+  } else {
+    CHECK_RESULT(parse_mut_valuetype());
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseFieldList(std::vector<Field>* fields) {
+  WABT_TRACE(ParseFieldList);
+  while (PeekMatch(TokenType::ValueType) || PeekMatch(TokenType::Lpar)) {
+    Field field;
+    CHECK_RESULT(ParseField(&field));
+    fields->push_back(field);
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseGlobalModuleField(Module* module) {
+  WABT_TRACE(ParseGlobalModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Global);
+  std::string name;
+  ParseBindVarOpt(&name);
+
+  ModuleFieldList export_fields;
+  CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Global));
+
+  if (PeekMatchLpar(TokenType::Import)) {
+    CheckImportOrdering(module);
+    auto import = MakeUnique<GlobalImport>(name);
+    CHECK_RESULT(ParseInlineImport(import.get()));
+    CHECK_RESULT(ParseGlobalType(&import->global));
+    auto field =
+        MakeUnique<ImportModuleField>(std::move(import), GetLocation());
+    module->AppendField(std::move(field));
+  } else {
+    auto field = MakeUnique<GlobalModuleField>(loc, name);
+    CHECK_RESULT(ParseGlobalType(&field->global));
+    CHECK_RESULT(ParseTerminatingInstrList(&field->global.init_expr));
+    module->AppendField(std::move(field));
+  }
+
+  AppendInlineExportFields(module, &export_fields, module->globals.size() - 1);
+
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseImportModuleField(Module* module) {
+  WABT_TRACE(ParseImportModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  CheckImportOrdering(module);
+  EXPECT(Import);
+  std::string module_name;
+  std::string field_name;
+  CHECK_RESULT(ParseQuotedText(&module_name));
+  CHECK_RESULT(ParseQuotedText(&field_name));
+  EXPECT(Lpar);
+
+  std::unique_ptr<ImportModuleField> field;
+  std::string name;
+
+  switch (Peek()) {
+    case TokenType::Func: {
+      Consume();
+      ParseBindVarOpt(&name);
+      auto import = MakeUnique<FuncImport>(name);
+      if (PeekMatchLpar(TokenType::Type)) {
+        import->func.decl.has_func_type = true;
+        CHECK_RESULT(ParseTypeUseOpt(&import->func.decl));
+        EXPECT(Rpar);
+      } else {
+        CHECK_RESULT(
+            ParseFuncSignature(&import->func.decl.sig, &import->func.bindings));
+        CHECK_RESULT(ErrorIfLpar({"param", "result"}));
+        EXPECT(Rpar);
+      }
+      field = MakeUnique<ImportModuleField>(std::move(import), loc);
+      break;
+    }
+
+    case TokenType::Table: {
+      Consume();
+      ParseBindVarOpt(&name);
+      auto import = MakeUnique<TableImport>(name);
+      CHECK_RESULT(ParseLimits(&import->table.elem_limits));
+      CHECK_RESULT(ParseRefType(&import->table.elem_type));
+      EXPECT(Rpar);
+      field = MakeUnique<ImportModuleField>(std::move(import), loc);
+      break;
+    }
+
+    case TokenType::Memory: {
+      Consume();
+      ParseBindVarOpt(&name);
+      auto import = MakeUnique<MemoryImport>(name);
+      CHECK_RESULT(ParseLimitsIndex(&import->memory.page_limits));
+      CHECK_RESULT(ParseLimits(&import->memory.page_limits));
+      EXPECT(Rpar);
+      field = MakeUnique<ImportModuleField>(std::move(import), loc);
+      break;
+    }
+
+    case TokenType::Global: {
+      Consume();
+      ParseBindVarOpt(&name);
+      auto import = MakeUnique<GlobalImport>(name);
+      CHECK_RESULT(ParseGlobalType(&import->global));
+      EXPECT(Rpar);
+      field = MakeUnique<ImportModuleField>(std::move(import), loc);
+      break;
+    }
+
+    case TokenType::Event: {
+      Consume();
+      ParseBindVarOpt(&name);
+      auto import = MakeUnique<EventImport>(name);
+      CHECK_RESULT(ParseTypeUseOpt(&import->event.decl));
+      CHECK_RESULT(ParseUnboundFuncSignature(&import->event.decl.sig));
+      EXPECT(Rpar);
+      field = MakeUnique<ImportModuleField>(std::move(import), loc);
+      break;
+    }
+
+    default:
+      return ErrorExpected({"an external kind"});
+  }
+
+  field->import->module_name = module_name;
+  field->import->field_name = field_name;
+
+  module->AppendField(std::move(field));
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseMemoryModuleField(Module* module) {
+  WABT_TRACE(ParseMemoryModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Memory);
+  std::string name;
+  ParseBindVarOpt(&name);
+
+  ModuleFieldList export_fields;
+  CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Memory));
+
+  if (PeekMatchLpar(TokenType::Import)) {
+    CheckImportOrdering(module);
+    auto import = MakeUnique<MemoryImport>(name);
+    CHECK_RESULT(ParseInlineImport(import.get()));
+    CHECK_RESULT(ParseLimitsIndex(&import->memory.page_limits));
+    CHECK_RESULT(ParseLimits(&import->memory.page_limits));
+    auto field =
+        MakeUnique<ImportModuleField>(std::move(import), GetLocation());
+    module->AppendField(std::move(field));
+  } else {
+    auto field = MakeUnique<MemoryModuleField>(loc, name);
+    CHECK_RESULT(ParseLimitsIndex(&field->memory.page_limits));
+    if (MatchLpar(TokenType::Data)) {
+      auto data_segment_field = MakeUnique<DataSegmentModuleField>(loc);
+      DataSegment& data_segment = data_segment_field->data_segment;
+      data_segment.memory_var = Var(module->memories.size());
+      data_segment.offset.push_back(MakeUnique<ConstExpr>(Const::I32(0)));
+      data_segment.offset.back().loc = loc;
+      ParseTextListOpt(&data_segment.data);
+      EXPECT(Rpar);
+
+      uint32_t byte_size = WABT_ALIGN_UP_TO_PAGE(data_segment.data.size());
+      uint32_t page_size = WABT_BYTES_TO_PAGES(byte_size);
+      field->memory.page_limits.initial = page_size;
+      field->memory.page_limits.max = page_size;
+      field->memory.page_limits.has_max = true;
+
+      module->AppendField(std::move(field));
+      module->AppendField(std::move(data_segment_field));
+    } else {
+      CHECK_RESULT(ParseLimits(&field->memory.page_limits));
+      module->AppendField(std::move(field));
+    }
+  }
+
+  AppendInlineExportFields(module, &export_fields, module->memories.size() - 1);
+
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseStartModuleField(Module* module) {
+  WABT_TRACE(ParseStartModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  if (module->starts.size() > 0) {
+    Error(loc, "multiple start sections");
+    return Result::Error;
+  }
+  EXPECT(Start);
+  Var var;
+  CHECK_RESULT(ParseVar(&var));
+  EXPECT(Rpar);
+  module->AppendField(MakeUnique<StartModuleField>(var, loc));
+  return Result::Ok;
+}
+
+Result WastParser::ParseTableModuleField(Module* module) {
+  WABT_TRACE(ParseTableModuleField);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Table);
+  std::string name;
+  ParseBindVarOpt(&name);
+
+  ModuleFieldList export_fields;
+  CHECK_RESULT(ParseInlineExports(&export_fields, ExternalKind::Table));
+
+  if (PeekMatchLpar(TokenType::Import)) {
+    CheckImportOrdering(module);
+    auto import = MakeUnique<TableImport>(name);
+    CHECK_RESULT(ParseInlineImport(import.get()));
+    CHECK_RESULT(ParseLimits(&import->table.elem_limits));
+    CHECK_RESULT(ParseRefType(&import->table.elem_type));
+    auto field =
+        MakeUnique<ImportModuleField>(std::move(import), GetLocation());
+    module->AppendField(std::move(field));
+  } else if (PeekMatch(TokenType::ValueType)) {
+    Type elem_type;
+    CHECK_RESULT(ParseRefType(&elem_type));
+
+    EXPECT(Lpar);
+    EXPECT(Elem);
+
+    auto elem_segment_field = MakeUnique<ElemSegmentModuleField>(loc);
+    ElemSegment& elem_segment = elem_segment_field->elem_segment;
+    elem_segment.table_var = Var(module->tables.size());
+    elem_segment.offset.push_back(MakeUnique<ConstExpr>(Const::I32(0)));
+    elem_segment.offset.back().loc = loc;
+    elem_segment.elem_type = elem_type;
+    // Syntax is either an optional list of var (legacy), or a non-empty list
+    // of elem expr.
+    ElemExpr elem_expr;
+    if (ParseElemExprOpt(&elem_expr)) {
+      elem_segment.elem_exprs.push_back(elem_expr);
+      // Parse the rest.
+      ParseElemExprListOpt(&elem_segment.elem_exprs);
+    } else {
+      ParseElemExprVarListOpt(&elem_segment.elem_exprs);
+    }
+    EXPECT(Rpar);
+
+    auto table_field = MakeUnique<TableModuleField>(loc, name);
+    table_field->table.elem_limits.initial = elem_segment.elem_exprs.size();
+    table_field->table.elem_limits.max = elem_segment.elem_exprs.size();
+    table_field->table.elem_limits.has_max = true;
+    table_field->table.elem_type = elem_type;
+    module->AppendField(std::move(table_field));
+    module->AppendField(std::move(elem_segment_field));
+  } else {
+    auto field = MakeUnique<TableModuleField>(loc, name);
+    CHECK_RESULT(ParseLimits(&field->table.elem_limits));
+    CHECK_RESULT(ParseRefType(&field->table.elem_type));
+    module->AppendField(std::move(field));
+  }
+
+  AppendInlineExportFields(module, &export_fields, module->tables.size() - 1);
+
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseExportDesc(Export* export_) {
+  WABT_TRACE(ParseExportDesc);
+  EXPECT(Lpar);
+  switch (Peek()) {
+    case TokenType::Func:   export_->kind = ExternalKind::Func; break;
+    case TokenType::Table:  export_->kind = ExternalKind::Table; break;
+    case TokenType::Memory: export_->kind = ExternalKind::Memory; break;
+    case TokenType::Global: export_->kind = ExternalKind::Global; break;
+    case TokenType::Event:  export_->kind = ExternalKind::Event; break;
+    default:
+      return ErrorExpected({"an external kind"});
+  }
+  Consume();
+  CHECK_RESULT(ParseVar(&export_->var));
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseInlineExports(ModuleFieldList* fields,
+                                      ExternalKind kind) {
+  WABT_TRACE(ParseInlineExports);
+  while (PeekMatchLpar(TokenType::Export)) {
+    EXPECT(Lpar);
+    auto field = MakeUnique<ExportModuleField>(GetLocation());
+    field->export_.kind = kind;
+    EXPECT(Export);
+    CHECK_RESULT(ParseQuotedText(&field->export_.name));
+    EXPECT(Rpar);
+    fields->push_back(std::move(field));
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseInlineImport(Import* import) {
+  WABT_TRACE(ParseInlineImport);
+  EXPECT(Lpar);
+  EXPECT(Import);
+  CHECK_RESULT(ParseQuotedText(&import->module_name));
+  CHECK_RESULT(ParseQuotedText(&import->field_name));
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseTypeUseOpt(FuncDeclaration* decl) {
+  WABT_TRACE(ParseTypeUseOpt);
+  if (MatchLpar(TokenType::Type)) {
+    decl->has_func_type = true;
+    CHECK_RESULT(ParseVar(&decl->type_var));
+    EXPECT(Rpar);
+  } else {
+    decl->has_func_type = false;
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseFuncSignature(FuncSignature* sig,
+                                      BindingHash* param_bindings) {
+  WABT_TRACE(ParseFuncSignature);
+  CHECK_RESULT(ParseBoundValueTypeList(TokenType::Param, &sig->param_types,
+                                       param_bindings));
+  CHECK_RESULT(ParseResultList(&sig->result_types));
+  return Result::Ok;
+}
+
+Result WastParser::ParseUnboundFuncSignature(FuncSignature* sig) {
+  WABT_TRACE(ParseUnboundFuncSignature);
+  CHECK_RESULT(ParseUnboundValueTypeList(TokenType::Param, &sig->param_types));
+  CHECK_RESULT(ParseResultList(&sig->result_types));
+  return Result::Ok;
+}
+
+Result WastParser::ParseBoundValueTypeList(TokenType token,
+                                           TypeVector* types,
+                                           BindingHash* bindings,
+                                           Index binding_index_offset) {
+  WABT_TRACE(ParseBoundValueTypeList);
+  while (MatchLpar(token)) {
+    if (PeekMatch(TokenType::Var)) {
+      std::string name;
+      Type type;
+      Location loc = GetLocation();
+      ParseBindVarOpt(&name);
+      CHECK_RESULT(ParseValueType(&type));
+      bindings->emplace(name,
+                        Binding(loc, binding_index_offset + types->size()));
+      types->push_back(type);
+    } else {
+      CHECK_RESULT(ParseValueTypeList(types));
+    }
+    EXPECT(Rpar);
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseUnboundValueTypeList(TokenType token,
+                                             TypeVector* types) {
+  WABT_TRACE(ParseUnboundValueTypeList);
+  while (MatchLpar(token)) {
+    CHECK_RESULT(ParseValueTypeList(types));
+    EXPECT(Rpar);
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseResultList(TypeVector* result_types) {
+  WABT_TRACE(ParseResultList);
+  return ParseUnboundValueTypeList(TokenType::Result, result_types);
+}
+
+Result WastParser::ParseInstrList(ExprList* exprs) {
+  WABT_TRACE(ParseInstrList);
+  ExprList new_exprs;
+  while (IsInstr(PeekPair())) {
+    if (Succeeded(ParseInstr(&new_exprs))) {
+      exprs->splice(exprs->end(), new_exprs);
+    } else {
+      CHECK_RESULT(Synchronize(IsInstr));
+    }
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseTerminatingInstrList(ExprList* exprs) {
+  WABT_TRACE(ParseTerminatingInstrList);
+  Result result = ParseInstrList(exprs);
+  // An InstrList often has no further Lpar following it, because it would have
+  // gobbled it up. So if there is a following Lpar it is an error. If we
+  // handle it here we can produce a nicer error message.
+  CHECK_RESULT(ErrorIfLpar({"an instr"}));
+  return result;
+}
+
+Result WastParser::ParseInstr(ExprList* exprs) {
+  WABT_TRACE(ParseInstr);
+  if (IsPlainInstr(Peek())) {
+    std::unique_ptr<Expr> expr;
+    CHECK_RESULT(ParsePlainInstr(&expr));
+    exprs->push_back(std::move(expr));
+    return Result::Ok;
+  } else if (IsBlockInstr(Peek())) {
+    std::unique_ptr<Expr> expr;
+    CHECK_RESULT(ParseBlockInstr(&expr));
+    exprs->push_back(std::move(expr));
+    return Result::Ok;
+  } else if (PeekMatchExpr()) {
+    return ParseExpr(exprs);
+  } else {
+    assert(!"ParseInstr should only be called when IsInstr() is true");
+    return Result::Error;
+  }
+}
+
+template <typename T>
+Result WastParser::ParsePlainInstrVar(Location loc,
+                                      std::unique_ptr<Expr>* out_expr) {
+  Var var;
+  CHECK_RESULT(ParseVar(&var));
+  out_expr->reset(new T(var, loc));
+  return Result::Ok;
+}
+
+template <typename T>
+Result WastParser::ParsePlainLoadStoreInstr(Location loc,
+                                            Token token,
+                                            std::unique_ptr<Expr>* out_expr) {
+  Opcode opcode = token.opcode();
+  Address offset;
+  Address align;
+  ParseOffsetOpt(&offset);
+  ParseAlignOpt(&align);
+  out_expr->reset(new T(opcode, align, offset, loc));
+  return Result::Ok;
+}
+
+Result WastParser::ParsePlainInstr(std::unique_ptr<Expr>* out_expr) {
+  WABT_TRACE(ParsePlainInstr);
+  Location loc = GetLocation();
+  switch (Peek()) {
+    case TokenType::Unreachable:
+      Consume();
+      out_expr->reset(new UnreachableExpr(loc));
+      break;
+
+    case TokenType::Nop:
+      Consume();
+      out_expr->reset(new NopExpr(loc));
+      break;
+
+    case TokenType::Drop:
+      Consume();
+      out_expr->reset(new DropExpr(loc));
+      break;
+
+    case TokenType::Select: {
+      Consume();
+      TypeVector result;
+      if (options_->features.reference_types_enabled() &&
+          MatchLpar(TokenType::Result)) {
+        CHECK_RESULT(ParseValueTypeList(&result));
+        EXPECT(Rpar);
+      }
+      out_expr->reset(new SelectExpr(result, loc));
+      break;
+    }
+
+    case TokenType::Br:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<BrExpr>(loc, out_expr));
+      break;
+
+    case TokenType::BrIf:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<BrIfExpr>(loc, out_expr));
+      break;
+
+    case TokenType::BrTable: {
+      Consume();
+      auto expr = MakeUnique<BrTableExpr>(loc);
+      CHECK_RESULT(ParseVarList(&expr->targets));
+      expr->default_target = expr->targets.back();
+      expr->targets.pop_back();
+      *out_expr = std::move(expr);
+      break;
+    }
+
+    case TokenType::Return:
+      Consume();
+      out_expr->reset(new ReturnExpr(loc));
+      break;
+
+    case TokenType::Call:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<CallExpr>(loc, out_expr));
+      break;
+
+    case TokenType::CallIndirect: {
+      Consume();
+      auto expr = MakeUnique<CallIndirectExpr>(loc);
+      ParseVarOpt(&expr->table, Var(0, loc));
+      CHECK_RESULT(ParseTypeUseOpt(&expr->decl));
+      CHECK_RESULT(ParseUnboundFuncSignature(&expr->decl.sig));
+      *out_expr = std::move(expr);
+      break;
+    }
+
+    case TokenType::ReturnCall:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<ReturnCallExpr>(loc, out_expr));
+      break;
+
+    case TokenType::ReturnCallIndirect: {
+      ErrorUnlessOpcodeEnabled(Consume());
+      auto expr = MakeUnique<ReturnCallIndirectExpr>(loc);
+      CHECK_RESULT(ParseTypeUseOpt(&expr->decl));
+      CHECK_RESULT(ParseUnboundFuncSignature(&expr->decl.sig));
+      ParseVarOpt(&expr->table, Var(0, loc));
+      *out_expr = std::move(expr);
+      break;
+    }
+
+    case TokenType::LocalGet:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<LocalGetExpr>(loc, out_expr));
+      break;
+
+    case TokenType::LocalSet:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<LocalSetExpr>(loc, out_expr));
+      break;
+
+    case TokenType::LocalTee:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<LocalTeeExpr>(loc, out_expr));
+      break;
+
+    case TokenType::GlobalGet:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<GlobalGetExpr>(loc, out_expr));
+      break;
+
+    case TokenType::GlobalSet:
+      Consume();
+      CHECK_RESULT(ParsePlainInstrVar<GlobalSetExpr>(loc, out_expr));
+      break;
+
+    case TokenType::Load:
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<LoadExpr>(loc, Consume(), out_expr));
+      break;
+
+    case TokenType::Store:
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<StoreExpr>(loc, Consume(), out_expr));
+      break;
+
+    case TokenType::Const: {
+      Const const_;
+      CHECK_RESULT(ParseConst(&const_, ConstType::Normal));
+      out_expr->reset(new ConstExpr(const_, loc));
+      break;
+    }
+
+    case TokenType::Unary: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      out_expr->reset(new UnaryExpr(token.opcode(), loc));
+      break;
+    }
+
+    case TokenType::Binary: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      out_expr->reset(new BinaryExpr(token.opcode(), loc));
+      break;
+    }
+
+    case TokenType::Compare:
+      out_expr->reset(new CompareExpr(Consume().opcode(), loc));
+      break;
+
+    case TokenType::Convert: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      out_expr->reset(new ConvertExpr(token.opcode(), loc));
+      break;
+    }
+
+    case TokenType::MemoryCopy:
+      ErrorUnlessOpcodeEnabled(Consume());
+      out_expr->reset(new MemoryCopyExpr(loc));
+      break;
+
+    case TokenType::MemoryFill:
+      ErrorUnlessOpcodeEnabled(Consume());
+      out_expr->reset(new MemoryFillExpr(loc));
+      break;
+
+    case TokenType::DataDrop:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<DataDropExpr>(loc, out_expr));
+      break;
+
+    case TokenType::MemoryInit:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<MemoryInitExpr>(loc, out_expr));
+      break;
+
+    case TokenType::MemorySize:
+      Consume();
+      out_expr->reset(new MemorySizeExpr(loc));
+      break;
+
+    case TokenType::MemoryGrow:
+      Consume();
+      out_expr->reset(new MemoryGrowExpr(loc));
+      break;
+
+    case TokenType::TableCopy: {
+      ErrorUnlessOpcodeEnabled(Consume());
+      Var dst(0, loc);
+      Var src(0, loc);
+      if (options_->features.reference_types_enabled()) {
+        ParseVarOpt(&dst, dst);
+        ParseVarOpt(&src, src);
+      }
+      out_expr->reset(new TableCopyExpr(dst, src, loc));
+      break;
+    }
+
+    case TokenType::ElemDrop:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<ElemDropExpr>(loc, out_expr));
+      break;
+
+    case TokenType::TableInit: {
+      ErrorUnlessOpcodeEnabled(Consume());
+      Var segment_index(0, loc);
+      CHECK_RESULT(ParseVar(&segment_index));
+      Var table_index(0, loc);
+      if (ParseVarOpt(&table_index, table_index)) {
+        // Here are the two forms:
+        //
+        //   table.init $elemidx ...
+        //   table.init $tableidx $elemidx ...
+        //
+        // So if both indexes are provided, we need to swap them.
+        std::swap(segment_index, table_index);
+      }
+      out_expr->reset(new TableInitExpr(segment_index, table_index, loc));
+      break;
+    }
+
+    case TokenType::TableGet:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<TableGetExpr>(loc, out_expr));
+      break;
+
+    case TokenType::TableSet:
+      ErrorUnlessOpcodeEnabled(Consume());
+      // TODO: Table index.
+      CHECK_RESULT(ParsePlainInstrVar<TableSetExpr>(loc, out_expr));
+      break;
+
+    case TokenType::TableGrow:
+      ErrorUnlessOpcodeEnabled(Consume());
+      // TODO: Table index.
+      CHECK_RESULT(ParsePlainInstrVar<TableGrowExpr>(loc, out_expr));
+      break;
+
+    case TokenType::TableSize:
+      ErrorUnlessOpcodeEnabled(Consume());
+      // TODO: Table index.
+      CHECK_RESULT(ParsePlainInstrVar<TableSizeExpr>(loc, out_expr));
+      break;
+
+    case TokenType::TableFill:
+      ErrorUnlessOpcodeEnabled(Consume());
+      // TODO: Table index.
+      CHECK_RESULT(ParsePlainInstrVar<TableFillExpr>(loc, out_expr));
+      break;
+
+    case TokenType::RefFunc:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<RefFuncExpr>(loc, out_expr));
+      break;
+
+    case TokenType::RefNull: {
+      ErrorUnlessOpcodeEnabled(Consume());
+      Type type;
+      CHECK_RESULT(ParseRefKind(&type));
+      out_expr->reset(new RefNullExpr(type, loc));
+      break;
+    }
+
+    case TokenType::RefIsNull:
+      ErrorUnlessOpcodeEnabled(Consume());
+      out_expr->reset(new RefIsNullExpr(loc));
+      break;
+
+    case TokenType::Throw:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<ThrowExpr>(loc, out_expr));
+      break;
+
+    case TokenType::Rethrow:
+      ErrorUnlessOpcodeEnabled(Consume());
+      CHECK_RESULT(ParsePlainInstrVar<RethrowExpr>(loc, out_expr));
+      break;
+
+    case TokenType::AtomicNotify: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<AtomicNotifyExpr>(loc, token, out_expr));
+      break;
+    }
+
+    case TokenType::AtomicFence: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      uint32_t consistency_model = 0x0;
+      out_expr->reset(new AtomicFenceExpr(consistency_model, loc));
+      break;
+    }
+
+    case TokenType::AtomicWait: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<AtomicWaitExpr>(loc, token, out_expr));
+      break;
+    }
+
+    case TokenType::AtomicLoad: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<AtomicLoadExpr>(loc, token, out_expr));
+      break;
+    }
+
+    case TokenType::AtomicStore: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<AtomicStoreExpr>(loc, token, out_expr));
+      break;
+    }
+
+    case TokenType::AtomicRmw: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<AtomicRmwExpr>(loc, token, out_expr));
+      break;
+    }
+
+    case TokenType::AtomicRmwCmpxchg: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      CHECK_RESULT(
+          ParsePlainLoadStoreInstr<AtomicRmwCmpxchgExpr>(loc, token, out_expr));
+      break;
+    }
+
+    case TokenType::Ternary: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      out_expr->reset(new TernaryExpr(token.opcode(), loc));
+      break;
+    }
+
+    case TokenType::SimdLaneOp: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      if (!PeekMatch(TokenType::Nat) && !PeekMatch(TokenType::Int)) {
+        return ErrorExpected({"a natural number"}, "123");
+      }
+
+      Literal literal = Consume().literal();
+      uint64_t lane_idx;
+
+      Result result = ParseInt64(literal.text.begin(), literal.text.end(),
+                                 &lane_idx, ParseIntType::UnsignedOnly);
+
+      if (Failed(result)) {
+        Error(loc, "invalid literal \"" PRIstringview "\"",
+              WABT_PRINTF_STRING_VIEW_ARG(literal.text));
+        return Result::Error;
+      }
+
+      // TODO: Should share lane validation logic w/ SimdShuffleOp below. (See
+      // comment below for explanation of 255 vs. 32)
+      if (lane_idx > 255) {
+        Error(loc, "lane index \"" PRIstringview "\" out-of-range [0, 32)",
+              WABT_PRINTF_STRING_VIEW_ARG(literal.text));
+        return Result::Error;
+      }
+      out_expr->reset(new SimdLaneOpExpr(token.opcode(), lane_idx, loc));
+      break;
+    }
+
+    case TokenType::SimdShuffleOp: {
+      Token token = Consume();
+      ErrorUnlessOpcodeEnabled(token);
+      v128 values;
+      for (int lane = 0; lane < 16; ++lane) {
+        Location loc = GetLocation();
+
+        if (!PeekMatch(TokenType::Nat)) {
+          return ErrorExpected({"a natural number in range [0, 32)"});
+        }
+
+        Literal literal = Consume().literal();
+
+        string_view sv = literal.text;
+        const char* s = sv.begin();
+        const char* end = sv.end();
+        Result result;
+
+        uint32_t value = 0;
+        result = ParseInt32(s, end, &value, ParseIntType::UnsignedOnly);
+
+        if (Failed(result)) {
+          Error(loc, "invalid literal \"" PRIstringview "\"",
+                WABT_PRINTF_STRING_VIEW_ARG(literal.text));
+          return Result::Error;
+        }
+
+        // The valid range is only [0, 32), but it's only malformed if it can't
+        // fit in a byte.
+        if (value > 255) {
+          Error(loc,
+                "shuffle index \"" PRIstringview "\" out-of-range [0, 32)",
+                WABT_PRINTF_STRING_VIEW_ARG(literal.text));
+          return Result::Error;
+        }
+
+        values.set_u8(lane, static_cast<uint8_t>(value));
+      }
+
+      out_expr->reset(
+          new SimdShuffleOpExpr(token.opcode(), values, loc));
+      break;
+    }
+
+    default:
+      assert(
+          !"ParsePlainInstr should only be called when IsPlainInstr() is true");
+      return Result::Error;
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseSimdV128Const(Const* const_,
+                                      TokenType token_type,
+                                      ConstType const_type) {
+  WABT_TRACE(ParseSimdV128Const);
+
+  uint8_t lane_count = 0;
+  bool integer = true;
+  switch (token_type) {
+    case TokenType::I8X16: { lane_count = 16; break; }
+    case TokenType::I16X8: { lane_count = 8; break; }
+    case TokenType::I32X4: { lane_count = 4; break; }
+    case TokenType::I64X2: { lane_count = 2; break; }
+    case TokenType::F32X4: { lane_count = 4; integer = false; break; }
+    case TokenType::F64X2: { lane_count = 2; integer = false; break; }
+    default: {
+      Error(
+        const_->loc,
+        "Unexpected type at start of simd constant. "
+        "Expected one of: i8x16, i16x8, i32x4, i64x2, f32x4, f64x2. "
+        "Found \"%s\".",
+        GetTokenTypeName(token_type)
+      );
+      return Result::Error;
+    }
+  }
+  Consume();
+
+  const_->loc = GetLocation();
+
+  for (int lane = 0; lane < lane_count; ++lane) {
+    Location loc = GetLocation();
+
+    // Check that the lane literal type matches the element type of the v128:
+    Token token = GetToken();
+    switch (token.token_type()) {
+      case TokenType::Nat:
+      case TokenType::Int:
+        // OK.
+        break;
+
+      case TokenType::Float:
+      case TokenType::NanArithmetic:
+      case TokenType::NanCanonical:
+        if (integer) {
+          goto error;
+        }
+        break;
+
+      error:
+      default:
+        if (integer) {
+          return ErrorExpected({"a Nat or Integer literal"}, "123");
+        } else {
+          return ErrorExpected({"a Float literal"}, "42.0");
+        }
+    }
+
+    Result result;
+
+    // For each type, parse the next literal, bound check it, and write it to
+    // the array of bytes:
+    if (integer) {
+      string_view sv = Consume().literal().text;
+      const char* s = sv.begin();
+      const char* end = sv.end();
+
+      switch (lane_count) {
+        case 16: {
+          uint8_t value = 0;
+          result = ParseInt8(s, end, &value, ParseIntType::SignedAndUnsigned);
+          const_->set_v128_u8(lane, value);
+          break;
+        }
+        case 8: {
+          uint16_t value = 0;
+          result = ParseInt16(s, end, &value, ParseIntType::SignedAndUnsigned);
+          const_->set_v128_u16(lane, value);
+          break;
+        }
+        case 4: {
+          uint32_t value = 0;
+          result = ParseInt32(s, end, &value, ParseIntType::SignedAndUnsigned);
+          const_->set_v128_u32(lane, value);
+          break;
+        }
+        case 2: {
+          uint64_t value = 0;
+          result = ParseInt64(s, end, &value, ParseIntType::SignedAndUnsigned);
+          const_->set_v128_u64(lane, value);
+          break;
+        }
+      }
+    } else {
+      Const lane_const_;
+      switch (lane_count) {
+        case 4:
+          result = ParseF32(&lane_const_, const_type);
+          const_->set_v128_f32(lane, lane_const_.f32_bits());
+          break;
+
+        case 2:
+          result = ParseF64(&lane_const_, const_type);
+          const_->set_v128_f64(lane, lane_const_.f64_bits());
+          break;
+      }
+
+      const_->set_expected_nan(lane, lane_const_.expected_nan());
+    }
+
+    if (Failed(result)) {
+      Error(loc, "invalid literal \"%s\"", token.to_string().c_str());
+      return Result::Error;
+    }
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseExpectedNan(ExpectedNan* expected) {
+  WABT_TRACE(ParseExpectedNan);
+  TokenType token_type = Peek();
+  switch (token_type) {
+    case TokenType::NanArithmetic:
+      *expected = ExpectedNan::Arithmetic;
+      break;
+    case TokenType::NanCanonical:
+      *expected = ExpectedNan::Canonical;
+      break;
+    default:
+      return Result::Error;
+  }
+  Consume();
+  return Result::Ok;
+}
+
+Result WastParser::ParseF32(Const* const_, ConstType const_type) {
+  ExpectedNan expected;
+  if (const_type == ConstType::Expectation &&
+      Succeeded(ParseExpectedNan(&expected))) {
+    const_->set_f32(expected);
+    return Result::Ok;
+  }
+  auto literal = Consume().literal();
+  uint32_t f32_bits;
+  Result result = ParseFloat(literal.type, literal.text.begin(),
+                             literal.text.end(), &f32_bits);
+  const_->set_f32(f32_bits);
+  return result;
+}
+
+Result WastParser::ParseF64(Const* const_, ConstType const_type) {
+  ExpectedNan expected;
+  if (const_type == ConstType::Expectation &&
+      Succeeded(ParseExpectedNan(&expected))) {
+    const_->set_f64(expected);
+    return Result::Ok;
+  }
+  auto literal = Consume().literal();
+  uint64_t f64_bits;
+  Result result = ParseDouble(literal.type, literal.text.begin(),
+                              literal.text.end(), &f64_bits);
+  const_->set_f64(f64_bits);
+  return result;
+}
+
+Result WastParser::ParseConst(Const* const_, ConstType const_type) {
+  WABT_TRACE(ParseConst);
+  Token opcode_token = Consume();
+  Opcode opcode = opcode_token.opcode();
+  const_->loc = GetLocation();
+  Token token = GetToken();
+
+  // V128 is fully handled by ParseSimdV128Const:
+  if (opcode != Opcode::V128Const) {
+    switch (token.token_type()) {
+      case TokenType::Nat:
+      case TokenType::Int:
+      case TokenType::Float:
+        // OK.
+        break;
+      case TokenType::NanArithmetic:
+      case TokenType::NanCanonical:
+        break;
+      default:
+        return ErrorExpected({"a numeric literal"}, "123, -45, 6.7e8");
+    }
+  }
+
+  Result result;
+  switch (opcode) {
+    case Opcode::I32Const: {
+      auto sv = Consume().literal().text;
+      uint32_t u32;
+      result = ParseInt32(sv.begin(), sv.end(), &u32,
+                          ParseIntType::SignedAndUnsigned);
+      const_->set_u32(u32);
+      break;
+    }
+
+    case Opcode::I64Const: {
+      auto sv = Consume().literal().text;
+      uint64_t u64;
+      result = ParseInt64(sv.begin(), sv.end(), &u64,
+                          ParseIntType::SignedAndUnsigned);
+      const_->set_u64(u64);
+      break;
+    }
+
+    case Opcode::F32Const:
+      result = ParseF32(const_, const_type);
+      break;
+
+    case Opcode::F64Const:
+      result = ParseF64(const_, const_type);
+      break;
+
+    case Opcode::V128Const:
+      ErrorUnlessOpcodeEnabled(opcode_token);
+      // Parse V128 Simd Const (16 bytes).
+      result = ParseSimdV128Const(const_, token.token_type(), const_type);
+      // ParseSimdV128Const report error already, just return here if parser get
+      // errors.
+      if (Failed(result)) {
+        return Result::Error;
+      }
+      break;
+
+    default:
+      assert(!"ParseConst called with invalid opcode");
+      return Result::Error;
+  }
+
+  if (Failed(result)) {
+    Error(const_->loc, "invalid literal \"%s\"", token.to_string().c_str());
+    // Return if parser get errors.
+    return Result::Error;
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseExternref(Const* const_) {
+  WABT_TRACE(ParseExternref);
+  Token token = Consume();
+  if (!options_->features.reference_types_enabled()) {
+    Error(token.loc, "externref not allowed");
+    return Result::Error;
+  }
+
+  Literal literal;
+  string_view sv;
+  const char* s;
+  const char* end;
+  const_->loc = GetLocation();
+  TokenType token_type = Peek();
+
+  switch (token_type) {
+    case TokenType::Nat:
+    case TokenType::Int: {
+      literal = Consume().literal();
+      sv = literal.text;
+      s = sv.begin();
+      end = sv.end();
+      break;
+    }
+    default:
+      return ErrorExpected({"a numeric literal"}, "123");
+  }
+
+  uint64_t ref_bits;
+  Result result = ParseInt64(s, end, &ref_bits, ParseIntType::UnsignedOnly);
+
+  const_->set_externref(static_cast<uintptr_t>(ref_bits));
+
+  if (Failed(result)) {
+    Error(const_->loc, "invalid literal \"" PRIstringview "\"",
+          WABT_PRINTF_STRING_VIEW_ARG(literal.text));
+    // Return if parser get errors.
+    return Result::Error;
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseConstList(ConstVector* consts, ConstType type) {
+  WABT_TRACE(ParseConstList);
+  while (PeekMatchLpar(TokenType::Const) || PeekMatchLpar(TokenType::RefNull) ||
+         PeekMatchLpar(TokenType::RefExtern) ||
+         PeekMatchLpar(TokenType::RefFunc)) {
+    Consume();
+    Const const_;
+    switch (Peek()) {
+      case TokenType::Const:
+        CHECK_RESULT(ParseConst(&const_, type));
+        break;
+      case TokenType::RefNull: {
+        auto token = Consume();
+        Type type;
+        CHECK_RESULT(ParseRefKind(&type));
+        ErrorUnlessOpcodeEnabled(token);
+        const_.loc = GetLocation();
+        const_.set_null(type);
+        break;
+      }
+      case TokenType::RefFunc: {
+        auto token = Consume();
+        ErrorUnlessOpcodeEnabled(token);
+        const_.loc = GetLocation();
+        const_.set_funcref();
+        break;
+      }
+      case TokenType::RefExtern:
+        CHECK_RESULT(ParseExternref(&const_));
+        break;
+      default:
+        assert(!"unreachable");
+        return Result::Error;
+    }
+    EXPECT(Rpar);
+    consts->push_back(const_);
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseBlockInstr(std::unique_ptr<Expr>* out_expr) {
+  WABT_TRACE(ParseBlockInstr);
+  Location loc = GetLocation();
+
+  switch (Peek()) {
+    case TokenType::Block: {
+      Consume();
+      auto expr = MakeUnique<BlockExpr>(loc);
+      CHECK_RESULT(ParseLabelOpt(&expr->block.label));
+      CHECK_RESULT(ParseBlock(&expr->block));
+      EXPECT(End);
+      CHECK_RESULT(ParseEndLabelOpt(expr->block.label));
+      *out_expr = std::move(expr);
+      break;
+    }
+
+    case TokenType::Loop: {
+      Consume();
+      auto expr = MakeUnique<LoopExpr>(loc);
+      CHECK_RESULT(ParseLabelOpt(&expr->block.label));
+      CHECK_RESULT(ParseBlock(&expr->block));
+      EXPECT(End);
+      CHECK_RESULT(ParseEndLabelOpt(expr->block.label));
+      *out_expr = std::move(expr);
+      break;
+    }
+
+    case TokenType::If: {
+      Consume();
+      auto expr = MakeUnique<IfExpr>(loc);
+      CHECK_RESULT(ParseLabelOpt(&expr->true_.label));
+      CHECK_RESULT(ParseBlock(&expr->true_));
+      if (Match(TokenType::Else)) {
+        CHECK_RESULT(ParseEndLabelOpt(expr->true_.label));
+        CHECK_RESULT(ParseTerminatingInstrList(&expr->false_));
+        expr->false_end_loc = GetLocation();
+      }
+      EXPECT(End);
+      CHECK_RESULT(ParseEndLabelOpt(expr->true_.label));
+      *out_expr = std::move(expr);
+      break;
+    }
+
+    case TokenType::Try: {
+      ErrorUnlessOpcodeEnabled(Consume());
+      auto expr = MakeUnique<TryExpr>(loc);
+      CatchVector catches;
+      CHECK_RESULT(ParseLabelOpt(&expr->block.label));
+      CHECK_RESULT(ParseBlock(&expr->block));
+      if (IsCatch(Peek())) {
+        CHECK_RESULT(ParseCatchInstrList(&expr->catches));
+        expr->kind = TryKind::Catch;
+      } else if (PeekMatch(TokenType::Unwind)) {
+        Consume();
+        CHECK_RESULT(ParseInstrList(&expr->unwind));
+        expr->kind = TryKind::Unwind;
+      } else if (PeekMatch(TokenType::Delegate)) {
+        Consume();
+        Var var;
+        CHECK_RESULT(ParseVar(&var));
+        expr->delegate_target = var;
+        expr->kind = TryKind::Delegate;
+      } else {
+        return ErrorExpected({"catch", "catch_all", "unwind", "delegate"});
+      }
+      CHECK_RESULT(ErrorIfLpar({"a valid try clause"}));
+      expr->block.end_loc = GetLocation();
+      if (expr->kind != TryKind::Delegate) {
+        EXPECT(End);
+      }
+      CHECK_RESULT(ParseEndLabelOpt(expr->block.label));
+      *out_expr = std::move(expr);
+      break;
+    }
+
+    default:
+      assert(
+          !"ParseBlockInstr should only be called when IsBlockInstr() is true");
+      return Result::Error;
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseLabelOpt(std::string* out_label) {
+  WABT_TRACE(ParseLabelOpt);
+  if (PeekMatch(TokenType::Var)) {
+    *out_label = Consume().text().to_string();
+  } else {
+    out_label->clear();
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseEndLabelOpt(const std::string& begin_label) {
+  WABT_TRACE(ParseEndLabelOpt);
+  Location loc = GetLocation();
+  std::string end_label;
+  CHECK_RESULT(ParseLabelOpt(&end_label));
+  if (!end_label.empty()) {
+    if (begin_label.empty()) {
+      Error(loc, "unexpected label \"%s\"", end_label.c_str());
+    } else if (begin_label != end_label) {
+      Error(loc, "mismatching label \"%s\" != \"%s\"", begin_label.c_str(),
+            end_label.c_str());
+    }
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseBlockDeclaration(BlockDeclaration* decl) {
+  WABT_TRACE(ParseBlockDeclaration);
+  FuncDeclaration func_decl;
+  CHECK_RESULT(ParseTypeUseOpt(&func_decl));
+  CHECK_RESULT(ParseUnboundFuncSignature(&func_decl.sig));
+  decl->has_func_type = func_decl.has_func_type;
+  decl->type_var = func_decl.type_var;
+  decl->sig = func_decl.sig;
+  return Result::Ok;
+}
+
+Result WastParser::ParseBlock(Block* block) {
+  WABT_TRACE(ParseBlock);
+  CHECK_RESULT(ParseBlockDeclaration(&block->decl));
+  CHECK_RESULT(ParseInstrList(&block->exprs));
+  block->end_loc = GetLocation();
+  return Result::Ok;
+}
+
+Result WastParser::ParseExprList(ExprList* exprs) {
+  WABT_TRACE(ParseExprList);
+  ExprList new_exprs;
+  while (PeekMatchExpr()) {
+    if (Succeeded(ParseExpr(&new_exprs))) {
+      exprs->splice(exprs->end(), new_exprs);
+    } else {
+      CHECK_RESULT(Synchronize(IsExpr));
+    }
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseExpr(ExprList* exprs) {
+  WABT_TRACE(ParseExpr);
+  if (!PeekMatch(TokenType::Lpar)) {
+    return Result::Error;
+  }
+
+  if (IsPlainInstr(Peek(1))) {
+    Consume();
+    std::unique_ptr<Expr> expr;
+    CHECK_RESULT(ParsePlainInstr(&expr));
+    CHECK_RESULT(ParseExprList(exprs));
+    CHECK_RESULT(ErrorIfLpar({"an expr"}));
+    exprs->push_back(std::move(expr));
+  } else {
+    Location loc = GetLocation();
+
+    switch (Peek(1)) {
+      case TokenType::Block: {
+        Consume();
+        Consume();
+        auto expr = MakeUnique<BlockExpr>(loc);
+        CHECK_RESULT(ParseLabelOpt(&expr->block.label));
+        CHECK_RESULT(ParseBlock(&expr->block));
+        exprs->push_back(std::move(expr));
+        break;
+      }
+
+      case TokenType::Loop: {
+        Consume();
+        Consume();
+        auto expr = MakeUnique<LoopExpr>(loc);
+        CHECK_RESULT(ParseLabelOpt(&expr->block.label));
+        CHECK_RESULT(ParseBlock(&expr->block));
+        exprs->push_back(std::move(expr));
+        break;
+      }
+
+      case TokenType::If: {
+        Consume();
+        Consume();
+        auto expr = MakeUnique<IfExpr>(loc);
+
+        CHECK_RESULT(ParseLabelOpt(&expr->true_.label));
+        CHECK_RESULT(ParseBlockDeclaration(&expr->true_.decl));
+
+        if (PeekMatchExpr()) {
+          ExprList cond;
+          CHECK_RESULT(ParseExpr(&cond));
+          exprs->splice(exprs->end(), cond);
+        }
+
+        if (MatchLpar(TokenType::Then)) {
+          CHECK_RESULT(ParseTerminatingInstrList(&expr->true_.exprs));
+          expr->true_.end_loc = GetLocation();
+          EXPECT(Rpar);
+
+          if (MatchLpar(TokenType::Else)) {
+            CHECK_RESULT(ParseTerminatingInstrList(&expr->false_));
+            EXPECT(Rpar);
+          } else if (PeekMatchExpr()) {
+            CHECK_RESULT(ParseExpr(&expr->false_));
+          }
+          expr->false_end_loc = GetLocation();
+        } else if (PeekMatchExpr()) {
+          CHECK_RESULT(ParseExpr(&expr->true_.exprs));
+          expr->true_.end_loc = GetLocation();
+          if (PeekMatchExpr()) {
+            CHECK_RESULT(ParseExpr(&expr->false_));
+            expr->false_end_loc = GetLocation();
+          }
+        } else {
+          ConsumeIfLpar();
+          return ErrorExpected({"then block"}, "(then ...)");
+        }
+
+        exprs->push_back(std::move(expr));
+        break;
+      }
+
+      case TokenType::Try: {
+        Consume();
+        ErrorUnlessOpcodeEnabled(Consume());
+
+        auto expr = MakeUnique<TryExpr>(loc);
+        CHECK_RESULT(ParseLabelOpt(&expr->block.label));
+        CHECK_RESULT(ParseBlockDeclaration(&expr->block.decl));
+        EXPECT(Lpar);
+        EXPECT(Do);
+        CHECK_RESULT(ParseInstrList(&expr->block.exprs));
+        EXPECT(Rpar);
+        EXPECT(Lpar);
+        TokenType type = Peek();
+        switch (type) {
+          case TokenType::Catch:
+          case TokenType::CatchAll:
+            CHECK_RESULT(ParseCatchExprList(&expr->catches));
+            expr->kind = TryKind::Catch;
+            break;
+          case TokenType::Unwind:
+            Consume();
+            CHECK_RESULT(ParseTerminatingInstrList(&expr->unwind));
+            expr->kind = TryKind::Unwind;
+            EXPECT(Rpar);
+            break;
+          case TokenType::Delegate: {
+            Consume();
+            Var var;
+            CHECK_RESULT(ParseVar(&var));
+            expr->delegate_target = var;
+            expr->kind = TryKind::Delegate;
+            EXPECT(Rpar);
+            break;
+          }
+          default:
+            ErrorExpected({"catch", "catch_all", "unwind", "delegate"});
+            break;
+        }
+        CHECK_RESULT(ErrorIfLpar({"a valid try clause"}));
+        expr->block.end_loc = GetLocation();
+        exprs->push_back(std::move(expr));
+        break;
+      }
+
+      default:
+        assert(!"ParseExpr should only be called when IsExpr() is true");
+        return Result::Error;
+    }
+  }
+
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseCatchInstrList(CatchVector* catches) {
+  WABT_TRACE(ParseCatchInstrList);
+  bool parsedCatch = false;
+  bool parsedCatchAll = false;
+
+  while (IsCatch(Peek())) {
+    Catch catch_(GetLocation());
+
+    auto token = Consume();
+    if (token.token_type() == TokenType::Catch) {
+      CHECK_RESULT(ParseVar(&catch_.var));
+    } else {
+      if (parsedCatchAll) {
+        Error(token.loc, "multiple catch_all clauses not allowed");
+        return Result::Error;
+      }
+      parsedCatchAll = true;
+    }
+
+    CHECK_RESULT(ParseInstrList(&catch_.exprs));
+    catches->push_back(std::move(catch_));
+    parsedCatch = true;
+  }
+
+  if (!parsedCatch) {
+    return ErrorExpected({"catch"});
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseCatchExprList(CatchVector* catches) {
+  WABT_TRACE(ParseCatchExprList);
+  bool parsedCatchAll = false;
+
+  do {
+    Catch catch_(GetLocation());
+
+    auto token = Consume();
+    if (token.token_type() == TokenType::Catch) {
+      CHECK_RESULT(ParseVar(&catch_.var));
+    } else {
+      if (parsedCatchAll) {
+        Error(token.loc, "multiple catch_all clauses not allowed");
+        return Result::Error;
+      }
+      parsedCatchAll = true;
+    }
+
+    CHECK_RESULT(ParseTerminatingInstrList(&catch_.exprs));
+    EXPECT(Rpar);
+    catches->push_back(std::move(catch_));
+  } while (Match(TokenType::Lpar) && IsCatch(Peek()));
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseGlobalType(Global* global) {
+  WABT_TRACE(ParseGlobalType);
+  if (MatchLpar(TokenType::Mut)) {
+    global->mutable_ = true;
+    CHECK_RESULT(ParseValueType(&global->type));
+    CHECK_RESULT(ErrorIfLpar({"i32", "i64", "f32", "f64"}));
+    EXPECT(Rpar);
+  } else {
+    CHECK_RESULT(ParseValueType(&global->type));
+  }
+
+  return Result::Ok;
+}
+
+Result WastParser::ParseCommandList(Script* script,
+                                    CommandPtrVector* commands) {
+  WABT_TRACE(ParseCommandList);
+  while (IsCommand(PeekPair())) {
+    CommandPtr command;
+    if (Succeeded(ParseCommand(script, &command))) {
+      commands->push_back(std::move(command));
+    } else {
+      CHECK_RESULT(Synchronize(IsCommand));
+    }
+  }
+  return Result::Ok;
+}
+
+Result WastParser::ParseCommand(Script* script, CommandPtr* out_command) {
+  WABT_TRACE(ParseCommand);
+  switch (Peek(1)) {
+    case TokenType::AssertExhaustion:
+      return ParseAssertExhaustionCommand(out_command);
+
+    case TokenType::AssertInvalid:
+      return ParseAssertInvalidCommand(out_command);
+
+    case TokenType::AssertMalformed:
+      return ParseAssertMalformedCommand(out_command);
+
+    case TokenType::AssertReturn:
+      return ParseAssertReturnCommand(out_command);
+
+    case TokenType::AssertTrap:
+      return ParseAssertTrapCommand(out_command);
+
+    case TokenType::AssertUnlinkable:
+      return ParseAssertUnlinkableCommand(out_command);
+
+    case TokenType::Get:
+    case TokenType::Invoke:
+      return ParseActionCommand(out_command);
+
+    case TokenType::Module:
+      return ParseModuleCommand(script, out_command);
+
+    case TokenType::Register:
+      return ParseRegisterCommand(out_command);
+
+    case TokenType::Input:
+      return ParseInputCommand(out_command);
+
+    case TokenType::Output:
+      return ParseOutputCommand(out_command);
+
+    default:
+      assert(!"ParseCommand should only be called when IsCommand() is true");
+      return Result::Error;
+  }
+}
+
+Result WastParser::ParseAssertExhaustionCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertExhaustionCommand);
+  return ParseAssertActionTextCommand<AssertExhaustionCommand>(
+      TokenType::AssertExhaustion, out_command);
+}
+
+Result WastParser::ParseAssertInvalidCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertInvalidCommand);
+  return ParseAssertScriptModuleCommand<AssertInvalidCommand>(
+      TokenType::AssertInvalid, out_command);
+}
+
+Result WastParser::ParseAssertMalformedCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertMalformedCommand);
+  return ParseAssertScriptModuleCommand<AssertMalformedCommand>(
+      TokenType::AssertMalformed, out_command);
+}
+
+Result WastParser::ParseAssertReturnCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertReturnCommand);
+  EXPECT(Lpar);
+  EXPECT(AssertReturn);
+  auto command = MakeUnique<AssertReturnCommand>();
+  CHECK_RESULT(ParseAction(&command->action));
+  CHECK_RESULT(ParseConstList(&command->expected, ConstType::Expectation));
+  EXPECT(Rpar);
+  *out_command = std::move(command);
+  return Result::Ok;
+}
+
+Result WastParser::ParseAssertTrapCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertTrapCommand);
+  EXPECT(Lpar);
+  EXPECT(AssertTrap);
+  if (PeekMatchLpar(TokenType::Module)) {
+    auto command = MakeUnique<AssertUninstantiableCommand>();
+    CHECK_RESULT(ParseScriptModule(&command->module));
+    CHECK_RESULT(ParseQuotedText(&command->text));
+    *out_command = std::move(command);
+  } else {
+    auto command = MakeUnique<AssertTrapCommand>();
+    CHECK_RESULT(ParseAction(&command->action));
+    CHECK_RESULT(ParseQuotedText(&command->text));
+    *out_command = std::move(command);
+  }
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseAssertUnlinkableCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertUnlinkableCommand);
+  return ParseAssertScriptModuleCommand<AssertUnlinkableCommand>(
+      TokenType::AssertUnlinkable, out_command);
+}
+
+Result WastParser::ParseActionCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseActionCommand);
+  auto command = MakeUnique<ActionCommand>();
+  CHECK_RESULT(ParseAction(&command->action));
+  *out_command = std::move(command);
+  return Result::Ok;
+}
+
+Result WastParser::ParseModuleCommand(Script* script, CommandPtr* out_command) {
+  WABT_TRACE(ParseModuleCommand);
+  std::unique_ptr<ScriptModule> script_module;
+  CHECK_RESULT(ParseScriptModule(&script_module));
+
+  auto command = MakeUnique<ModuleCommand>();
+  Module& module = command->module;
+
+  switch (script_module->type()) {
+    case ScriptModuleType::Text:
+      module = std::move(cast<TextScriptModule>(script_module.get())->module);
+      break;
+
+    case ScriptModuleType::Binary: {
+      auto* bsm = cast<BinaryScriptModule>(script_module.get());
+      ReadBinaryOptions options;
+#if WABT_TRACING
+      auto log_stream = FileStream::CreateStdout();
+      options.log_stream = log_stream.get();
+#endif
+      options.features = options_->features;
+      Errors errors;
+      const char* filename = "<text>";
+      ReadBinaryIr(filename, bsm->data.data(), bsm->data.size(), options,
+                   &errors, &module);
+      module.name = bsm->name;
+      module.loc = bsm->loc;
+      for (const auto& error: errors) {
+        assert(error.error_level == ErrorLevel::Error);
+        if (error.loc.offset == kInvalidOffset) {
+          Error(bsm->loc, "error in binary module: %s", error.message.c_str());
+        } else {
+          Error(bsm->loc, "error in binary module: @0x%08" PRIzx ": %s",
+                error.loc.offset, error.message.c_str());
+        }
+      }
+      break;
+    }
+
+    case ScriptModuleType::Quoted:
+      return ErrorExpected({"a binary module", "a text module"});
+  }
+
+  // script is nullptr when ParseModuleCommand is called from ParseModule.
+  if (script) {
+    Index command_index = script->commands.size();
+
+    if (!module.name.empty()) {
+      script->module_bindings.emplace(module.name,
+                                      Binding(module.loc, command_index));
+    }
+
+    last_module_index_ = command_index;
+  }
+
+  *out_command = std::move(command);
+  return Result::Ok;
+}
+
+Result WastParser::ParseRegisterCommand(CommandPtr* out_command) {
+  WABT_TRACE(ParseRegisterCommand);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Register);
+  std::string text;
+  Var var;
+  CHECK_RESULT(ParseQuotedText(&text));
+  ParseVarOpt(&var, Var(last_module_index_, loc));
+  EXPECT(Rpar);
+  out_command->reset(new RegisterCommand(text, var));
+  return Result::Ok;
+}
+
+Result WastParser::ParseInputCommand(CommandPtr*) {
+  // Parse the input command, but always fail since this command is not
+  // actually supported.
+  WABT_TRACE(ParseInputCommand);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Input);
+  Error(loc, "input command is not supported");
+  Var var;
+  std::string text;
+  ParseVarOpt(&var);
+  CHECK_RESULT(ParseQuotedText(&text));
+  EXPECT(Rpar);
+  return Result::Error;
+}
+
+Result WastParser::ParseOutputCommand(CommandPtr*) {
+  // Parse the output command, but always fail since this command is not
+  // actually supported.
+  WABT_TRACE(ParseOutputCommand);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Output);
+  Error(loc, "output command is not supported");
+  Var var;
+  std::string text;
+  ParseVarOpt(&var);
+  if (Peek() == TokenType::Text) {
+    CHECK_RESULT(ParseQuotedText(&text));
+  }
+  EXPECT(Rpar);
+  return Result::Error;
+}
+
+Result WastParser::ParseAction(ActionPtr* out_action) {
+  WABT_TRACE(ParseAction);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+
+  switch (Peek()) {
+    case TokenType::Invoke: {
+      Consume();
+      auto action = MakeUnique<InvokeAction>(loc);
+      ParseVarOpt(&action->module_var, Var(last_module_index_, loc));
+      CHECK_RESULT(ParseQuotedText(&action->name));
+      CHECK_RESULT(ParseConstList(&action->args, ConstType::Normal));
+      *out_action = std::move(action);
+      break;
+    }
+
+    case TokenType::Get: {
+      Consume();
+      auto action = MakeUnique<GetAction>(loc);
+      ParseVarOpt(&action->module_var, Var(last_module_index_, loc));
+      CHECK_RESULT(ParseQuotedText(&action->name));
+      *out_action = std::move(action);
+      break;
+    }
+
+    default:
+      return ErrorExpected({"invoke", "get"});
+  }
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+Result WastParser::ParseScriptModule(
+    std::unique_ptr<ScriptModule>* out_module) {
+  WABT_TRACE(ParseScriptModule);
+  EXPECT(Lpar);
+  Location loc = GetLocation();
+  EXPECT(Module);
+  std::string name;
+  ParseBindVarOpt(&name);
+
+  switch (Peek()) {
+    case TokenType::Bin: {
+      Consume();
+      std::vector<uint8_t> data;
+      // TODO(binji): The spec allows this to be empty, switch to
+      // ParseTextListOpt.
+      CHECK_RESULT(ParseTextList(&data));
+
+      auto bsm = MakeUnique<BinaryScriptModule>();
+      bsm->name = name;
+      bsm->loc = loc;
+      bsm->data = std::move(data);
+      *out_module = std::move(bsm);
+      break;
+    }
+
+    case TokenType::Quote: {
+      Consume();
+      std::vector<uint8_t> data;
+      // TODO(binji): The spec allows this to be empty, switch to
+      // ParseTextListOpt.
+      CHECK_RESULT(ParseTextList(&data));
+
+      auto qsm = MakeUnique<QuotedScriptModule>();
+      qsm->name = name;
+      qsm->loc = loc;
+      qsm->data = std::move(data);
+      *out_module = std::move(qsm);
+      break;
+    }
+
+    default: {
+      auto tsm = MakeUnique<TextScriptModule>();
+      tsm->module.name = name;
+      tsm->module.loc = loc;
+      if (IsModuleField(PeekPair())) {
+        CHECK_RESULT(ParseModuleFieldList(&tsm->module));
+      } else if (!PeekMatch(TokenType::Rpar)) {
+        ConsumeIfLpar();
+        return ErrorExpected({"a module field"});
+      }
+      *out_module = std::move(tsm);
+      break;
+    }
+  }
+
+  EXPECT(Rpar);
+  return Result::Ok;
+}
+
+template <typename T>
+Result WastParser::ParseAssertActionCommand(TokenType token_type,
+                                            CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertActionCommand);
+  EXPECT(Lpar);
+  CHECK_RESULT(Expect(token_type));
+  auto command = MakeUnique<T>();
+  CHECK_RESULT(ParseAction(&command->action));
+  EXPECT(Rpar);
+  *out_command = std::move(command);
+  return Result::Ok;
+}
+
+template <typename T>
+Result WastParser::ParseAssertActionTextCommand(TokenType token_type,
+                                                CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertActionTextCommand);
+  EXPECT(Lpar);
+  CHECK_RESULT(Expect(token_type));
+  auto command = MakeUnique<T>();
+  CHECK_RESULT(ParseAction(&command->action));
+  CHECK_RESULT(ParseQuotedText(&command->text));
+  EXPECT(Rpar);
+  *out_command = std::move(command);
+  return Result::Ok;
+}
+
+template <typename T>
+Result WastParser::ParseAssertScriptModuleCommand(TokenType token_type,
+                                                  CommandPtr* out_command) {
+  WABT_TRACE(ParseAssertScriptModuleCommand);
+  EXPECT(Lpar);
+  CHECK_RESULT(Expect(token_type));
+  auto command = MakeUnique<T>();
+  CHECK_RESULT(ParseScriptModule(&command->module));
+  CHECK_RESULT(ParseQuotedText(&command->text));
+  EXPECT(Rpar);
+  *out_command = std::move(command);
+  return Result::Ok;
+}
+
+void WastParser::CheckImportOrdering(Module* module) {
+  if (module->funcs.size() != module->num_func_imports ||
+      module->tables.size() != module->num_table_imports ||
+      module->memories.size() != module->num_memory_imports ||
+      module->globals.size() != module->num_global_imports ||
+      module->events.size() != module->num_event_imports) {
+    Error(GetLocation(),
+          "imports must occur before all non-import definitions");
+  }
+}
+
+Result ParseWatModule(WastLexer* lexer,
+                      std::unique_ptr<Module>* out_module,
+                      Errors* errors,
+                      WastParseOptions* options) {
+  assert(out_module != nullptr);
+  assert(options != nullptr);
+  WastParser parser(lexer, errors, options);
+  CHECK_RESULT(parser.ParseModule(out_module));
+  return Result::Ok;
+}
+
+Result ParseWastScript(WastLexer* lexer,
+                       std::unique_ptr<Script>* out_script,
+                       Errors* errors,
+                       WastParseOptions* options) {
+  assert(out_script != nullptr);
+  assert(options != nullptr);
+  WastParser parser(lexer, errors, options);
+  CHECK_RESULT(parser.ParseScript(out_script));
+  CHECK_RESULT(ResolveNamesScript(out_script->get(), errors));
+  return Result::Ok;
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wast-parser.h
new file mode 100644 (file)
index 0000000..9c82b25
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * 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_WAST_PARSER_H_
+#define WABT_WAST_PARSER_H_
+
+#include <array>
+
+#include "src/circular-array.h"
+#include "src/error.h"
+#include "src/feature.h"
+#include "src/intrusive-list.h"
+#include "src/ir.h"
+#include "src/wast-lexer.h"
+
+namespace wabt {
+
+struct WastParseOptions {
+  WastParseOptions(const Features& features) : features(features) {}
+
+  Features features;
+  bool debug_parsing = false;
+};
+
+typedef std::array<TokenType, 2> TokenTypePair;
+
+class WastParser {
+ public:
+  WastParser(WastLexer*, Errors*, WastParseOptions*);
+
+  void WABT_PRINTF_FORMAT(3, 4) Error(Location, const char* format, ...);
+  Result ParseModule(std::unique_ptr<Module>* out_module);
+  Result ParseScript(std::unique_ptr<Script>* out_script);
+
+  std::unique_ptr<Script> ReleaseScript();
+
+ private:
+  enum class ConstType {
+    Normal,
+    Expectation,
+  };
+
+  void ErrorUnlessOpcodeEnabled(const Token&);
+
+  // Print an error message listing the expected tokens, as well as an example
+  // of expected input.
+  Result ErrorExpected(const std::vector<std::string>& expected,
+                       const char* example = nullptr);
+
+  // Print an error message, and and return Result::Error if the next token is
+  // '('. This is commonly used after parsing a sequence of s-expressions -- if
+  // no more can be parsed, we know that a following '(' is invalid. This
+  // function consumes the '(' so a better error message can be provided
+  // (assuming the following token was unexpected).
+  Result ErrorIfLpar(const std::vector<std::string>& expected,
+                     const char* example = nullptr);
+
+  // Returns the next token without consuming it.
+  Token GetToken();
+
+  // Returns the location of the next token.
+  Location GetLocation();
+
+  // Returns the type of the next token.
+  TokenType Peek(size_t n = 0);
+
+  // Returns the types of the next two tokens.
+  TokenTypePair PeekPair();
+
+  // Returns true if the next token's type is equal to the parameter.
+  bool PeekMatch(TokenType);
+
+  // Returns true if the next token's type is '(' and the following token is
+  // equal to the parameter.
+  bool PeekMatchLpar(TokenType);
+
+  // Returns true if the next two tokens can start an Expr. This allows for
+  // folded expressions, plain instructions and block instructions.
+  bool PeekMatchExpr();
+
+  // Returns true if the next token's type is equal to the parameter. If so,
+  // then the token is consumed.
+  bool Match(TokenType);
+
+  // Returns true if the next token's type is equal to '(' and the following
+  // token is equal to the parameter. If so, then the token is consumed.
+  bool MatchLpar(TokenType);
+
+  // Like Match(), but prints an error message if the token doesn't match, and
+  // returns Result::Error.
+  Result Expect(TokenType);
+
+  // Consume one token and return it.
+  Token Consume();
+
+  // Give the Match() function a clearer name when used to optionally consume a
+  // token (used for printing better error messages).
+  void ConsumeIfLpar() { Match(TokenType::Lpar); }
+
+  typedef bool SynchronizeFunc(TokenTypePair pair);
+
+  // Attempt to synchronize the token stream by dropping tokens until the
+  // SynchronizeFunc returns true, or until a token limit is reached. This
+  // function returns Result::Error if the stream was not able to be
+  // synchronized.
+  Result Synchronize(SynchronizeFunc);
+
+  bool ParseBindVarOpt(std::string* name);
+  Result ParseVar(Var* out_var);
+  bool ParseVarOpt(Var* out_var, Var default_var = Var());
+  Result ParseOffsetExpr(ExprList* out_expr_list);
+  bool ParseOffsetExprOpt(ExprList* out_expr_list);
+  Result ParseTextList(std::vector<uint8_t>* out_data);
+  bool ParseTextListOpt(std::vector<uint8_t>* out_data);
+  Result ParseVarList(VarVector* out_var_list);
+  bool ParseElemExprOpt(ElemExpr* out_elem_expr);
+  bool ParseElemExprListOpt(ElemExprVector* out_list);
+  bool ParseElemExprVarListOpt(ElemExprVector* out_list);
+  Result ParseValueType(Type* out_type);
+  Result ParseValueTypeList(TypeVector* out_type_list);
+  Result ParseRefKind(Type* out_type);
+  Result ParseRefType(Type* out_type);
+  bool ParseRefTypeOpt(Type* out_type);
+  Result ParseQuotedText(std::string* text);
+  bool ParseOffsetOpt(Address* offset);
+  bool ParseAlignOpt(Address* align);
+  Result ParseLimitsIndex(Limits*);
+  Result ParseLimits(Limits*);
+  Result ParseNat(uint64_t*);
+
+  Result ParseModuleFieldList(Module*);
+  Result ParseModuleField(Module*);
+  Result ParseDataModuleField(Module*);
+  Result ParseElemModuleField(Module*);
+  Result ParseEventModuleField(Module*);
+  Result ParseExportModuleField(Module*);
+  Result ParseFuncModuleField(Module*);
+  Result ParseTypeModuleField(Module*);
+  Result ParseGlobalModuleField(Module*);
+  Result ParseImportModuleField(Module*);
+  Result ParseMemoryModuleField(Module*);
+  Result ParseStartModuleField(Module*);
+  Result ParseTableModuleField(Module*);
+
+  Result ParseExportDesc(Export*);
+  Result ParseInlineExports(ModuleFieldList*, ExternalKind);
+  Result ParseInlineImport(Import*);
+  Result ParseTypeUseOpt(FuncDeclaration*);
+  Result ParseFuncSignature(FuncSignature*, BindingHash* param_bindings);
+  Result ParseUnboundFuncSignature(FuncSignature*);
+  Result ParseBoundValueTypeList(TokenType,
+                                 TypeVector*,
+                                 BindingHash*,
+                                 Index binding_index_offset = 0);
+  Result ParseUnboundValueTypeList(TokenType, TypeVector*);
+  Result ParseResultList(TypeVector*);
+  Result ParseInstrList(ExprList*);
+  Result ParseTerminatingInstrList(ExprList*);
+  Result ParseInstr(ExprList*);
+  Result ParsePlainInstr(std::unique_ptr<Expr>*);
+  Result ParseF32(Const*, ConstType type);
+  Result ParseF64(Const*, ConstType type);
+  Result ParseConst(Const*, ConstType type);
+  Result ParseExternref(Const*);
+  Result ParseExpectedNan(ExpectedNan* expected);
+  Result ParseConstList(ConstVector*, ConstType type);
+  Result ParseBlockInstr(std::unique_ptr<Expr>*);
+  Result ParseLabelOpt(std::string*);
+  Result ParseEndLabelOpt(const std::string&);
+  Result ParseBlockDeclaration(BlockDeclaration*);
+  Result ParseBlock(Block*);
+  Result ParseExprList(ExprList*);
+  Result ParseExpr(ExprList*);
+  Result ParseCatchInstrList(CatchVector* catches);
+  Result ParseCatchExprList(CatchVector* catches);
+  Result ParseGlobalType(Global*);
+  Result ParseField(Field*);
+  Result ParseFieldList(std::vector<Field>*);
+
+  template <typename T>
+  Result ParsePlainInstrVar(Location, std::unique_ptr<Expr>*);
+  template <typename T>
+  Result ParsePlainLoadStoreInstr(Location, Token, std::unique_ptr<Expr>*);
+
+  Result ParseCommandList(Script*, CommandPtrVector*);
+  Result ParseCommand(Script*, CommandPtr*);
+  Result ParseAssertExhaustionCommand(CommandPtr*);
+  Result ParseAssertInvalidCommand(CommandPtr*);
+  Result ParseAssertMalformedCommand(CommandPtr*);
+  Result ParseAssertReturnCommand(CommandPtr*);
+  Result ParseAssertReturnFuncCommand(CommandPtr*);
+  Result ParseAssertTrapCommand(CommandPtr*);
+  Result ParseAssertUnlinkableCommand(CommandPtr*);
+  Result ParseActionCommand(CommandPtr*);
+  Result ParseModuleCommand(Script*, CommandPtr*);
+  Result ParseRegisterCommand(CommandPtr*);
+  Result ParseInputCommand(CommandPtr*);
+  Result ParseOutputCommand(CommandPtr*);
+
+  Result ParseAction(ActionPtr*);
+  Result ParseScriptModule(std::unique_ptr<ScriptModule>*);
+
+  template <typename T>
+  Result ParseActionCommand(TokenType, CommandPtr*);
+  template <typename T>
+  Result ParseAssertActionCommand(TokenType, CommandPtr*);
+  template <typename T>
+  Result ParseAssertActionTextCommand(TokenType, CommandPtr*);
+  template <typename T>
+  Result ParseAssertScriptModuleCommand(TokenType, CommandPtr*);
+
+  Result ParseSimdV128Const(Const*, TokenType, ConstType);
+
+  void CheckImportOrdering(Module*);
+
+  WastLexer* lexer_;
+  Index last_module_index_ = kInvalidIndex;
+  Errors* errors_;
+  WastParseOptions* options_;
+
+  CircularArray<Token, 2> tokens_;
+};
+
+Result ParseWatModule(WastLexer* lexer,
+                      std::unique_ptr<Module>* out_module,
+                      Errors*,
+                      WastParseOptions* options);
+
+Result ParseWastScript(WastLexer* lexer,
+                       std::unique_ptr<Script>* out_script,
+                       Errors*,
+                       WastParseOptions* options);
+
+}  // namespace wabt
+
+#endif /* WABT_WAST_PARSER_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.cc b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.cc
new file mode 100644 (file)
index 0000000..0c051f8
--- /dev/null
@@ -0,0 +1,1697 @@
+/*
+ * 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/wat-writer.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cinttypes>
+#include <cstdarg>
+#include <cstdio>
+#include <iterator>
+#include <map>
+#include <string>
+#include <vector>
+
+#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"
+
+#define INDENT_SIZE 2
+#define NO_FORCE_NEWLINE 0
+#define FORCE_NEWLINE 1
+
+namespace wabt {
+
+namespace {
+
+static const uint8_t s_is_char_escaped[] = {
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+
+// This table matches the characters allowed by wast-lexer.cc for `symbol`.
+// The disallowed printable characters are: "(),;[]{} and <space>.
+static const uint8_t s_valid_name_chars[256] = {
+    //         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
+    /* 0x00 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    /* 0x10 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    /* 0x20 */ 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1,
+    /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+    /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1,
+    /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+    /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0,
+};
+
+enum class NextChar {
+  None,
+  Space,
+  Newline,
+  ForceNewline,
+};
+
+struct ExprTree {
+  explicit ExprTree(const Expr* expr, Index result_count)
+      : expr(expr), result_count(result_count) {}
+
+  const Expr* expr;
+  std::vector<ExprTree> children;
+  Index result_count;
+};
+
+class WatWriter : ModuleContext {
+ public:
+  WatWriter(Stream* stream, const WriteWatOptions& options,
+            const Module &module)
+      : ModuleContext(module), options_(options), stream_(stream) {}
+
+  Result WriteModule();
+
+ private:
+  void Indent();
+  void Dedent();
+  void WriteIndent();
+  void WriteNextChar();
+  void WriteDataWithNextChar(const void* src, size_t size);
+  void Writef(const char* format, ...);
+  void WritePutc(char c);
+  void WritePuts(const char* s, NextChar next_char);
+  void WritePutsSpace(const char* s);
+  void WritePutsNewline(const char* s);
+  void WriteNewline(bool force);
+  void WriteOpen(const char* name, NextChar next_char);
+  void WriteOpenNewline(const char* name);
+  void WriteOpenSpace(const char* name);
+  void WriteClose(NextChar next_char);
+  void WriteCloseNewline();
+  void WriteCloseSpace();
+  void WriteString(const std::string& str, NextChar next_char);
+  void WriteName(string_view str, NextChar next_char);
+  void WriteNameOrIndex(string_view str, Index index, NextChar next_char);
+  void WriteQuotedData(const void* data, size_t length);
+  void WriteQuotedString(string_view str, NextChar next_char);
+  void WriteVar(const Var& var, NextChar next_char);
+  void WriteVarUnlessZero(const Var& var, NextChar next_char);
+  void WriteBrVar(const Var& var, NextChar next_char);
+  void WriteRefKind(Type type, NextChar next_char);
+  void WriteType(Type type, NextChar next_char);
+  void WriteTypes(const TypeVector& types, const char* name);
+  void WriteFuncSigSpace(const FuncSignature& func_sig);
+  void WriteBeginBlock(LabelType label_type,
+                       const Block& block,
+                       const char* text);
+  void WriteEndBlock();
+  void WriteConst(const Const& const_);
+  void WriteExpr(const Expr* expr);
+  template <typename T>
+  void WriteLoadStoreExpr(const Expr* expr);
+  void WriteExprList(const ExprList& exprs);
+  void WriteInitExpr(const ExprList& expr);
+  template <typename T>
+  void WriteTypeBindings(const char* prefix,
+                         const T& types,
+                         const std::vector<std::string>& index_to_name,
+                         Index binding_index_offset = 0);
+  void WriteBeginFunc(const Func& func);
+  void WriteFunc(const Func& func);
+  void WriteBeginGlobal(const Global& global);
+  void WriteGlobal(const Global& global);
+  void WriteEvent(const Event& event);
+  void WriteLimits(const Limits& limits);
+  void WriteTable(const Table& table);
+  void WriteElemSegment(const ElemSegment& segment);
+  void WriteMemory(const Memory& memory);
+  void WriteDataSegment(const DataSegment& segment);
+  void WriteImport(const Import& import);
+  void WriteExport(const Export& export_);
+  void WriteTypeEntry(const TypeEntry& type);
+  void WriteField(const Field& field);
+  void WriteStartFunction(const Var& start);
+
+  class ExprVisitorDelegate;
+
+  void PushExpr(const Expr* expr, Index operand_count, Index result_count);
+  void FlushExprTree(const ExprTree& expr_tree);
+  void FlushExprTreeVector(const std::vector<ExprTree>&);
+  void FlushExprTreeStack();
+  void WriteFoldedExpr(const Expr*);
+  void WriteFoldedExprList(const ExprList&);
+
+  void BuildInlineExportMap();
+  void WriteInlineExports(ExternalKind, Index);
+  bool IsInlineExport(const Export& export_);
+  void BuildInlineImportMap();
+  void WriteInlineImport(ExternalKind, Index);
+
+  const WriteWatOptions& options_;
+  Stream* stream_ = nullptr;
+  Result result_ = Result::Ok;
+  int indent_ = 0;
+  NextChar next_char_ = NextChar::None;
+  std::vector<ExprTree> expr_tree_stack_;
+  std::multimap<std::pair<ExternalKind, Index>, const Export*>
+      inline_export_map_;
+  std::vector<const Import*> inline_import_map_[kExternalKindCount];
+
+  Index func_index_ = 0;
+  Index global_index_ = 0;
+  Index table_index_ = 0;
+  Index memory_index_ = 0;
+  Index type_index_ = 0;
+  Index event_index_ = 0;
+  Index data_segment_index_ = 0;
+  Index elem_segment_index_ = 0;
+};
+
+void WatWriter::Indent() {
+  indent_ += INDENT_SIZE;
+}
+
+void WatWriter::Dedent() {
+  indent_ -= INDENT_SIZE;
+  assert(indent_ >= 0);
+}
+
+void WatWriter::WriteIndent() {
+  static char s_indent[] =
+      "                                                                       "
+      "                                                                       ";
+  static size_t s_indent_len = sizeof(s_indent) - 1;
+  size_t to_write = indent_;
+  while (to_write >= s_indent_len) {
+    stream_->WriteData(s_indent, s_indent_len);
+    to_write -= s_indent_len;
+  }
+  if (to_write > 0) {
+    stream_->WriteData(s_indent, to_write);
+  }
+}
+
+void WatWriter::WriteNextChar() {
+  switch (next_char_) {
+    case NextChar::Space:
+      stream_->WriteChar(' ');
+      break;
+    case NextChar::Newline:
+    case NextChar::ForceNewline:
+      stream_->WriteChar('\n');
+      WriteIndent();
+      break;
+    case NextChar::None:
+      break;
+  }
+  next_char_ = NextChar::None;
+}
+
+void WatWriter::WriteDataWithNextChar(const void* src, size_t size) {
+  WriteNextChar();
+  stream_->WriteData(src, size);
+}
+
+void WABT_PRINTF_FORMAT(2, 3) WatWriter::Writef(const char* format, ...) {
+  WABT_SNPRINTF_ALLOCA(buffer, length, format);
+  /* default to following space */
+  WriteDataWithNextChar(buffer, length);
+  next_char_ = NextChar::Space;
+}
+
+void WatWriter::WritePutc(char c) {
+  stream_->WriteChar(c);
+}
+
+void WatWriter::WritePuts(const char* s, NextChar next_char) {
+  size_t len = strlen(s);
+  WriteDataWithNextChar(s, len);
+  next_char_ = next_char;
+}
+
+void WatWriter::WritePutsSpace(const char* s) {
+  WritePuts(s, NextChar::Space);
+}
+
+void WatWriter::WritePutsNewline(const char* s) {
+  WritePuts(s, NextChar::Newline);
+}
+
+void WatWriter::WriteNewline(bool force) {
+  if (next_char_ == NextChar::ForceNewline) {
+    WriteNextChar();
+  }
+  next_char_ = force ? NextChar::ForceNewline : NextChar::Newline;
+}
+
+void WatWriter::WriteOpen(const char* name, NextChar next_char) {
+  WritePuts("(", NextChar::None);
+  WritePuts(name, next_char);
+  Indent();
+}
+
+void WatWriter::WriteOpenNewline(const char* name) {
+  WriteOpen(name, NextChar::Newline);
+}
+
+void WatWriter::WriteOpenSpace(const char* name) {
+  WriteOpen(name, NextChar::Space);
+}
+
+void WatWriter::WriteClose(NextChar next_char) {
+  if (next_char_ != NextChar::ForceNewline) {
+    next_char_ = NextChar::None;
+  }
+  Dedent();
+  WritePuts(")", next_char);
+}
+
+void WatWriter::WriteCloseNewline() {
+  WriteClose(NextChar::Newline);
+}
+
+void WatWriter::WriteCloseSpace() {
+  WriteClose(NextChar::Space);
+}
+
+void WatWriter::WriteString(const std::string& str, NextChar next_char) {
+  WritePuts(str.c_str(), next_char);
+}
+
+void WatWriter::WriteName(string_view str, NextChar next_char) {
+  // Debug names must begin with a $ for for wast file to be valid
+  assert(!str.empty() && str.front() == '$');
+  bool has_invalid_chars = std::any_of(
+      str.begin(), str.end(), [](uint8_t c) { return !s_valid_name_chars[c]; });
+
+  if (has_invalid_chars) {
+    std::string valid_str;
+    std::transform(str.begin(), str.end(), std::back_inserter(valid_str),
+                   [](uint8_t c) { return s_valid_name_chars[c] ? c : '_'; });
+    WriteDataWithNextChar(valid_str.data(), valid_str.length());
+  } else {
+    WriteDataWithNextChar(str.data(), str.length());
+  }
+
+  next_char_ = next_char;
+}
+
+void WatWriter::WriteNameOrIndex(string_view str,
+                                 Index index,
+                                 NextChar next_char) {
+  if (!str.empty()) {
+    WriteName(str, next_char);
+  } else {
+    Writef("(;%u;)", index);
+  }
+}
+
+void WatWriter::WriteQuotedData(const void* data, size_t length) {
+  const uint8_t* u8_data = static_cast<const uint8_t*>(data);
+  static const char s_hexdigits[] = "0123456789abcdef";
+  WriteNextChar();
+  WritePutc('\"');
+  for (size_t i = 0; i < length; ++i) {
+    uint8_t c = u8_data[i];
+    if (s_is_char_escaped[c]) {
+      WritePutc('\\');
+      WritePutc(s_hexdigits[c >> 4]);
+      WritePutc(s_hexdigits[c & 0xf]);
+    } else {
+      WritePutc(c);
+    }
+  }
+  WritePutc('\"');
+  next_char_ = NextChar::Space;
+}
+
+void WatWriter::WriteQuotedString(string_view str, NextChar next_char) {
+  WriteQuotedData(str.data(), str.length());
+  next_char_ = next_char;
+}
+
+void WatWriter::WriteVar(const Var& var, NextChar next_char) {
+  if (var.is_index()) {
+    Writef("%" PRIindex, var.index());
+    next_char_ = next_char;
+  } else {
+    WriteName(var.name(), next_char);
+  }
+}
+
+bool VarIsZero(const Var& var) {
+  return var.is_index() && var.index() == 0;
+}
+
+void WatWriter::WriteVarUnlessZero(const Var& var, NextChar next_char) {
+  if (!VarIsZero(var)) {
+    WriteVar(var, next_char);
+  }
+}
+
+void WatWriter::WriteBrVar(const Var& var, NextChar next_char) {
+  if (var.is_index()) {
+    if (var.index() < GetLabelStackSize()) {
+      Writef("%" PRIindex " (;@%" PRIindex ";)", var.index(),
+             GetLabelStackSize() - var.index() - 1);
+    } else {
+      Writef("%" PRIindex " (; INVALID ;)", var.index());
+    }
+    next_char_ = next_char;
+  } else {
+    WriteString(var.name(), next_char);
+  }
+}
+
+void WatWriter::WriteRefKind(Type type, NextChar next_char) {
+  WritePuts(type.GetRefKindName(), next_char);
+}
+
+void WatWriter::WriteType(Type type, NextChar next_char) {
+  const char* type_name = type.GetName();
+  assert(type_name);
+  WritePuts(type_name, next_char);
+}
+
+void WatWriter::WriteTypes(const TypeVector& types, const char* name) {
+  if (types.size()) {
+    if (name) {
+      WriteOpenSpace(name);
+    }
+    for (Type type : types) {
+      WriteType(type, NextChar::Space);
+    }
+    if (name) {
+      WriteCloseSpace();
+    }
+  }
+}
+
+void WatWriter::WriteFuncSigSpace(const FuncSignature& func_sig) {
+  WriteTypes(func_sig.param_types, "param");
+  WriteTypes(func_sig.result_types, "result");
+}
+
+void WatWriter::WriteBeginBlock(LabelType label_type,
+                                const Block& block,
+                                const char* text) {
+  WritePutsSpace(text);
+  bool has_label = !block.label.empty();
+  if (has_label) {
+    WriteString(block.label, NextChar::Space);
+  }
+  WriteTypes(block.decl.sig.param_types, "param");
+  WriteTypes(block.decl.sig.result_types, "result");
+  if (!has_label) {
+    Writef(" ;; label = @%" PRIindex, GetLabelStackSize());
+  }
+  WriteNewline(FORCE_NEWLINE);
+  BeginBlock(label_type, block);
+  Indent();
+}
+
+void WatWriter::WriteEndBlock() {
+  Dedent();
+  EndBlock();
+  WritePutsNewline(Opcode::End_Opcode.GetName());
+}
+
+void WatWriter::WriteConst(const Const& const_) {
+  switch (const_.type()) {
+    case Type::I32:
+      WritePutsSpace(Opcode::I32Const_Opcode.GetName());
+      Writef("%d", static_cast<int32_t>(const_.u32()));
+      WriteNewline(NO_FORCE_NEWLINE);
+      break;
+
+    case Type::I64:
+      WritePutsSpace(Opcode::I64Const_Opcode.GetName());
+      Writef("%" PRId64, static_cast<int64_t>(const_.u64()));
+      WriteNewline(NO_FORCE_NEWLINE);
+      break;
+
+    case Type::F32: {
+      WritePutsSpace(Opcode::F32Const_Opcode.GetName());
+      char buffer[128];
+      WriteFloatHex(buffer, 128, const_.f32_bits());
+      WritePutsSpace(buffer);
+      Writef("(;=%g;)", Bitcast<float>(const_.f32_bits()));
+      WriteNewline(NO_FORCE_NEWLINE);
+      break;
+    }
+
+    case Type::F64: {
+      WritePutsSpace(Opcode::F64Const_Opcode.GetName());
+      char buffer[128];
+      WriteDoubleHex(buffer, 128, const_.f64_bits());
+      WritePutsSpace(buffer);
+      Writef("(;=%g;)", Bitcast<double>(const_.f64_bits()));
+      WriteNewline(NO_FORCE_NEWLINE);
+      break;
+    }
+
+    case Type::V128: {
+      WritePutsSpace(Opcode::V128Const_Opcode.GetName());
+      auto vec = const_.vec128();
+      Writef("i32x4 0x%08x 0x%08x 0x%08x 0x%08x", vec.u32(0), vec.u32(1),
+             vec.u32(2), vec.u32(3));
+      WriteNewline(NO_FORCE_NEWLINE);
+      break;
+    }
+
+    default:
+      assert(0);
+      break;
+  }
+}
+
+template <typename T>
+void WatWriter::WriteLoadStoreExpr(const Expr* expr) {
+  auto typed_expr = cast<T>(expr);
+  WritePutsSpace(typed_expr->opcode.GetName());
+  if (typed_expr->offset) {
+    Writef("offset=%" PRIaddress, typed_expr->offset);
+  }
+  if (!typed_expr->opcode.IsNaturallyAligned(typed_expr->align)) {
+    Writef("align=%" PRIaddress, typed_expr->align);
+  }
+  WriteNewline(NO_FORCE_NEWLINE);
+}
+
+class WatWriter::ExprVisitorDelegate : public ExprVisitor::Delegate {
+ public:
+  explicit ExprVisitorDelegate(WatWriter* writer) : writer_(writer) {}
+
+  Result OnBinaryExpr(BinaryExpr*) override;
+  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 OnCallIndirectExpr(CallIndirectExpr*) override;
+  Result OnCompareExpr(CompareExpr*) override;
+  Result OnConstExpr(ConstExpr*) override;
+  Result OnConvertExpr(ConvertExpr*) override;
+  Result OnDropExpr(DropExpr*) override;
+  Result OnGlobalGetExpr(GlobalGetExpr*) override;
+  Result OnGlobalSetExpr(GlobalSetExpr*) override;
+  Result BeginIfExpr(IfExpr*) override;
+  Result AfterIfTrueExpr(IfExpr*) override;
+  Result EndIfExpr(IfExpr*) override;
+  Result OnLoadExpr(LoadExpr*) override;
+  Result OnLocalGetExpr(LocalGetExpr*) override;
+  Result OnLocalSetExpr(LocalSetExpr*) override;
+  Result OnLocalTeeExpr(LocalTeeExpr*) override;
+  Result BeginLoopExpr(LoopExpr*) override;
+  Result EndLoopExpr(LoopExpr*) override;
+  Result OnMemoryCopyExpr(MemoryCopyExpr*) override;
+  Result OnDataDropExpr(DataDropExpr*) override;
+  Result OnMemoryFillExpr(MemoryFillExpr*) override;
+  Result OnMemoryGrowExpr(MemoryGrowExpr*) override;
+  Result OnMemoryInitExpr(MemoryInitExpr*) override;
+  Result OnMemorySizeExpr(MemorySizeExpr*) override;
+  Result OnTableCopyExpr(TableCopyExpr*) override;
+  Result OnElemDropExpr(ElemDropExpr*) 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 OnRefFuncExpr(RefFuncExpr*) override;
+  Result OnRefNullExpr(RefNullExpr*) override;
+  Result OnRefIsNullExpr(RefIsNullExpr*) override;
+  Result OnNopExpr(NopExpr*) override;
+  Result OnReturnExpr(ReturnExpr*) override;
+  Result OnReturnCallExpr(ReturnCallExpr*) override;
+  Result OnReturnCallIndirectExpr(ReturnCallIndirectExpr*) override;
+  Result OnSelectExpr(SelectExpr*) override;
+  Result OnStoreExpr(StoreExpr*) override;
+  Result OnUnaryExpr(UnaryExpr*) override;
+  Result OnUnreachableExpr(UnreachableExpr*) override;
+  Result BeginTryExpr(TryExpr*) override;
+  Result OnCatchExpr(TryExpr*, Catch*) override;
+  Result OnUnwindExpr(TryExpr*) override;
+  Result OnDelegateExpr(TryExpr*) override;
+  Result EndTryExpr(TryExpr*) override;
+  Result OnThrowExpr(ThrowExpr*) override;
+  Result OnRethrowExpr(RethrowExpr*) override;
+  Result OnAtomicWaitExpr(AtomicWaitExpr*) override;
+  Result OnAtomicFenceExpr(AtomicFenceExpr*) override;
+  Result OnAtomicNotifyExpr(AtomicNotifyExpr*) override;
+  Result OnAtomicLoadExpr(AtomicLoadExpr*) override;
+  Result OnAtomicStoreExpr(AtomicStoreExpr*) override;
+  Result OnAtomicRmwExpr(AtomicRmwExpr*) override;
+  Result OnAtomicRmwCmpxchgExpr(AtomicRmwCmpxchgExpr*) override;
+  Result OnTernaryExpr(TernaryExpr*) override;
+  Result OnSimdLaneOpExpr(SimdLaneOpExpr*) override;
+  Result OnSimdShuffleOpExpr(SimdShuffleOpExpr*) override;
+  Result OnLoadSplatExpr(LoadSplatExpr*) override;
+
+ private:
+  WatWriter* writer_;
+};
+
+Result WatWriter::ExprVisitorDelegate::OnBinaryExpr(BinaryExpr* expr) {
+  writer_->WritePutsNewline(expr->opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::BeginBlockExpr(BlockExpr* expr) {
+  writer_->WriteBeginBlock(LabelType::Block, expr->block,
+                           Opcode::Block_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::EndBlockExpr(BlockExpr* expr) {
+  writer_->WriteEndBlock();
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnBrExpr(BrExpr* expr) {
+  writer_->WritePutsSpace(Opcode::Br_Opcode.GetName());
+  writer_->WriteBrVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnBrIfExpr(BrIfExpr* expr) {
+  writer_->WritePutsSpace(Opcode::BrIf_Opcode.GetName());
+  writer_->WriteBrVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnBrTableExpr(BrTableExpr* expr) {
+  writer_->WritePutsSpace(Opcode::BrTable_Opcode.GetName());
+  for (const Var& var : expr->targets) {
+    writer_->WriteBrVar(var, NextChar::Space);
+  }
+  writer_->WriteBrVar(expr->default_target, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnCallExpr(CallExpr* expr) {
+  writer_->WritePutsSpace(Opcode::Call_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnCallIndirectExpr(
+    CallIndirectExpr* expr) {
+  writer_->WritePutsSpace(Opcode::CallIndirect_Opcode.GetName());
+  writer_->WriteVarUnlessZero(expr->table, NextChar::Space);
+  writer_->WriteOpenSpace("type");
+  writer_->WriteVar(expr->decl.type_var, NextChar::Newline);
+  writer_->WriteCloseNewline();
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnCompareExpr(CompareExpr* expr) {
+  writer_->WritePutsNewline(expr->opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnConstExpr(ConstExpr* expr) {
+  writer_->WriteConst(expr->const_);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnConvertExpr(ConvertExpr* expr) {
+  writer_->WritePutsNewline(expr->opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnDropExpr(DropExpr* expr) {
+  writer_->WritePutsNewline(Opcode::Drop_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnGlobalGetExpr(GlobalGetExpr* expr) {
+  writer_->WritePutsSpace(Opcode::GlobalGet_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnGlobalSetExpr(GlobalSetExpr* expr) {
+  writer_->WritePutsSpace(Opcode::GlobalSet_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::BeginIfExpr(IfExpr* expr) {
+  writer_->WriteBeginBlock(LabelType::If, expr->true_,
+                           Opcode::If_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::AfterIfTrueExpr(IfExpr* expr) {
+  if (!expr->false_.empty()) {
+    writer_->Dedent();
+    writer_->WritePutsSpace(Opcode::Else_Opcode.GetName());
+    writer_->Indent();
+    writer_->WriteNewline(FORCE_NEWLINE);
+  }
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::EndIfExpr(IfExpr* expr) {
+  writer_->WriteEndBlock();
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnLoadExpr(LoadExpr* expr) {
+  writer_->WriteLoadStoreExpr<LoadExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnLocalGetExpr(LocalGetExpr* expr) {
+  writer_->WritePutsSpace(Opcode::LocalGet_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnLocalSetExpr(LocalSetExpr* expr) {
+  writer_->WritePutsSpace(Opcode::LocalSet_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnLocalTeeExpr(LocalTeeExpr* expr) {
+  writer_->WritePutsSpace(Opcode::LocalTee_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::BeginLoopExpr(LoopExpr* expr) {
+  writer_->WriteBeginBlock(LabelType::Loop, expr->block,
+                           Opcode::Loop_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::EndLoopExpr(LoopExpr* expr) {
+  writer_->WriteEndBlock();
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnMemoryCopyExpr(MemoryCopyExpr* expr) {
+  writer_->WritePutsNewline(Opcode::MemoryCopy_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnDataDropExpr(DataDropExpr* expr) {
+  writer_->WritePutsSpace(Opcode::DataDrop_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnMemoryFillExpr(MemoryFillExpr* expr) {
+  writer_->WritePutsNewline(Opcode::MemoryFill_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnMemoryGrowExpr(MemoryGrowExpr* expr) {
+  writer_->WritePutsNewline(Opcode::MemoryGrow_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnMemorySizeExpr(MemorySizeExpr* expr) {
+  writer_->WritePutsNewline(Opcode::MemorySize_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnMemoryInitExpr(MemoryInitExpr* expr) {
+  writer_->WritePutsSpace(Opcode::MemoryInit_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTableCopyExpr(TableCopyExpr* expr) {
+  writer_->WritePutsSpace(Opcode::TableCopy_Opcode.GetName());
+  if (!(VarIsZero(expr->dst_table) && VarIsZero(expr->src_table))) {
+    writer_->WriteVar(expr->dst_table, NextChar::Space);
+    writer_->WriteVar(expr->src_table, NextChar::Space);
+  }
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnElemDropExpr(ElemDropExpr* expr) {
+  writer_->WritePutsSpace(Opcode::ElemDrop_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTableInitExpr(TableInitExpr* expr) {
+  writer_->WritePutsSpace(Opcode::TableInit_Opcode.GetName());
+  writer_->WriteVarUnlessZero(expr->table_index, NextChar::Space);
+  writer_->WriteVar(expr->segment_index, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTableGetExpr(TableGetExpr* expr) {
+  writer_->WritePutsSpace(Opcode::TableGet_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTableSetExpr(TableSetExpr* expr) {
+  writer_->WritePutsSpace(Opcode::TableSet_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTableGrowExpr(TableGrowExpr* expr) {
+  writer_->WritePutsSpace(Opcode::TableGrow_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTableSizeExpr(TableSizeExpr* expr) {
+  writer_->WritePutsSpace(Opcode::TableSize_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTableFillExpr(TableFillExpr* expr) {
+  writer_->WritePutsSpace(Opcode::TableFill_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnRefFuncExpr(RefFuncExpr* expr) {
+  writer_->WritePutsSpace(Opcode::RefFunc_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnRefNullExpr(RefNullExpr* expr) {
+  writer_->WritePutsSpace(Opcode::RefNull_Opcode.GetName());
+  writer_->WriteRefKind(expr->type, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnRefIsNullExpr(RefIsNullExpr* expr) {
+  writer_->WritePutsNewline(Opcode::RefIsNull_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnNopExpr(NopExpr* expr) {
+  writer_->WritePutsNewline(Opcode::Nop_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnReturnExpr(ReturnExpr* expr) {
+  writer_->WritePutsNewline(Opcode::Return_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnReturnCallExpr(ReturnCallExpr* expr) {
+  writer_->WritePutsSpace(Opcode::ReturnCall_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnReturnCallIndirectExpr(
+    ReturnCallIndirectExpr* expr) {
+  writer_->WritePutsSpace(Opcode::ReturnCallIndirect_Opcode.GetName());
+  writer_->WriteOpenSpace("type");
+  writer_->WriteVar(expr->decl.type_var, NextChar::Space);
+  writer_->WriteCloseNewline();
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnSelectExpr(SelectExpr* expr) {
+  writer_->WritePutsSpace(Opcode::Select_Opcode.GetName());
+  if (!expr->result_type.empty()) {
+    writer_->WriteTypes(expr->result_type, "result");
+  }
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnStoreExpr(StoreExpr* expr) {
+  writer_->WriteLoadStoreExpr<StoreExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnUnaryExpr(UnaryExpr* expr) {
+  writer_->WritePutsNewline(expr->opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnUnreachableExpr(
+    UnreachableExpr* expr) {
+  writer_->WritePutsNewline(Opcode::Unreachable_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::BeginTryExpr(TryExpr* expr) {
+  writer_->WriteBeginBlock(LabelType::Try, expr->block,
+                           Opcode::Try_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnCatchExpr(
+    TryExpr* expr, Catch* catch_) {
+  writer_->Dedent();
+  if (catch_->IsCatchAll()) {
+    writer_->WritePutsNewline(Opcode::CatchAll_Opcode.GetName());
+  } else {
+    writer_->WritePutsSpace(Opcode::Catch_Opcode.GetName());
+    writer_->WriteVar(catch_->var, NextChar::Newline);
+  }
+  writer_->Indent();
+  writer_->SetTopLabelType(LabelType::Catch);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnUnwindExpr(TryExpr* expr) {
+  writer_->Dedent();
+  writer_->WritePutsNewline(Opcode::Unwind_Opcode.GetName());
+  writer_->Indent();
+  writer_->SetTopLabelType(LabelType::Unwind);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnDelegateExpr(TryExpr* expr) {
+  writer_->Dedent();
+  writer_->WritePutsSpace(Opcode::Delegate_Opcode.GetName());
+  writer_->WriteVar(expr->delegate_target, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::EndTryExpr(TryExpr* expr) {
+  writer_->WriteEndBlock();
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnThrowExpr(ThrowExpr* expr) {
+  writer_->WritePutsSpace(Opcode::Throw_Opcode.GetName());
+  writer_->WriteVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnRethrowExpr(RethrowExpr* expr) {
+  writer_->WritePutsSpace(Opcode::Rethrow_Opcode.GetName());
+  writer_->WriteBrVar(expr->var, NextChar::Newline);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnAtomicWaitExpr(AtomicWaitExpr* expr) {
+  writer_->WriteLoadStoreExpr<AtomicWaitExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnAtomicFenceExpr(
+    AtomicFenceExpr* expr) {
+  assert(expr->consistency_model == 0);
+  writer_->WritePutsNewline(Opcode::AtomicFence_Opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnAtomicNotifyExpr(
+    AtomicNotifyExpr* expr) {
+  writer_->WriteLoadStoreExpr<AtomicNotifyExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnAtomicLoadExpr(AtomicLoadExpr* expr) {
+  writer_->WriteLoadStoreExpr<AtomicLoadExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnAtomicStoreExpr(
+    AtomicStoreExpr* expr) {
+  writer_->WriteLoadStoreExpr<AtomicStoreExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnAtomicRmwExpr(AtomicRmwExpr* expr) {
+  writer_->WriteLoadStoreExpr<AtomicRmwExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnAtomicRmwCmpxchgExpr(
+    AtomicRmwCmpxchgExpr* expr) {
+  writer_->WriteLoadStoreExpr<AtomicRmwCmpxchgExpr>(expr);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnTernaryExpr(TernaryExpr* expr) {
+  writer_->WritePutsNewline(expr->opcode.GetName());
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnSimdLaneOpExpr(SimdLaneOpExpr* expr) {
+  writer_->WritePutsSpace(expr->opcode.GetName());
+  writer_->Writef("%" PRIu64, (expr->val));
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnSimdShuffleOpExpr(
+    SimdShuffleOpExpr* expr) {
+  writer_->WritePutsSpace(expr->opcode.GetName());
+  std::array<uint8_t, 16> values = Bitcast<std::array<uint8_t, 16>>(expr->val);
+  for (int32_t lane = 0; lane < 16; ++lane) {
+#if WABT_BIG_ENDIAN
+    writer_->Writef("%u", values[15 - lane]);
+#else
+    writer_->Writef("%u", values[lane]);
+#endif
+  }
+  writer_->WriteNewline(NO_FORCE_NEWLINE);
+  return Result::Ok;
+}
+
+Result WatWriter::ExprVisitorDelegate::OnLoadSplatExpr(LoadSplatExpr* expr) {
+  writer_->WriteLoadStoreExpr<LoadSplatExpr>(expr);
+  return Result::Ok;
+}
+
+void WatWriter::WriteExpr(const Expr* expr) {
+  WABT_TRACE(WriteExprList);
+  ExprVisitorDelegate delegate(this);
+  ExprVisitor visitor(&delegate);
+  visitor.VisitExpr(const_cast<Expr*>(expr));
+}
+
+void WatWriter::WriteExprList(const ExprList& exprs) {
+  WABT_TRACE(WriteExprList);
+  ExprVisitorDelegate delegate(this);
+  ExprVisitor visitor(&delegate);
+  visitor.VisitExprList(const_cast<ExprList&>(exprs));
+}
+
+void WatWriter::WriteFoldedExpr(const Expr* expr) {
+  WABT_TRACE_ARGS(WriteFoldedExpr, "%s", GetExprTypeName(*expr));
+  auto arity = GetExprArity(*expr);
+  PushExpr(expr, arity.nargs, arity.nreturns);
+}
+
+void WatWriter::WriteFoldedExprList(const ExprList& exprs) {
+  WABT_TRACE(WriteFoldedExprList);
+  for (const Expr& expr : exprs) {
+    WriteFoldedExpr(&expr);
+  }
+}
+
+void WatWriter::PushExpr(const Expr* expr,
+                         Index operand_count,
+                         Index result_count) {
+  WABT_TRACE_ARGS(PushExpr, "%s, %" PRIindex ", %" PRIindex "",
+                  GetExprTypeName(*expr), operand_count, result_count);
+
+  // Try to pop operand off the expr stack to use as this expr's children. One
+  // expr can have multiple return values (with the multi-value extension), so
+  // we have to iterate over each in reverse.
+
+  auto first_operand = expr_tree_stack_.end();
+
+  Index current_count = 0;
+  if (operand_count > 0) {
+    for (auto iter = expr_tree_stack_.rbegin(); iter != expr_tree_stack_.rend();
+         ++iter) {
+      assert(iter->result_count > 0);
+      current_count += iter->result_count;
+
+      if (current_count == operand_count) {
+        first_operand = iter.base() - 1;
+        break;
+      } else if (current_count > operand_count) {
+        // We went over the number of operands this instruction wants; this can
+        // only happen when there are expressions on the stack with a
+        // result_count > 1. When this happens we can't fold, since any result
+        // we produce will not make sense.
+        break;
+      }
+    }
+  }
+
+  ExprTree tree(expr, result_count);
+
+  if (current_count == operand_count && operand_count > 0) {
+    auto last_operand = expr_tree_stack_.end();
+    std::move(first_operand, last_operand, std::back_inserter(tree.children));
+    expr_tree_stack_.erase(first_operand, last_operand);
+  }
+
+  expr_tree_stack_.emplace_back(std::move(tree));
+  if (current_count > operand_count || result_count == 0) {
+    FlushExprTreeStack();
+  }
+}
+
+void WatWriter::FlushExprTree(const ExprTree& expr_tree) {
+  WABT_TRACE_ARGS(FlushExprTree, "%s", GetExprTypeName(*expr_tree.expr));
+  switch (expr_tree.expr->type()) {
+    case ExprType::Block:
+      WritePuts("(", NextChar::None);
+      WriteBeginBlock(LabelType::Block, cast<BlockExpr>(expr_tree.expr)->block,
+                      Opcode::Block_Opcode.GetName());
+      WriteFoldedExprList(cast<BlockExpr>(expr_tree.expr)->block.exprs);
+      FlushExprTreeStack();
+      WriteCloseNewline();
+      EndBlock();
+      break;
+
+    case ExprType::Loop:
+      WritePuts("(", NextChar::None);
+      WriteBeginBlock(LabelType::Loop, cast<LoopExpr>(expr_tree.expr)->block,
+                      Opcode::Loop_Opcode.GetName());
+      WriteFoldedExprList(cast<LoopExpr>(expr_tree.expr)->block.exprs);
+      FlushExprTreeStack();
+      WriteCloseNewline();
+      EndBlock();
+      break;
+
+    case ExprType::If: {
+      auto if_expr = cast<IfExpr>(expr_tree.expr);
+      WritePuts("(", NextChar::None);
+      WriteBeginBlock(LabelType::If, if_expr->true_,
+                      Opcode::If_Opcode.GetName());
+      FlushExprTreeVector(expr_tree.children);
+      WriteOpenNewline("then");
+      WriteFoldedExprList(if_expr->true_.exprs);
+      FlushExprTreeStack();
+      WriteCloseNewline();
+      if (!if_expr->false_.empty()) {
+        WriteOpenNewline("else");
+        WriteFoldedExprList(if_expr->false_);
+        FlushExprTreeStack();
+        WriteCloseNewline();
+      }
+      WriteCloseNewline();
+      EndBlock();
+      break;
+    }
+
+    case ExprType::Try: {
+      auto try_expr = cast<TryExpr>(expr_tree.expr);
+      WritePuts("(", NextChar::None);
+      WriteBeginBlock(LabelType::Try, try_expr->block,
+                      Opcode::Try_Opcode.GetName());
+      WriteOpenNewline("do");
+      FlushExprTreeVector(expr_tree.children);
+      WriteFoldedExprList(try_expr->block.exprs);
+      FlushExprTreeStack();
+      WriteCloseNewline();
+      switch (try_expr->kind) {
+        case TryKind::Catch:
+          for (const Catch& catch_ : try_expr->catches) {
+            WritePuts("(", NextChar::None);
+            if (catch_.IsCatchAll()) {
+              WritePutsNewline("catch_all");
+            } else {
+              WritePutsSpace(Opcode::Catch_Opcode.GetName());
+              WriteVar(catch_.var, NextChar::Newline);
+            }
+            Indent();
+            WriteFoldedExprList(catch_.exprs);
+            FlushExprTreeStack();
+            WriteCloseNewline();
+          }
+          break;
+        case TryKind::Unwind:
+          WritePuts("(", NextChar::None);
+          WritePutsNewline(Opcode::Unwind_Opcode.GetName());
+          Indent();
+          WriteFoldedExprList(try_expr->unwind);
+          FlushExprTreeStack();
+          WriteCloseNewline();
+          break;
+        case TryKind::Delegate:
+          WritePuts("(", NextChar::None);
+          WritePutsSpace(Opcode::Delegate_Opcode.GetName());
+          WriteVar(try_expr->delegate_target, NextChar::None);
+          WritePuts(")", NextChar::Newline);
+          break;
+        case TryKind::Invalid:
+          // Should not occur.
+          break;
+      }
+      WriteCloseNewline();
+      EndBlock();
+      break;
+    }
+
+    default: {
+      WritePuts("(", NextChar::None);
+      WriteExpr(expr_tree.expr);
+      Indent();
+      FlushExprTreeVector(expr_tree.children);
+      WriteCloseNewline();
+      break;
+    }
+  }
+}
+
+void WatWriter::FlushExprTreeVector(const std::vector<ExprTree>& expr_trees) {
+  WABT_TRACE_ARGS(FlushExprTreeVector, "%zu", expr_trees.size());
+  for (auto expr_tree : expr_trees) {
+    FlushExprTree(expr_tree);
+  }
+}
+
+void WatWriter::FlushExprTreeStack() {
+  std::vector<ExprTree> stack_copy(std::move(expr_tree_stack_));
+  expr_tree_stack_.clear();
+  FlushExprTreeVector(stack_copy);
+}
+
+void WatWriter::WriteInitExpr(const ExprList& expr) {
+  if (!expr.empty()) {
+    WritePuts("(", NextChar::None);
+    WriteExprList(expr);
+    /* clear the next char, so we don't write a newline after the expr */
+    next_char_ = NextChar::None;
+    WritePuts(")", NextChar::Space);
+  }
+}
+
+template <typename T>
+void WatWriter::WriteTypeBindings(const char* prefix,
+                                  const T& types,
+                                  const std::vector<std::string>& index_to_name,
+                                  Index binding_index_offset) {
+  /* named params/locals must be specified by themselves, but nameless
+   * params/locals can be compressed, e.g.:
+   *   (param $foo i32)
+   *   (param i32 i64 f32)
+   */
+  bool first = true;
+  bool prev_has_name = false;
+  size_t index = 0;
+  for (Type type : types) {
+    const std::string& name = index_to_name[binding_index_offset + index];
+    bool has_name = !name.empty();
+    if ((has_name || prev_has_name) && !first) {
+      WriteCloseSpace();
+    }
+    if (has_name || prev_has_name || first) {
+      WriteOpenSpace(prefix);
+    }
+    if (has_name) {
+      WriteString(name, NextChar::Space);
+    }
+    WriteType(type, NextChar::Space);
+    prev_has_name = has_name;
+    first = false;
+    ++index;
+  }
+  if (types.size() != 0) {
+    WriteCloseSpace();
+  }
+}
+
+void WatWriter::WriteBeginFunc(const Func& func) {
+  WriteOpenSpace("func");
+  WriteNameOrIndex(func.name, func_index_, NextChar::Space);
+  WriteInlineExports(ExternalKind::Func, func_index_);
+  WriteInlineImport(ExternalKind::Func, func_index_);
+  if (func.decl.has_func_type) {
+    WriteOpenSpace("type");
+    WriteVar(func.decl.type_var, NextChar::None);
+    WriteCloseSpace();
+  }
+
+  if (module.IsImport(ExternalKind::Func, Var(func_index_))) {
+    // Imported functions can be written a few ways:
+    //
+    //   1. (import "module" "field" (func (type 0)))
+    //   2. (import "module" "field" (func (param i32) (result i32)))
+    //   3. (func (import "module" "field") (type 0))
+    //   4. (func (import "module" "field") (param i32) (result i32))
+    //   5. (func (import "module" "field") (type 0) (param i32) (result i32))
+    //
+    // Note that the text format does not allow including the param/result
+    // explicitly when using the "(import..." syntax (#1 and #2).
+    if (options_.inline_import || !func.decl.has_func_type) {
+      WriteFuncSigSpace(func.decl.sig);
+    }
+  }
+  func_index_++;
+}
+
+void WatWriter::WriteFunc(const Func& func) {
+  WriteBeginFunc(func);
+  std::vector<std::string> index_to_name;
+  MakeTypeBindingReverseMapping(func.GetNumParamsAndLocals(), func.bindings,
+                                &index_to_name);
+  WriteTypeBindings("param", func.decl.sig.param_types, index_to_name);
+  WriteTypes(func.decl.sig.result_types, "result");
+  WriteNewline(NO_FORCE_NEWLINE);
+  if (func.local_types.size()) {
+    WriteTypeBindings("local", func.local_types, index_to_name,
+                      func.GetNumParams());
+  }
+  WriteNewline(NO_FORCE_NEWLINE);
+  BeginFunc(func);
+  if (options_.fold_exprs) {
+    WriteFoldedExprList(func.exprs);
+    FlushExprTreeStack();
+  } else {
+    WriteExprList(func.exprs);
+  }
+  EndFunc();
+  WriteCloseNewline();
+}
+
+void WatWriter::WriteBeginGlobal(const Global& global) {
+  WriteOpenSpace("global");
+  WriteNameOrIndex(global.name, global_index_, NextChar::Space);
+  WriteInlineExports(ExternalKind::Global, global_index_);
+  WriteInlineImport(ExternalKind::Global, global_index_);
+  if (global.mutable_) {
+    WriteOpenSpace("mut");
+    WriteType(global.type, NextChar::Space);
+    WriteCloseSpace();
+  } else {
+    WriteType(global.type, NextChar::Space);
+  }
+  global_index_++;
+}
+
+void WatWriter::WriteGlobal(const Global& global) {
+  WriteBeginGlobal(global);
+  WriteInitExpr(global.init_expr);
+  WriteCloseNewline();
+}
+
+void WatWriter::WriteEvent(const Event& event) {
+  WriteOpenSpace("event");
+  WriteNameOrIndex(event.name, event_index_, NextChar::Space);
+  WriteInlineExports(ExternalKind::Event, event_index_);
+  WriteInlineImport(ExternalKind::Event, event_index_);
+  if (event.decl.has_func_type) {
+    WriteOpenSpace("type");
+    WriteVar(event.decl.type_var, NextChar::None);
+    WriteCloseSpace();
+  }
+  WriteTypes(event.decl.sig.param_types, "param");
+  ++event_index_;
+  WriteCloseNewline();
+}
+
+void WatWriter::WriteLimits(const Limits& limits) {
+  if (limits.is_64) {
+    Writef("i64");
+  }
+  Writef("%" PRIu64, limits.initial);
+  if (limits.has_max) {
+    Writef("%" PRIu64, limits.max);
+  }
+  if (limits.is_shared) {
+    Writef("shared");
+  }
+}
+
+void WatWriter::WriteTable(const Table& table) {
+  WriteOpenSpace("table");
+  WriteNameOrIndex(table.name, table_index_, NextChar::Space);
+  WriteInlineExports(ExternalKind::Table, table_index_);
+  WriteInlineImport(ExternalKind::Table, table_index_);
+  WriteLimits(table.elem_limits);
+  WriteType(table.elem_type, NextChar::None);
+  WriteCloseNewline();
+  table_index_++;
+}
+
+void WatWriter::WriteElemSegment(const ElemSegment& segment) {
+  WriteOpenSpace("elem");
+  WriteNameOrIndex(segment.name, elem_segment_index_, NextChar::Space);
+
+  uint8_t flags = segment.GetFlags(&module);
+
+  if ((flags & (SegPassive | SegExplicitIndex)) == SegExplicitIndex) {
+    WriteOpenSpace("table");
+    WriteVar(segment.table_var, NextChar::Space);
+    WriteCloseSpace();
+  }
+
+  if (!(flags & SegPassive)) {
+    WriteInitExpr(segment.offset);
+  }
+
+  if ((flags & SegDeclared) == SegDeclared) {
+    WritePuts("declare", NextChar::Space);
+  }
+
+  if (flags & SegUseElemExprs) {
+    WriteType(segment.elem_type, NextChar::Space);
+  } else {
+    assert(segment.elem_type == Type::FuncRef);
+    WritePuts("func", NextChar::Space);
+  }
+
+  for (const ElemExpr& expr : segment.elem_exprs) {
+    if (flags & SegUseElemExprs) {
+      if (expr.kind == ElemExprKind::RefNull) {
+        WriteOpenSpace("ref.null");
+        WriteRefKind(expr.type, NextChar::Space);
+        WriteCloseSpace();
+      } else {
+        WriteOpenSpace("ref.func");
+        WriteVar(expr.var, NextChar::Space);
+        WriteCloseSpace();
+      }
+    } else {
+      assert(expr.kind == ElemExprKind::RefFunc);
+      WriteVar(expr.var, NextChar::Space);
+    }
+  }
+  WriteCloseNewline();
+  elem_segment_index_++;
+}
+
+void WatWriter::WriteMemory(const Memory& memory) {
+  WriteOpenSpace("memory");
+  WriteNameOrIndex(memory.name, memory_index_, NextChar::Space);
+  WriteInlineExports(ExternalKind::Memory, memory_index_);
+  WriteInlineImport(ExternalKind::Memory, memory_index_);
+  WriteLimits(memory.page_limits);
+  WriteCloseNewline();
+  memory_index_++;
+}
+
+void WatWriter::WriteDataSegment(const DataSegment& segment) {
+  WriteOpenSpace("data");
+  WriteNameOrIndex(segment.name, data_segment_index_, NextChar::Space);
+  if (segment.kind != SegmentKind::Passive) {
+    WriteInitExpr(segment.offset);
+  }
+  WriteQuotedData(segment.data.data(), segment.data.size());
+  WriteCloseNewline();
+  data_segment_index_++;
+}
+
+void WatWriter::WriteImport(const Import& import) {
+  if (!options_.inline_import) {
+    WriteOpenSpace("import");
+    WriteQuotedString(import.module_name, NextChar::Space);
+    WriteQuotedString(import.field_name, NextChar::Space);
+  }
+
+  switch (import.kind()) {
+    case ExternalKind::Func:
+      WriteBeginFunc(cast<FuncImport>(&import)->func);
+      WriteCloseSpace();
+      break;
+
+    case ExternalKind::Table:
+      WriteTable(cast<TableImport>(&import)->table);
+      break;
+
+    case ExternalKind::Memory:
+      WriteMemory(cast<MemoryImport>(&import)->memory);
+      break;
+
+    case ExternalKind::Global:
+      WriteBeginGlobal(cast<GlobalImport>(&import)->global);
+      WriteCloseSpace();
+      break;
+
+    case ExternalKind::Event:
+      WriteEvent(cast<EventImport>(&import)->event);
+      break;
+  }
+
+  if (options_.inline_import) {
+    WriteNewline(NO_FORCE_NEWLINE);
+  } else {
+    WriteCloseNewline();
+  }
+}
+
+void WatWriter::WriteExport(const Export& export_) {
+  if (options_.inline_export && IsInlineExport(export_)) {
+    return;
+  }
+  WriteOpenSpace("export");
+  WriteQuotedString(export_.name, NextChar::Space);
+  WriteOpenSpace(GetKindName(export_.kind));
+  WriteVar(export_.var, NextChar::Space);
+  WriteCloseSpace();
+  WriteCloseNewline();
+}
+
+void WatWriter::WriteTypeEntry(const TypeEntry& type) {
+  WriteOpenSpace("type");
+  WriteNameOrIndex(type.name, type_index_++, NextChar::Space);
+  switch (type.kind()) {
+    case TypeEntryKind::Func:
+      WriteOpenSpace("func");
+      WriteFuncSigSpace(cast<FuncType>(&type)->sig);
+      WriteCloseSpace();
+      break;
+
+    case TypeEntryKind::Struct: {
+      auto* struct_type = cast<StructType>(&type);
+      WriteOpenSpace("struct");
+      Index field_index = 0;
+      for (auto&& field : struct_type->fields) {
+        // TODO: Write shorthand if there is no name.
+        WriteOpenSpace("field");
+        WriteNameOrIndex(field.name, field_index++, NextChar::Space);
+        WriteField(field);
+        WriteCloseSpace();
+      }
+      WriteCloseSpace();
+      break;
+    }
+
+    case TypeEntryKind::Array: {
+      auto* array_type = cast<ArrayType>(&type);
+      WriteOpenSpace("array");
+      WriteField(array_type->field);
+      WriteCloseSpace();
+      break;
+    }
+  }
+  WriteCloseNewline();
+}
+
+void WatWriter::WriteField(const Field& field) {
+  if (field.mutable_) {
+    WriteOpenSpace("mut");
+  }
+  WriteType(field.type, NextChar::Space);
+  if (field.mutable_) {
+    WriteCloseSpace();
+  }
+}
+
+void WatWriter::WriteStartFunction(const Var& start) {
+  WriteOpenSpace("start");
+  WriteVar(start, NextChar::None);
+  WriteCloseNewline();
+}
+
+Result WatWriter::WriteModule() {
+  BuildInlineExportMap();
+  BuildInlineImportMap();
+  WriteOpenSpace("module");
+  if (module.name.empty()) {
+    WriteNewline(NO_FORCE_NEWLINE);
+  } else {
+    WriteName(module.name, NextChar::Newline);
+  }
+  for (const ModuleField& field : module.fields) {
+    switch (field.type()) {
+      case ModuleFieldType::Func:
+        WriteFunc(cast<FuncModuleField>(&field)->func);
+        break;
+      case ModuleFieldType::Global:
+        WriteGlobal(cast<GlobalModuleField>(&field)->global);
+        break;
+      case ModuleFieldType::Import:
+        WriteImport(*cast<ImportModuleField>(&field)->import);
+        break;
+      case ModuleFieldType::Event:
+        WriteEvent(cast<EventModuleField>(&field)->event);
+        break;
+      case ModuleFieldType::Export:
+        WriteExport(cast<ExportModuleField>(&field)->export_);
+        break;
+      case ModuleFieldType::Table:
+        WriteTable(cast<TableModuleField>(&field)->table);
+        break;
+      case ModuleFieldType::ElemSegment:
+        WriteElemSegment(cast<ElemSegmentModuleField>(&field)->elem_segment);
+        break;
+      case ModuleFieldType::Memory:
+        WriteMemory(cast<MemoryModuleField>(&field)->memory);
+        break;
+      case ModuleFieldType::DataSegment:
+        WriteDataSegment(cast<DataSegmentModuleField>(&field)->data_segment);
+        break;
+      case ModuleFieldType::Type:
+        WriteTypeEntry(*cast<TypeModuleField>(&field)->type);
+        break;
+      case ModuleFieldType::Start:
+        WriteStartFunction(cast<StartModuleField>(&field)->start);
+        break;
+    }
+  }
+  WriteCloseNewline();
+  /* force the newline to be written */
+  WriteNextChar();
+  return result_;
+}
+
+void WatWriter::BuildInlineExportMap() {
+  if (!options_.inline_export) {
+    return;
+  }
+
+  for (Export* export_ : module.exports) {
+    Index index = kInvalidIndex;
+
+    // Exported imports can't be written with inline exports, unless the
+    // imports are also inline. For example, the following is invalid:
+    //
+    //   (import "module" "field" (func (export "e")))
+    //
+    // But this is valid:
+    //
+    //   (func (export "e") (import "module" "field"))
+    //
+    if (!options_.inline_import && module.IsImport(*export_)) {
+      continue;
+    }
+
+    switch (export_->kind) {
+      case ExternalKind::Func:
+        index = module.GetFuncIndex(export_->var);
+        break;
+
+      case ExternalKind::Table:
+        index = module.GetTableIndex(export_->var);
+        break;
+
+      case ExternalKind::Memory:
+        index = module.GetMemoryIndex(export_->var);
+        break;
+
+      case ExternalKind::Global:
+        index = module.GetGlobalIndex(export_->var);
+        break;
+
+      case ExternalKind::Event:
+        index = module.GetEventIndex(export_->var);
+        break;
+    }
+
+    if (index != kInvalidIndex) {
+      auto key = std::make_pair(export_->kind, index);
+      inline_export_map_.insert(std::make_pair(key, export_));
+    }
+  }
+}
+
+void WatWriter::WriteInlineExports(ExternalKind kind, Index index) {
+  if (!options_.inline_export) {
+    return;
+  }
+
+  auto iter_pair = inline_export_map_.equal_range(std::make_pair(kind, index));
+  for (auto iter = iter_pair.first; iter != iter_pair.second; ++iter) {
+    const Export* export_ = iter->second;
+    WriteOpenSpace("export");
+    WriteQuotedString(export_->name, NextChar::None);
+    WriteCloseSpace();
+  }
+}
+
+bool WatWriter::IsInlineExport(const Export& export_) {
+  Index index;
+  switch (export_.kind) {
+    case ExternalKind::Func:
+      index = module.GetFuncIndex(export_.var);
+      break;
+
+    case ExternalKind::Table:
+      index = module.GetTableIndex(export_.var);
+      break;
+
+    case ExternalKind::Memory:
+      index = module.GetMemoryIndex(export_.var);
+      break;
+
+    case ExternalKind::Global:
+      index = module.GetGlobalIndex(export_.var);
+      break;
+
+    case ExternalKind::Event:
+      index = module.GetEventIndex(export_.var);
+      break;
+  }
+
+  return inline_export_map_.find(std::make_pair(export_.kind, index)) !=
+         inline_export_map_.end();
+}
+
+void WatWriter::BuildInlineImportMap() {
+  if (!options_.inline_import) {
+    return;
+  }
+
+  for (const Import* import : module.imports) {
+    inline_import_map_[static_cast<size_t>(import->kind())].push_back(import);
+  }
+}
+
+void WatWriter::WriteInlineImport(ExternalKind kind, Index index) {
+  if (!options_.inline_import) {
+    return;
+  }
+
+  size_t kind_index = static_cast<size_t>(kind);
+
+  if (index >= inline_import_map_[kind_index].size()) {
+    return;
+  }
+
+  const Import* import = inline_import_map_[kind_index][index];
+  WriteOpenSpace("import");
+  WriteQuotedString(import->module_name, NextChar::Space);
+  WriteQuotedString(import->field_name, NextChar::Space);
+  WriteCloseSpace();
+}
+
+}  // end anonymous namespace
+
+Result WriteWat(Stream* stream,
+                const Module* module,
+                const WriteWatOptions& options) {
+  WatWriter wat_writer(stream, options, *module);
+  return wat_writer.WriteModule();
+}
+
+}  // namespace wabt
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.h b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/src/wat-writer.h
new file mode 100644 (file)
index 0000000..ec8a3ee
--- /dev/null
@@ -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_WAT_WRITER_H_
+#define WABT_WAT_WRITER_H_
+
+#include "src/common.h"
+
+namespace wabt {
+
+struct Module;
+class Stream;
+
+struct WriteWatOptions {
+  bool fold_exprs = false;  // Write folded expressions.
+  bool inline_export = false;
+  bool inline_import = false;
+};
+
+Result WriteWat(Stream*, const Module*, const WriteWatOptions&);
+
+}  // namespace wabt
+
+#endif /* WABT_WAT_WRITER_H_ */
diff --git a/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/ubsan.blacklist b/lwnode/code/escargotshim/deps/escargot/third_party/wasm/wabt/ubsan.blacklist
new file mode 100644 (file)
index 0000000..5ac9d3c
--- /dev/null
@@ -0,0 +1,12 @@
+# Work around libstdc++ bug: https://llvm.org/bugs/show_bug.cgi?id=18156
+# Also see: http://lists.llvm.org/pipermail/cfe-dev/2015-January/040945.html
+src:*/ios_base.h
+
+# Work around another libstdc++ bug:
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60734
+src:*/stl_tree.h
+
+# Work around for libstdc++ 4.8 bug:
+# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59829
+src:*/stl_vector.h
+src:*/stl_iterator.h
diff --git a/lwnode/test/node/cctest.gypi b/lwnode/test/node/cctest.gypi
new file mode 100644 (file)
index 0000000..e1831d8
--- /dev/null
@@ -0,0 +1,78 @@
+{
+  'includes': [
+    '../../../node.gypi',
+  ],
+
+  'dependencies': [
+    '<(node_lib_target_name)',
+    'deps/histogram/histogram.gyp:histogram',
+    'deps/uvwasi/uvwasi.gyp:uvwasi',
+    'node_dtrace_header',
+    'node_dtrace_ustack',
+    'node_dtrace_provider',
+    # lwnode
+    '<(lwnode_jsengine_path)/escargotshim.gyp:escargotshim',
+    '<(lwnode_jsengine_path)/escargot.gyp:escargot',
+  ],
+
+  'include_dirs': [
+    '../../../src',
+    '../../../tools/msvs/genfiles',
+    '../../../<(lwnode_jsengine_path)/include',
+    '../../../deps/cares/include',
+    '../../../deps/uv/include',
+    '../../../deps/uvwasi/include',
+    'test/cctest',
+    # lwnode
+    '../../../<(lwnode_jsengine_path)/src',
+  ],
+
+  'defines': [
+    'NODE_ARCH="<(target_arch)"',
+    'NODE_PLATFORM="<(OS)"',
+    'NODE_WANT_INTERNALS=1',
+  ],
+
+  'sources': [
+    '../../../src/node_snapshot_stub.cc',
+    '../../../src/node_code_cache_stub.cc',
+    'test/cctest/gtest/gtest-all.cc',
+    'test/cctest/gtest/gtest_main.cc',
+    'test/cctest/node_test_fixture.cc',
+    'test/cctest/node_test_fixture.h',
+    # 'test/cctest/test_aliased_buffer.cc',
+    'test/cctest/test_base64.cc',
+    'test/cctest/test_base_object_ptr.cc',
+    # 'test/cctest/test_node_postmortem_metadata.cc',
+    'test/cctest/test_environment.cc',
+    'test/cctest/test_linked_binding.cc',
+    # 'test/cctest/test_per_process.cc',
+    # 'test/cctest/test_platform.cc',
+    'test/cctest/test_json_utils.cc',
+    'test/cctest/test_sockaddr.cc',
+    # 'test/cctest/test_traced_value.cc',
+    'test/cctest/test_util.cc',
+    'test/cctest/test_url.cc',
+  ],
+
+  'conditions': [
+    [ 'node_use_openssl=="true"', {
+      'defines': [
+        'HAVE_OPENSSL=1',
+      ],
+    }],
+    ['v8_enable_inspector==1', {
+      'sources': [
+        'test/cctest/test_inspector_socket.cc',
+        'test/cctest/test_inspector_socket_server.cc'
+      ],
+      'defines': [
+        'HAVE_INSPECTOR=1',
+      ],
+    }, {
+        'defines': [
+          'HAVE_INSPECTOR=0',
+        ]
+    }],
+  ],
+} # cctest